The LINQ expression could not be translated - c#

I have a table called Orders and a list called Customers. Orders has a property CustomerId. Now I want to get all orders of customers that are in my Customers list.
This is what I tried:
IEnumerable<Customer> customers; // list of customers
List<Order> orders = dbContext.Orders.Where(x => customers.Any(y => y.Id == x.CustomerId)).Include(x => x.someOtherTable).ToList();
For some reason this always results in an exception saying that the LINQ expression could not be translated. My assumption is that this is due to the fact that the CustomerId in Order is nullable. I am not sure though.
Order:
public int Id { get; set; }
public int? CustomerId { get; set; } // has to be nullable
...
Customer:
public int Id { get; set; }
public string Name { get; set; } // has to be nullable
...
This is only a small snippet due to simplicity.

No, the reason is that customers is IEnumerable, not IQueryable, so LINQ can not transale to SQL code your collection.
Convert your IEnumerable<Customer> to id list:
int[] ids = customers.Select(o => o.id).ToArray();
And Where with Contains:
List<Order> orders = dbContext.Orders.Where(x => ids.Contains(x.Id))
.Include(x => x.someOtherTable).ToList();

My issue was that I was using a read only property [x.Id] in the linq statement.
In my partial class:
public partial class Paddock
{
public int Id => EntityId;
}
My linq query with error:
var paddocks = _context.Paddocks.Where(x => ids.Contains(x.Id)).ToList();
Changing it to the true property fixed it for me:
var paddocks = _context.Paddocks.Where(x => ids.Contains(x.EntityId)).ToList();

Related

Using LINQ to query four nested entities. - Include Where condition

I have four classes Offer, Section, Field, and Option:
Where the offer has sections and every section has some fields and each field has some options as shown:
public class Offer
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Section> Sections { get; set; }
}
public class Section
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Field> Fields { get; set; }
}
public class Field
{
public int Id { get; set; }
public string Type { get; set; } //[question, group]
public ICollection<Option> Options { get; set; }
}
public class Option
{
public int Id { get; set; }
public string Name { get; set; }
}
I tried to get the offer by id including the nested entities and this code works perfectly:
var offer = _context.Offers
.Include(o => o.Sections
.Select(s => s.Fields
.Select(f => f.Options)))
.FirstOrDefault(o => o.Id == offerId);
The problem is when I try to filter the Fields by 'type' like this:
var offer = _context.Offers
.Include(o => o.Sections
.Select(s => s.Fields.Where(f => f.Type == "question")
.Select(f => f.Options)))
.FirstOrDefault(o => o.Id == offerId);
and I get this error:
The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties.
Parameter name: path
I've reviewed lots of questions and still cannot achieve that :(
Linq: query with three nested levels
EF LINQ include nested entities [duplicate]
Using LINQ to query three entitites. - Include path expression must refer to a navigation property defined on the type
Include() is used for Eager loading. It is the process whereby a query for one type of entity also loads related entities as part of the query, so that we don't need to execute a separate query for related entities. Where() is currently not supported inside Include.
If you want to just filter the result you can do something like this :
var offer = _context.Offers
.Include(o => o.Sections
.Select(s => s.Fields
.Select(f => f.Options)))
.FirstOrDefault(o => o.Id == offerId);
var filtered_offer =
new Offer
{
Sections = offer.Sections.Select(S => new Section
{
Id = S.Id,
Name = S.Name,
Fields = S.Fields.Where(f => f.Type == "question").ToList()
}).ToList(),
Id = offer.Id,
Name = offer.Name
};

Entity Framework: generate dynamic where clause and select custom columns

I have 3 tables: Person, PersonFriend, PersonGroup.
Using LINQ, i want to join the 3 tables, filter using a dynamically generated where clause, and select custom columns with flattened rows (flattened one-to-many relationship table columns).
Pseudo-SQL design:
CREATE TABLE Person (int id, varchar socialclass, date createddate);
CREATE TABLE Person_Friend (int id, id personid references person.id, id friendpersonid references person.id, varchar friendtype);
CREATE TABLE Person_Group (int id, int memberid references person.id, varchar membershiplevel);
Entities:
public class Person
{
public int Id { get; set; }
public string SocialClass { get; set; }
public DateTime? CreatedDate { get; set; }
public ICollection<PersonFriend> Friend { get; set; }
public ICollection<PersonGroup> Group { get; set; }
}
public class PersonFriend
{
public int Id { get; set; }
public int PersonId { get; set; }
public int FriendPersonId { get; set; }
public string FriendType { get; set; }
}
public class PersonGroup
{
public int Id { get; set; }
public int MemberId { get; set; }
public string MembershipLevel { get; set; }
}
query syntax LINQ:
var queryResult = from person in _context.Person
join friend in _context.PersonFriend on person.Id equals friend.FriendPersonId
join group in _context.PersonGroup on person.Id equals group.MemberId
where (friend.PersonId == 1 && friend.FriendType == "type1") || (friend.PersonId == 3 && friend.FriendType == "type2") || ...
select new { person.Id, person.SocialClass, person.CreatedDate, friend.FriendPersonId, friend.FriendType, group.Id, group.MembershipLevel };
Notice the where clause; Given a list of { PersonId, FriendType } object, I want to build the where clause like above.
Since I could not figure building a dynamic where clause for a query syntax LINQ,
I tried converting it to the Method syntax LINQ statement so i can leverage the PredicateBuilder (http://www.albahari.com/nutshell/predicatebuilder.aspx) but I run into the problem during Selecting one-to-many things into a flattened object.
var methodResult = _context.Person
.Include(x => x.Friend)
.Include(x => x.Group)
.Select(person => new { person.Id, person.SocialClass, person.CreatedDate, person.friend.FriendPersonId, person.friend.FriendType, person.group.Id, person.group.MembershipLevel });
notice that the above Select is not possible because friend is a ICollection.
I also tried using the above query syntax LINQ statement without the where clause, making it return a object instead of an annonymous object, and then calling the method .Where() with the predicate builder. But the built expression runs into LINQ => Entity Framework SQL conversion error and executes the where in the application, not in DB.
var queryResultWithoutWhere = from person in _context.Person
join friend in _context.PersonFriend on person.Id equals friend.FriendPersonId
join group in _context.PersonGroup on person.Id equals group.MemberId
select new SelectedObject { PersonId = person.Id, SocialClass = person.SocialClass, CreatedDate = person.CreatedDate, FriendId = friend.FriendPersonId, FriendType = friend.FriendType, GroupId = group.Id, MembershipLevel = group.MembershipLevel };
var predicate = PredicateBuilder.New<SelectedObject>(false);
foreach (var searchObject in searchRequestObjects)
{
predicate.Or(p => p.FriendPersonId == searchObject.FriendPersonId && p.FriendType == searchObject.FriendType);
}
var result = queryResultWithoutWhere.Where(predicate).ToList();
I feel like I tried everything I could, and I cannot seem to generate this SQL. Last resort would be writing a raw SQL string and then executing it, but I really would like to get this working with Entity Framework.
How would I accomplish creating a dynamic where clause, select into a custom flattened object, and have entity framework generate the SQL?
You can use SelectMany to flatten the collections:
var methodResult = Persons
.Include(x => x.Friend)
.Include(x => x.Group)
.SelectMany(person =>
person.Friend.SelectMany(friend =>
person.Group.Select(group =>
new {
person.Id,
person.SocialClass,
person.CreatedDate,
friend.FriendPersonId,
friend.FriendType,
GroupId = group.Id,
group.MembershipLevel
}
)
)
);

Linq to entities with join

I'm having some problem with my linqToEntities query. The Product is missing in the query result. Is there any way to return the ProductQuantity with the Product property correctly with a linqToEntities expression?
public class ProductQuantity
{
public string Id { get; set; }
public string SomeProperty { get; set; }
public Product Product { get; set; }
public Guid ProductId { get; set; }
}
public class Product
{
public Guid Id { get; set; }
public string SomeProperty { get; set; }
//...
}
// MyId is the ProductId I need
// The following will return all productQuantity detail but the Product property will be null
var result = myEntities.ProductQuantities.Include(x => x.Product).Where(x => x.ProductId == MyId)
// The following will work but I want to avoid refilling the object like this :
var result = myEntities.ProductQuantities.Include(x => x.Product).Where(x => x.ProductId == MyId)
.Select(y => new ProductQuantity{ SomeProperty = y.SomeProperty, Product = y.Product});
What is the proper way to do this with linq to entities? Why the product is not just simply returned with the query ?
Thanks
EDIT 1
Look like my problem is releated to .Include() when using more than one include.
Just add a Category to ProductQuantity in the preceding example :
//This will return the product but not the category
var result = myEntities.ProductQuantities.Include(x => x.Product).Include(x=> x.Category).Single(x => x.ProductId == MyId)
//This will return the category but not the product
var result = myEntities.ProductQuantities.Include(x => x.Category).Include(x=> x.Product).Single(x => x.ProductId == MyId)
Why only one include can be used and only the first one is working??????? (a saw tons of similar example on the net?)
Any help?
Seems like there is a problem when the same entity is used in any other include. (ex: Product.Unit and Product.AlternateUnit cannot be retreived at the same time if the same entity is used ie:unit) I dont really understand why but I use separate query to fetch the data that cannot be retrieved by the include.

Any of the properties equals any of a list of objects

I have a problem in Entity-Framework, using Code-First, that I couldn't solve.
Having entities of the type
public class Product {
public int ID {get; set; }
public virtual ICollection<Category> Categories { get; set; }
}
public class Category {
public int ID {get; set;}
public virtual ICollection<Product> Products { get; set; }
// rest omitted
}
in my database, i try to get all Products that have at least one Category from a list of given Categories. I need an Expression as this expression is combined with other expressions later.
Ie. i tried:
var searchFor = new List<Category>{...};
var expression = product => product.Categories.Any(cat => searchFor.Contains(cat))
Executing this later against a DbContext
context.Products.Where(expression).ToList();
creates an exception stating mainly that This context supports primitive types only.
Changing it to
var expression = product => product.Categories.Any(
cat => searchFor.Any(d => d.ID == cat.ID));
to get rid of the object comparison didn't help. I'm stuck. How can I manage that?
You should get rid of List<Category>, replacing it with a list of IDs, like this:
// I'm assuming that ID is of type long; please fix as necessary
var searchFor = new List<long>{...};
var expression = product =>
product.Categories.Any(cat => searchFor.Contains(cat.ID))
If you've already got a list of categories, you can build a list of IDs outside the query:
var searchForIds = searchFor.Select(x => x.ID).ToList();
var query = context.Products
.Where(product => product.Categories
.Any(cat => searchForIds.Contains(cat.ID)));
I don't know that that will work, but it might. (Apologies for the indentation... it's just to avoid scrolling.)

How to get unique entries of products in a List<Order> with LINQ

I have a classic Order -> Order Row scenario something like this:
public class Order
{
public int Id { get; set; }
public string Name { get; set; }
public List<OrderRow> OrderRows { get; set; }
}
public class OrderRow
{
public int Id { get; set; }
public int ProductId { get; set; }
public int Amount { get; set; }
}
and a List<Order>. From that list of orders I want to get a list of all the unique ProductIds.
I solved it like this:
var orders = new List<Order>();
// TODO get the orders from DB
var products = new Dictionary<int,int>();
orders.ForEach(order => order.OrderRows.ForEach(row => products[row.ProductId]=row.ProductId));
but I got questions about my use of Dictionary and why I didn't use LINQs GroupBy and also comments that it wasn't very clear how it worked. I think the solution is fine but the comments made me want to try to solve it in LINQ but for some reason I hit a brick wall trying.
How do I get a list of unique products ids from a list of orders with LINQ here?
Untested, but how about:
var products = orders.SelectMany(o => o.OrderRows)
.Select(r => r.ProductId)
.Distinct();
If you don't want to remember SelectMany, this query comprehension syntax will still get you where you want to go:
var productIDs =
(
from order in orders
from orderrow in order.OrderRows
select orderrow.ProductId
).Distinct();
This should get the unique product ids from the list of orders.
var orders = new List<Order>();
// Get orders from database.
IEnumerable<int> uniqueIds = orders.SelectMany(order => order.OrderRows)
.Select(row => row.ProductId).Distinct();

Categories