I want to create EFCore query that will return all entities that meet some conditions for their related entities.
For example entities look like this (that's pretty simplified example):
public class MyEntity
{
public int Id { get; set; }
public List<MyOtherEntity> OtherEntities { get; set; }
}
public class MyOtherEntity
{
public int Id { get; set; }
public int SomeProperty1 { get; set; }
public int SomeProperty2 { get; set; }
}
And I have a method that takes array of simplified MyOtherEntity objects:
public class MySimpleOtherEntity
{
public int SomeProperty1 { get; set; }
public int SomeProperty2 { get; set; }
}
Now I have some method that takes IEnumerable of these simplified objects, and I want to return all of the MyEntity objects that have in their relations MyOtherEntities that match all of the required conditions:
public IEnumerable<MyEntity> GetMyEntitiesByMyOtherEntities(IEnumerable<MySimpleOtherEntity> entities)
{
// example with some static values
// we want to find all MyEntities that have MyOtherEntity with value 1,2 AND MyOtherEntity with value 2,2
_dataContext
.Where(x => x.OtherEntities.Any(y => y.SomeProperty1 == 1 && y.SomeProperty2 == 2)
&&
x.OtherEntities.Any(y => y.SomeProperty1 == 2 && y.SomeProperty2 == 2)
&&
.
. // and so on
.)
.ToList();
The query above is translated correctly to SQL. I already created a solution with glueing some raw SQL parts that gives correct results, because it's just attaching AND EXISTS parts with proper subqueries.
That being said I would (if possible) rather like to have it as some dynamic LINQ Where expression. SQL parser creates pretty much as good SQL as I would do for this example, but with raw SQL queries I lose some of the control that EFCore gives me.
I created some list of predicates that I would like to chain together and inject into .Where:
public IEnumerable<MyEntity> GetMyEntitiesByMyOtherEntities(IEnumerable<MySimpleOtherEntity> entities)
{
var predicates = new List<Expression<Func<MyEntity, bool>>>();
foreach(var entity in entities)
{
predicates.Add(x => x.OtherEntities.Any(y => y.SomeProperty1 == entity.SomeProperty1
&& y.SomeProperty2 == entity.SomeProperty2);
}
}
Unfortunately I don't know how to chain them properly. I tried to use
var combinedPredicate = predicates.Aggregate((l, r) => Expression.AndAlso(l, r));
But it has some casting issues (probably related to AndAlso returning BinaryExpression?) that won't allow me to do it in such simple way.
How can I achieve that so it's not overly complicated?