I have the following function (which is hosted in a WCF service, if that matters):
public List<IceVsRepositoryFile> GetRepositoryFilesByRepositoryId(int repId)
{
var entity = new IceVSEntities();
var files = from p in entity.Files where p.RepositoryId == repId select p.FileId;
List<long> iList = files.ToList();
var repFiles = from p in entity.RepositoryFiles where iList.Contains(p.FileId) select p;
if (!repFiles.Any())
return null;
var retFiles = repFiles.ToList().Select(z => new IceVsRepositoryFile
{
FileId = (int)z.FileId,
RollbackFileId = (int)z.RollbackFileId,
UserId = (int)z.UserId,
FileContents = z.FileContents,
ChangeDescription = z.ChangeDescription
}).ToList();
return retFiles;
}
When I run this function I am getting the following an error that says "LINQ to Entities does not recognize the method 'Boolean Contains(Int64)' method and this method cannot be translated into a store expression.
I understand why I am getting the error message. My question is, how can I rewrite my query to make this work as expected? My backend database, if it matters, if SqlLite 3. I am using .NET 3.5.
The contains you used is for List, it's not in IEnumerable so it can't be converted to corresponding sql query. Instead you can use Any, ... like:
iList.Any(x=>x == p.FileId) (or use related property)
Also instead of doing:
List<long> iList = files.ToList();
use files.Any... in your query to prevent from too many fetching from DB. Actually use IEnumerable functions instead of List functions.
I believe a join can do this:
public List<IceVsRepositoryFile> GetRepositoryFilesByRepositoryId(int repId)
{
var entity = new IceVSEntities();
var repFiles = from file in entity.Files where file.RepositoryId == repId join repFile in entity.RepositoryFiles on repFile.FileId equals file.FileId select repFile;
var retFiles = // as before
return retFiles;
}
Do you have a relationship between Files and RepositoryFiles? If so, it would be easier to do something like this:
var repFiles = from p in entity.RepositoryFiles where p.File.RepositoryId == repId select p;
This will avoid the problems with being unable to translate the query to SQL.
Related
Hi I i'm doing this linq expression in an web api but then it gives this error
LINQ to Entities does not recognize the method 'WebApplicationAPI.Models.Registo convertToRegisto(WebApplicationAPI.Models.TBS0017)' method, and this method cannot be translated into a store expression.
Here's the code:
var tBS0017 = from row in db.TBS0017
where row.Cartao == cartao && row.Data == data
var teste = tBS0017.Select(x => convertToRegisto(x));
public Registo convertToRegisto(TBS0017 x)
{
string term = db.ba_terminal.Where(y => "00"+y.terminal_id.ToString() == x.CodTerminal).Select(y => y.terminal_name).ToString();
string emp = db.TG0006.Where(y => "00"+y.IdCompanhia.ToString() == x.IdCompanhia.ToString()).Select(y => y.DsCompanhia).ToString();
Registo r = new Registo() { Cartao = x.Cartao, Data = x.Data, Hora = x.Hora, Local = term, Empresa = emp };
return r;
}
Bring tBS0017 back into memory with ToList()
var results = tBS0017.ToList()
.Select(x => convertToRegisto(x));
However, this has some serious flaws.
For every element in tBS0017, you are doing 2 more db query's. You should really be doing this in the one query and projecting to Registo
The issue is that using Linq to Entities tries to convert your C# code into equivalent SQL which can run your query. There is no function "convertToRegisto" in SQL so this gives you an exception.
You can solve the issue by using ToList() to bring the result of the query into memory first. Then you're able to use your methods in the Select.
var teste = tBS0017
.ToList()
.Select(x => convertToRegisto(x));
You can not convert int value from linq to sql. You must use the sql function that convert int to string values. On the other hand, in memory handling is quite heavy operation
e.g
string term = db.ba_terminal.Where(y => "00"+
SqlFunctions.StringConvert((double)y.terminal_id) ==
x.CodTerminal).Select(y => y.terminal_name).ToString();
I am using LINQ to Entities for selecting data from SQL.
Here is my statement
var employee = from p in _context.employee
select p;
employee = employee.Where(p =>
Helper.RemoveSpecialCharacters(p.IdentificationNumber).
Equals(Helper.RemoveSpecialCharacters(search.IdentificationNumber)));
var Results = employee.ToList();
I am using RemoveSpecialCharacters method which I wrote to compare both sides of comparison without special characters.
Here I Get error, "RemoveSpecialCharacters" Method is not supported by Linq->Entity and is not a valid Store Expression.
I understand that it can't be translated as SQL. But how do I make such comparison using LINQ?
RemoveSpecialCharacters Method
public static string RemoveSpecialCharacters(string str)
{
char[] arr = str.Where(c => (char.IsLetterOrDigit(c))).ToArray();
str = new string(arr);
return str;
}
If methodname be translated to LINQ store then maybe how can I put this in linq so that sql understands it.
If you can express your RemoveSpecialCharacters in SQL, you could have a SQL view presenting your employees with a computed IdentificationNumberWithoutSpecialCharacters column, and then filter on it.
You could also reuse your C# implementation of the method by creating a .NET assembly for SQL Server.
The .ToList() finishes off your initial DB query, and gives you an
in-memory representation to work with and modify to your object.
var employee = from p in _context.employee
select p.ToList();
string searchIdent = Helper.RemoveSpecialCharacters(search.IdentificationNumber);
employee = employee.Where(p =>
Helper.RemoveSpecialCharacters(p.IdentificationNumber).
Equals(searchIdent));
var Results = employee;
I'm migrating some stuff from one mysql server to a sql server but i can't figure out how to make this code work:
using (var context = new Context())
{
...
foreach (var item in collection)
{
IQueryable<entity> pages = from p in context.pages
where p.Serial == item.Key.ToString()
select p;
foreach (var page in pages)
{
DataManager.AddPageToDocument(page, item.Value);
}
}
Console.WriteLine("Done!");
Console.Read();
}
When it enters into the second foreach (var page in pages) it throws an exception saying:
LINQ to Entities does not recognize the method 'System.String
ToString()' method, and this method cannot be translated into a store
expression.
Anyone know why this happens?
Just save the string to a temp variable and then use that in your expression:
var strItem = item.Key.ToString();
IQueryable<entity> pages = from p in context.pages
where p.Serial == strItem
select p;
The problem arises because ToString() isn't really executed, it is turned into a MethodGroup and then parsed and translated to SQL. Since there is no ToString() equivalent, the expression fails.
Note:
Make sure you also check out Alex's answer regarding the SqlFunctions helper class that was added later. In many cases it can eliminate the need for the temporary variable.
As others have answered, this breaks because .ToString fails to translate to relevant SQL on the way into the database.
However, Microsoft provides the SqlFunctions class that is a collection of methods that can be used in situations like this.
For this case, what you are looking for here is SqlFunctions.StringConvert:
from p in context.pages
where p.Serial == SqlFunctions.StringConvert((double)item.Key.Id)
select p;
Good when the solution with temporary variables is not desirable for whatever reasons.
Similar to SqlFunctions you also have the EntityFunctions (with EF6 obsoleted by DbFunctions) that provides a different set of functions that also are data source agnostic (not limited to e.g. SQL).
The problem is that you are calling ToString in a LINQ to Entities query. That means the parser is trying to convert the ToString call into its equivalent SQL (which isn't possible...hence the exception).
All you have to do is move the ToString call to a separate line:
var keyString = item.Key.ToString();
var pages = from p in context.entities
where p.Serial == keyString
select p;
Cast table to Enumerable, then you call LINQ methods with using ToString() method inside:
var example = contex.table_name.AsEnumerable()
.Select(x => new {Date = x.date.ToString("M/d/yyyy")...)
But be careful, when you calling AsEnumerable or ToList methods because you will request all data from all entity before this method. In my case above I read all table_name rows by one request.
Had a similar problem.
Solved it by calling ToList() on the entity collection and querying the list.
If the collection is small this is an option.
IQueryable<entity> pages = context.pages.ToList().Where(p=>p.serial == item.Key.ToString())
Hope this helps.
Upgrading to Entity Framework Version 6.2.0 worked for me.
I was previously on Version 6.0.0.
Hope this helps,
Change it like this and it should work:
var key = item.Key.ToString();
IQueryable<entity> pages = from p in context.pages
where p.Serial == key
select p;
The reason why the exception is not thrown in the line the LINQ query is declared but in the line of the foreach is the deferred execution feature, i.e. the LINQ query is not executed until you try to access the result. And this happens in the foreach and not earlier.
If you really want to type ToString inside your query, you could write an expression tree visitor that rewrites the call to ToString with a call to the appropriate StringConvert function:
using System.Linq;
using System.Data.Entity.SqlServer;
using System.Linq.Expressions;
using static System.Linq.Expressions.Expression;
using System;
namespace ToStringRewriting {
class ToStringRewriter : ExpressionVisitor {
static MethodInfo stringConvertMethodInfo = typeof(SqlFunctions).GetMethods()
.Single(x => x.Name == "StringConvert" && x.GetParameters()[0].ParameterType == typeof(decimal?));
protected override Expression VisitMethodCall(MethodCallExpression node) {
var method = node.Method;
if (method.Name=="ToString") {
if (node.Object.GetType() == typeof(string)) { return node.Object; }
node = Call(stringConvertMethodInfo, Convert(node.Object, typeof(decimal?));
}
return base.VisitMethodCall(node);
}
}
class Person {
string Name { get; set; }
long SocialSecurityNumber { get; set; }
}
class Program {
void Main() {
Expression<Func<Person, Boolean>> expr = x => x.ToString().Length > 1;
var rewriter = new ToStringRewriter();
var finalExpression = rewriter.Visit(expr);
var dcx = new MyDataContext();
var query = dcx.Persons.Where(finalExpression);
}
}
}
In MVC, assume you are searching record(s) based on your requirement or information.
It is working properly.
[HttpPost]
[ActionName("Index")]
public ActionResult SearchRecord(FormCollection formcollection)
{
EmployeeContext employeeContext = new EmployeeContext();
string searchby=formcollection["SearchBy"];
string value=formcollection["Value"];
if (formcollection["SearchBy"] == "Gender")
{
List<MvcApplication1.Models.Employee> emplist = employeeContext.Employees.Where(x => x.Gender == value).ToList();
return View("Index", emplist);
}
else
{
List<MvcApplication1.Models.Employee> emplist = employeeContext.Employees.Where(x => x.Name == value).ToList();
return View("Index", emplist);
}
}
I got the same error in this case:
var result = Db.SystemLog
.Where(log =>
eventTypeValues.Contains(log.EventType)
&& (
search.Contains(log.Id.ToString())
|| log.Message.Contains(search)
|| log.PayLoad.Contains(search)
|| log.Timestamp.ToString(CultureInfo.CurrentUICulture).Contains(search)
)
)
.OrderByDescending(log => log.Id)
.Select(r => r);
After spending way too much time debugging, I figured out that error appeared in the logic expression.
The first line search.Contains(log.Id.ToString()) does work fine, but the last line that deals with a DateTime object made it fail miserably:
|| log.Timestamp.ToString(CultureInfo.CurrentUICulture).Contains(search)
Remove the problematic line and problem solved.
I do not fully understand why, but it seems as ToString() is a LINQ expression for strings, but not for Entities. LINQ for Entities deals with database queries like SQL, and SQL has no notion of ToString(). As such, we can not throw ToString() into a .Where() clause.
But how then does the first line work? Instead of ToString(), SQL have CAST and CONVERT, so my best guess so far is that linq for entities uses that in some simple cases. DateTime objects are not always found to be so simple...
My problem was that I had a 'text' data type for this column (due to a migration from sqlite).
Solution: just change the data type to 'nvarchar()' and regenerate the table.
Then Linq accepts the string comparison.
I am working on retiring Telerik Open Access and replacing it with Entity Framework 4.0. I came across same issue that telerik:GridBoundColumn filtering stopped working.
I find out that its not working only on System.String DataTypes. So I found this thread and solved it by just using .List() at the end of my Linq query as follows:
var x = (from y in db.Tables
orderby y.ColumnId descending
select new
{
y.FileName,
y.FileSource,
y.FileType,
FileDepartment = "Claims"
}).ToList();
Just turn the LINQ to Entity query into a LINQ to Objects query (e.g. call ToArray) anytime you need to use a method call in your LINQ query.
This linq works fine:
return (from page in db.WebPages
where pageids.Contains(page.page_id)
select new Result
{
a = page.a,
b = page.b
});
However I would like to do something like this which does not work:
return (from page in db.WebPages select GetResult(page));
public Result GetResult(WebPage page)
{
return new Result
{
a = page.a,
b = page.b
};
}
This gives an error of no supported translation to Linq.
The reason that I want to do this is because the Result is more complex and the code is done a lot of times so to avoid writing the same thing in every linq select new {} clause.
Try something like the following:
private static IQueryable<Result> toResults(IQueryable<WebPage> query)
{
return query.Select(item => new Result
{
//...
}
}
Usage:
return toResults(db.WebPages);
Organizing them like this has worked for me with other query providers, although I haven't worked with Linq-to-SQL personally.
You are trying to execute the method GetResult() in the scope of the database. Linq to Sql / Entities is translated into SQL queries where your method will not work. You will have to go with approach A. Alternatively you can force execution of the later part of your query as Linq to Objects using AsEnumerable():
return (from page in db.WebPages
where pageids.Contains(page.page_id)).AsEnumerable()
.Select(GetResult);
Try this?
return db.WebPages.Where( x=> x.Contains(page.page_id).Select(x => GetResult(x));
i have a list of event Ids returned from an xml document as shown below
public IEnumerable<EventFeed> GetEventIdsByEventDate(DateTime eventDate)
{
return (from feed in xmlDoc.Descendants("Show")
from ev in feed.Elements("Event")
where Convert.ToDateTime(ev.Attribute("Date").Value).ToShortDateString() == eventDate.ToShortDateString()
select new EventFeed()
{
EventShowCode = feed.Attribute("Code").Value
}).ToList();
}
i now need to query my database to match events that equal the eventIds returned from the above method. so i would have something like:
select * from eventsdb where eventId in GetEventIdsByEventDate()
how can i do this using LINQ
i cant seem to get any of the answers working.
this is the method that looks up the eventIds from an XML feed
public IList<EventsDetails> GetEventIds(DateTime eventDate)
{
var eventids = (from feed in xmlDoc.Descendants("Show")
from ev in feed.Elements("Event")
where Convert.ToDateTime(ev.Attribute("Date").Value).ToShortDateString() == eventDate.ToShortDateString()
select new EventsDetails()
{
EventId = feed.Attribute("Code").Value
}).ToList();
return eventids;
}
this is the method that looks up the events in my database
public IEnumerable<EventFeed> GetAllEventsFromDatabase()
{
var allEvents = from eventsList in GetEventsList()
select new EventFeed()
{
EventName = eventsList.Title,
EventSummary = eventsList.Introduction,
EventShowCode = eventsList.EventId,
EventImageSmall = eventsList.EventImageThumbUrl,
EventUrl = eventsList.Url,
EventSortBy = eventsList.SortOrder
};
return allEvents.OrderBy(x => x.EventSortBy);
}
and this is the method to look up any matching eventIds in the XML that exist in my database
public IEnumerable<EventFeed> FilteredEvents(DateTime eventDate)
{
return GetAllEventsFromDatabase().Where(p => GetEventIds(eventDate).Contains<EventsDetails>(p.EventShowCode));
}
the project fails to build with the following error:
Error 9 Argument '2': cannot convert from 'string' to 'Events.EventsDetails'
var eventids = GetEventIdsByEventDate(DateTime.Now);
var result = eventsdb.Where(e => eventids.Contains(e));
If you are returnning List<EventFeed> inside the method, you should change the method return type from IEnumerable<EventFeed> to List<EventFeed>.
In likeness of how I found this question using Google, I wanted to take it one step further.
Lets say I have a string[] states and a db Entity of StateCounties and I just want the states from the list returned and not all of the StateCounties.
I would write:
db.StateCounties.Where(x => states.Any(s => x.State.Equals(s))).ToList();
I found this within the sample of CheckBoxList for nu-get.
The "in" in Linq-To-Sql uses a reverse logic compared to a SQL query.
Let's say you have a list of integers, and want to find the items that match those integers.
int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var items = from p in context.Items
where numbers.Contains(p.ItemId)
select p;
Anyway, the above works fine in linq-to-sql but not in EF 1.0. Haven't tried it in EF 4.0
Execute the GetEventIdsByEventDate() method and save the results in a variable, and then you can use the .Contains() method