Get result function in LINQ without translate to store expression - c#

I need to get result from a function that it need to run in LINQ query. This result bind to grid but in run time I encounter with this error:
LINQ to Entities does not recognize the method 'System.String
GetName(System.Type, System.Object)' method, and this method cannot be
translated into a store expression.
This is my Code:
public IQueryable GetForRah_CapacityList(XQueryParam param)
{
var result = (from x in Data()
select new
{
Rah_CapacityId = x.Rah_CapacityId,
Rah_CapacityName = x.Rah_CapacityName,
Rah_St = Enum.GetName(typeof(Domain.Enums.CapacityState), x.Rah_St),
Rah_LinesId = x.Rah_LinesId
}).OrderByDescending(o => new { o.Rah_CapacityId });
return result;
}

GetName couldn't be translated to T-SQL, Linq to Entities couldn't recognize it. You can modify the code as below:
var result = (from x in Data().AsEnumerable()
select new
{
Rah_CapacityId = x.Rah_CapacityId,
Rah_CapacityName = x.Rah_CapacityName,
Rah_St = Enum.GetName(typeof(Domain.Enums.CapacityState), x.Rah_St),
Rah_LinesId = x.Rah_LinesId
}).OrderByDescending(o => new { o.Rah_CapacityId });
With .ToList() after data is loaded, any further operation (such as select) is performed using Linq to Objects, on the data already in memory.
EDIT: Also your method's return type is IQueryable while your query is IOrderedEnumerable of anonymous type, so you should either change the method's type to System.Object or as a better solution create a class, send the values into the class's properties, and then return it.

You can't use this method in Linq-To-Entities because LINQ does not know how to translate Enum.GetName to sql. So execute it in memory with Linq-To-Objects by using AsEnumerable and after the query use AsQueryable to get the desired AsQueryable:
So either:
var result = Data()
.OrderBy(x=> x.CapacityId)
.AsEnumerable()
.Select(x => new
{
Rah_CapacityId = x.Rah_CapacityId,
Rah_CapacityName = x.Rah_CapacityName,
Rah_St = Enum.GetName(typeof(Domain.Enums.CapacityState), x.Rah_St),
Rah_LinesId = x.Rah_LinesId
})
.AsQueryable();
You should first use OrderBy before you use AsEnumerable to benefit from database sorting performance. The same applies to Where, always do this before AsEnumerable(or ToList).

Related

Converting linq select into model, LINQ to Entities does not recognize the method, and this method cannot be translated into a store expression

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();

Method not supported in LINQ Store expression

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;

Using an IQueryable in another IQueryable

I've an extension method, which returns an IQueryable, to get company products, I just want to use it in a IQueryable as a subquery,
public static class DBEntitiesCompanyExtensions {
public static IQueryable<Product> GetCompanyProducts(this DBEntities db, int companyId)
{
return db.Products.Where(m => m.CompanyId == companyId);
}
}
And this is how I call it,
using(var db = new DBEntities()) {
var query = db.Companies.Select(m => new {
CompanyName = m.Name,
NumberOfProducts = db.GetCompanyProducts(m.CompanyId).Count()
});
}
I expected it to works beacuse my extension methods returns an IQueryable, so it could be used in a IQueryable, am I wrong?
This is what I get, Is that possible to make it work?
System.NotSupportedException: LINQ to Entities does not recognize the
method 'System.Linq.IQueryable`1[WebProject.Models.Company]
GetCompanyProducts(WebProject.Models.DBEntities, Int32)'
method, and this method cannot be translated into a store expression.
Problem is not IQueryable inside IQueryable, because you can include subqueries just not the way you did.
In your example whole Select is represented as expression tree. In that expression tree there is something like :
CALL method DBEntitiesCompanyExtensions.GetCompanyProducts
Now EF should somehow traslate this into SQL SELECT statement. It cannot do that, because it cannot "look inside" GetCompanyProducts method and see what is going on there. Nor can it execute this method and do anything with it's result. The fact it returns IQueryable does not help and is not related.
Instead of using IQueryable you should create an expression predicate and use inside the IQueryable object that is connected to the data source
the object looks like that:
Expression<Func<Person, bool>> predicate = x => x.Name == "Adi";
var data = await queryable.Where(predicate).ToListAsync();

Does converting an IEnumerable to IQueryable enumerate the query

I am using JQuery widgets's datatable to have a table control in an MVC application with server-side paging, sorting and filtering. When doing the filtering, I have the following method:
private IQueryable<ImportRfqViewModel> BuildLinqQuery(System.Collections.Specialized.NameValueCollection query)
{
var result = query.GetValues("filterslength");
var filtersCount = int.Parse(query.GetValues("filterslength")[0]);
if (result == null || filtersCount == 0)
{
return AllImportRfq();
}
Predicate<ImportRfqViewModel> orResultPredicate = PredicateExtensions.False<ImportRfqViewModel>();
for (var i = 0; i < filtersCount; i += 1)
{
var filterValue = query.GetValues("filtervalue" + i)[0].ToUpper();
var filterCondition = query.GetValues("filtercondition" + i)[0];
var filterDataField = query.GetValues("filterdatafield" + i)[0];
var filterOperator = query.GetValues("filteroperator" + i)[0];
if (filterDataField == "ImportRfqId")
{
Predicate<ImportRfqViewModel> predicate = p => p.ImportRfqId.ToString().Contains(filterValue);
orResultPredicate = orResultPredicate.Or(predicate);
}
else if (filterDataField == "DateCreated")
{
Predicate<ImportRfqViewModel> predicate = p => p.DateCreated.ToString("yyyy/MM/dd hh:mm:ss").Contains(filterValue);
orResultPredicate = orResultPredicate.Or(predicate);
}
...
}
Func<ImportRfqViewModel, bool> funcOr = l => orResultPredicate(l);
var allResearch = AllImportRfq().Where(funcOr).AsQueryable();
return allResearch;
}
I'm using the predicates in order to chain Or conditions. I obviously want to return an IQueryable so that the query is not run before I get to the part:
dbResult = dbResult.Skip(pagesize * pagenum).Take(pagesize);
The result of the predicate though, is an IEnumerable. This is why I call the .AsQueryable();
What I'm concerned about and don't know is whether the thing potentially is enumerating the query and then returning a IQueryable afterwards and throwing away the enumeration, if I'm making sense.
In all this I'm assuming that if I return an IEnumerable, it would execute the query.
Returning an IEnumerable by itself does not mean you are actually executing the query. It depends on the IEnumerable's creator, but normally IEnumerable is considered lazy and the underlying data source is touched only when enumerating an IEnumerator. Linq operators and extension methods behave nicely, so your AsQueryable() call does not enumerate the target, and you should be safe.
BTW, did you try changing your code from this:
Func<ImportRfqViewModel, bool> funcOr = l => orResultPredicate(l);
to this (as long as your query provider fully supports Where and the predicate you are building, of course)?
Expression<Func<ImportRfqViewModel, bool>> funcOr = ...;
This way you should be able to avoid going back and forth across IQueryable and IEnumerable, you would not need calling AsQueryable() at all and therefore you'd have no more doubts. If your query provider supports it, it would be much more efficient than what you are doing, which would execute the filtering after querying the underlying data source.
EDIT: just to make it clearer, the move from Func<> to Expression<> is not just a matter of changing the type of your variable, it actually means you'd have to review the whole process of building your predicates so that you always work by composing Expression instances, and not just Func ones, otherwise your resulting expression tree will hardly be understandable to your query provider.

Use a function within LINQ

I am using LINQ to create a list. But I want to use a function at the end to generate the object iself, something LINQ complains about
LINQ to Entities does not recognize the method 'WashroomStatusItem GetWashroomStatusForItem(WashroomStatus)' method, and this method cannot be translated into a store expression.
What am I doing wrong?
var query = (from c in context.WashroomStatus
where c.WashroomId == GroupItem.WashroomID
select GetWashroomStatusForItem(c));
private WashroomStatusItem GetWashroomStatusForItem(WashroomStatus item)
{
WashroomStatusItem temp = new WashroomMonitorWCF.WashroomStatusItem();
//do stuff with it
return temp;
}
The problem is that the SQL conversion can't convert your method into SQL. You should use AsEnumerable() to "switch" from the out-of-process provider to LINQ to Objects. For example:
var query = context.WashroomStatus
.Where(c => c.WashroomId == GroupItem.WashroomID)
.AsEnumerable()
.Select(c => GetWashroomStatusForItem(c));
Note that if GetWashroomStatusForItem only uses some properties, you may want to project to those separately first, to reduce the amount of information fetched from the server:
var query = context.WashroomStatus
.Where(c => c.WashroomId == GroupItem.WashroomID)
.Select(c => new { c.Location, c.Date };
.AsEnumerable()
.Select(p => GetWashroomStatusForItem(p.Location, p.Date));
Jon Skeet's answer is correct, but I'd add that depending on the nature of GetWashroomStatusForItem(), it should probably either be broken down into LINQ statements and added into the query itself, or it should be executed after the query has returned.
So, lets say GetWashroomStatusForItem() looks something like this: note that this is extremely oversimplified.
public static WashroomStatus GetWashroomStatusForItem(Item c)
{
return c.WashroomStatus;
}
it should just be added to the LINQ query like this:
var query = (from c in context.WashroomStatus
where c.WashroomId == GroupItem.WashroomID
select c.WashroomStatus);
But if it relies heavily on stuff not in the db, I'd just end the Linq statement before you get the WashroomStatus, and then call GetWashroomStatusForItem() on the results. It's not gonna a performance difference since Linq uses lazy evaluation, and you generally want to keep db operations separate from "programmatic" ones.

Categories

Resources