Linq Exception The expression must be a MemberExpression - c#

i am working on a linq query and try to include entities upto multi level as per suggested in Mutilevel include in C# Linq.
So i write down a query like
query.Include(u => u.Stops.Select(d => d.Address).Select(c => c.City));
where query is
IQueryable<SomeEntity> query
and i get the exception
The expression must be a MemberExpression
Screenshot for my entities is
Kindly help, Thanks

This overload (extension?) of Include does not support inclusion through method chains. It does, however, support nesting of inclusion expressions:
query.Include(u => u.Stops.Select(d => d.Address.City));
// this would work too:
categories.Include(u => u.SubCategories.Select(c => c.Items.Select(i => i.Manufacturer)));
// equals
categories.Include("SubCategories.Items.Manufacturer");
The Select part is only for accessing members of collection type property items.

Related

C# - filtering collection based on another collection exception

I've searched through numerous examples on how to filter collection based on another collection and I have found an easy way, like so:
var oShipnotes = await DbContext.ShipNotes.Where(s => oManageRouteDto.ShipNotes.Any(mr => mr.Id == s.Id)).ToListAsync();
however it throws an exception that says it cannot be translated to SQL query.
Could anyone point me the right direction how to solve this?
Thanks!
Replace nested LINQ query to materialized list of identifiers:
// 1) get the list of target ship note identifiers
var ids = oManageRouteDto.ShipNotes.Select(mr => mr.Id).ToList();
// 2) pass this list into Where using Contains
var oShipnotes = await DbContext.ShipNotes.Where(s => ids.Contains(s.Id)).ToListAsync();
EF is aware of this pattern and translates IList<T>.Contains into SQL's IN condition.
Since EF deals with IQueryables, each LINQ query must be translated into valid SQL expression. As a result, EF and underlying provider cannot translate every valid LINQ query (from C# perspective) just because SQL is not C#.

LINQ to SQL to find values starting with characters from another table

I would like to retrieve a list of values from a SQL table where the records start with a prefix defined in another table.
This post gives an accurate answer, but it is for EF and not Linq to SQL.
With SQL I get an error:
Only arguments that can be evaluated on the client are supported for
the String.Contains method
Sample code:
var lookupList = dc.LookupTable.Select(p => p.Prefix);
var q = dc.Personnel
.Where(item => lookupList
.Any(p => item.Surname.StartsWith(p))).Select(x => x.PersonID);
This works with EF. Yes, I can ToList() my collections but the tables are big and the query becomes very slow. Any suggestions on how to make it work without enumerating my objects?
This part: .Any(p => item.Surname.StartsWith(p)) gives the error:
Only arguments that can be evaluated on the client are supported for the String.Contains method
It tells you Contains method does not work with the given parameter which can only be evaluated on the server. StartsWith basically uses the same mechanism.
So, instead of Contains or StartsWith you should use IndexOf to find out whether or not the containing parameter is occured at the beginning or not:
.Any(p => item.Surname.IndexOf(p) == 0)
According to MSDN:
IndexOf(T):
The index of item if found in the list; otherwise, -1.
This answer is partially taken from here.

How do I translate this unsupported LINQ query to its native Mongo equivalent?

I have this chained LINQ query which MongoDB fails to execute:
RoleCollection.AsQueryable().Where(r => r.Users.Any(id => id == user.Id))
.Select(r => r.Name).ToArray();
This results in the following error:
Any is only support for items that serialize into documents. The current serializer is ObjectIdSerializer and must implement IBsonDocumentSerializer for participation in Any queries.
How can I translate the query into a native query which Mongo will support?
You should be able to replace .Any() with a combination of .Where() and a length check, like so:
RoleCollection.AsQueryable().Where(r => r.Users.Where(id => id == user.Id).Length > 0)
.Select(r => r.Name).ToArray();
Note however that there is a performance implication here since it will pull back all of the Users with that id to do a length on it.
I'm not sure what Mongo supports (Sorry I'm answering this purely from a linq perspective), but you could also use a combination of FirstOrDefault and perform a null check in your where. That might be better since you're only ever expecting one or nothing:
RoleCollection.AsQueryable().Where(r => r.Users.FirstOrDefault(id => id == user.Id) != null)
.Select(r => r.Name).ToArray();
I got the following query working, although I'm not entirely certain as to its semantics yet:
RoleCollection.Find(new QueryDocument("Users", user.Id))
.Select(r => r.Name).ToArray();

Using NHibernate LINQ, Is it possible to put a .Where() clause after a .ThenFetch()

I understand that in NHibernate LINQ, you need to have the fetches at the end of your code but how would you filter on something that is loaded via a ThenFetch?
Here is an example
IEnumerable<Project> list = Session.Query<Project>()
.FetchMany(r => r.ProjectSponsors)
.ThenFetch(r => r.Sponsor)
.Where(r => !r.Name == "Joe");
this above doens't work as it throws a NotSupportedException.
Any ideas on the right way to implement the above query?
No currently it isn't. Fetch can only be used as last statement.

LINQ to Entities: Using DateTime.AddMonth in Lambda Expression

I've been reading some posts but I don't find a solution to a problem that I have with LINQ To Entities, Lambda Expressions and DateTime.AddMonth.
The problem is that I'm trying to use DateTime.AddMonth inside a Lambda Expression and I'm getting this error:
"LINQ to Entities does not recognize the method 'System.DateTime
AddMonths(Int32)' method, and this method cannot be translated into a
store expression"
when I execute this piece of code:
List<Orders> orders = context.Orders
.Where(o => o.IdOrderStatus == 1)
.Where(o => o.PaymentDate.Value.AddMonths(o.Products.ProductCategories.CommissionableMonths) > DateTime.Now)
.ToList();
Is there a way to avoid this exception but mantaining the same behavior?
I don't know a lot about Linq, Lambdas or Entity Framework.
Thank you very much in advance!
Gsus.
You could return the necessary information without filtering on the date, then filter on the date afterward. (Of course, I'm not sure what size your data will be, so this may be inefficient. If so, you'll need a SQL-based solution of some sort -- maybe a stored procedure.)
List<Orders> orders = context.Orders
.Where(o => o.IdOrderStatus == 1)
.ToList();
orders = orders.Where(o.PaymentDate.Value.AddMonths(o.Products.ProductCategories.CommissionableMonths) > DateTime.Now);
This turns the AddMonths portion of the query in to a Linq-to-Objects method instead of Linq-to-Entities call.
try this,
var today =DateTime.Now;
List<Orders> orders = context.Orders
.Where(o => o.IdOrderStatus == 1)
.Where(o => SqlFunctions.DateAdd("month" ,o.Products.ProductCategories.CommissionableMonths,o.PaymentDate) > today)
.ToList();
LINQ to Entities converts your linq expression into SQL code, sometimes this conversion is seamless such as integer addition, selects, groups, etc, but sometimes the abstraction leaks, as in date operations.

Categories