score:2
EF Core metadata services can be used to obtain information about primary key of an entity, like
var entityType = context.Model.FindEntityType(typeof(T));
var primaryKey = entityType.FindPrimaryKey();
Then this information can be used to build dynamically equality comparer:
public static Expression<Func<T, T, bool>> GetPrimaryKeyCompareExpression<T>(this DbContext context)
{
var entityType = context.Model.FindEntityType(typeof(T));
var primaryKey = entityType.FindPrimaryKey();
var first = Expression.Parameter(typeof(T), "first");
var second = Expression.Parameter(typeof(T), "second");
var body = primaryKey.Properties
.Select(p => Expression.Equal(
Expression.Property(first, p.PropertyInfo),
Expression.Property(second, p.PropertyInfo)))
.Aggregate(Expression.AndAlso); // handles composite PKs
return Expression.Lambda<Func<T, T, bool>>(body, first, second);
}
which in turn can be compiled to delegate and used inside the LINQ to Objects (since you are using IEnumerable
s) query, e.g.
var setA = context.Set<T>().AsEnumerable();
var setB = context2.Set<T>().AsEnumerable();
var comparePKs = context.GetPrimaryKeyCompareExpression<T>().Compile();
var notExistsOnA = setB
.Where(b => !setA.Any(a => comparePKs(a, b)))
.ToList();
But note that in LINQ to Objects, !Any(...)
inside query criteria is inefficient, as it it linear search operation, so the resulting time complexity is quadratic (O(Na * Nb
), so you'll have performance issues with bigger data sets.
So in general it would be better to use join operator. But instead of comparison, it needs key selector, which also can be built similar to the above, but this time emitting Tuple
instances (in order to handle composite PKs), e.g.
public static Expression<Func<T, object>> GetPrimaryKeySelector<T>(this DbContext context)
{
var entityType = context.Model.FindEntityType(typeof(T));
var primaryKey = entityType.FindPrimaryKey();
var item = Expression.Parameter(typeof(T), "item");
var body = Expression.Call(
typeof(Tuple), nameof(Tuple.Create),
primaryKey.Properties.Select(p => p.ClrType).ToArray(),
primaryKey.Properties.Select(p => Expression.Property(item, p.PropertyInfo)).ToArray()
);
return Expression.Lambda<Func<T, object>>(body, item);
}
and could be used as follows
var selectPK = context.GetPrimaryKeySelector<T>().Compile();
var notExistsOnA = setB
.GroupJoin(setA, selectPK, selectPK, (b, As) => (b, As))
.Where(r => !r.As.Any())
.Select(r => r.b)
.ToList();
Source: stackoverflow.com
Related Articles
- Building dynamic expression to compare between two table
- passing dynamic expression to order by in code first EF repository
- how to create a pivot table with dynamic column using linq tree expression
- Dynamic linq Building Expression
- Dynamic LINQ: Compare date between today and four weeks ago
- Make access possible to dynamic table LINQ EF6 Code First
- Building dynamic query in a loop using Expression trees
- I can't seem to be able to access a Dictonary<string, object> values while building a dynamic linq expression
- Build a dynamic expression with nested OR between many ANDS
- Dynamic Expression Building Error
- Building Dynamic GroupBy Selector Expression Tree With Multiple Properties
- code first join between table not appeared
- EF5 code first datetime2, building a linq expression
- Dynamic lambda expression - compare properties in a List<T> postion 0 with properties in position 1
- Difference between expression lambda and statement lambda
- Simple Examples of joining 2 and 3 table using lambda expression
- Building a LINQ expression tree: how to get variable in scope
- Difference between Query Expression and Method Expression in LINQ?
- Error: An expression tree may not contain a dynamic operation
- How to detect IsNull / NotNull when building dynamic LINQ expressions?
- Equivalent of SQL Between Statement Using Linq or a Lambda expression
- Building an OrderBy Lambda expression based on child entity's property
- How to build a dynamic AND OR linq expression tree in a loop
- Expression Cast Error - No coercion operator is defined between types
- Dynamic table names in Entity Framework linq
- Common Table Expression in EntityFramework
- Building Dynamic LINQ Queries based on Combobox Value
- Extension method returning lambda expression through compare
- Dynamic Expression using LINQ. How To Find the Kitchens?
- Difference between LINQ Queries & Lambda expression
- How to implement FIND method of EF in Unit Test?
- Query File System Info Dynamically using LINQ
- Linq error when I use First() and FirstOrDefault()
- Linq Lambdas vs SQL Like Notation
- Why one loop is performing better than other memory wise as well as performance wise?
- Split a list of objects into sub-lists of contiguous elements using LINQ?
- "The entity or complex type cannot be constructed in a LINQ to Entities query" in Controler
- Find an object within a list and replace its value
- Group by on IEnumerable<DataRow>
- Linq select result with duplicating rows
- How can i select distinct using one field
- How to select distinct based on combination of two fields with LINQ?
- C# LINQ SQL EntityFramework challenge
- Adding an artificial row to an anonymous Linq resultset
- MVC Data Annotation - Required Field not Working
- QueryExtender Linq Orderby using TimeSpan.Parse
- Is the from keyword preferable to direct method calls in C#?
- Union tables with LINQ query for custom Model
- Filter data from MongoDB with .NET driver
- Alternative implementation for creating a dictionary using Linq