I made an generic extension method to add new entities only if a specified key doesn’t exists. This works for the data in the database, but I also want to check the Local values. Maybe it has been added and didn’t saved to the database yet. I use the following code:
public static void AddIfNotExists<TEntity>(this IDbSet<TEntity> set, Expression<Func<TEntity, object>> identifierexp, params TEntity[] entities) where TEntity : class
{
if (set == null)
throw new Exception("DbSet not assinged");
if (entities == null)
throw new Exception("Entities not assinged");
var dbSet = set as DbSet<TEntity>;
if (dbSet != null)
{
MemberExpression body = identifierexp.Body as MemberExpression;
if (body == null)
{
UnaryExpression ubody = (UnaryExpression)identifierexp.Body;
body = ubody.Operand as MemberExpression;
}
ParameterExpression parameter = Expression.Parameter(typeof(TEntity), "X");
Expression property = Expression.Property(parameter, body.Member.Name);
foreach (var entity in entities)
{
Expression target = Expression.Constant(entity.GetType().GetProperty(body.Member.Name).GetValue(entity).ToString());
Expression containsMethod = Expression.Call(property, "Contains", null, target);
Expression<Func<TEntity, bool>> lamba = Expression.Lambda<Func<TEntity, bool>>(containsMethod, parameter);
var Exists = dbSet.SingleOrDefault(lamba);
if (Exists == null)
{
dbSet.Add(entity);
}
}
}
}
When I change it with the following code he can’t use Lambda
on the local property. Because the is not a right overload. But as far as I can see the overload is the same. What is the right way?
var Exists = dbSet.Local.SingleOrDefault(lamba);
if (Exists != null)
return;
Exists = dbSet.SingleOrDefault(lamba);
if (Exists != null)
return;
dbSet.Add(entity);
And the error i'm getting:
Error 1 'System.Collections.ObjectModel.ObservableCollection<TEntity>' does not contain a definition for 'SingleOrDefault' and the best extension method overload 'System.Linq.Enumerable.SingleOrDefault<TSource>(System.Collections.Generic.IEnumerable<TSource>, System.Func<TSource,bool>)' has some invalid arguments
That is because dbSet.Local
doesn't implement IQueryable<T>
. The LINQ extensions for IEnumerable<T>
only accept delegates, not expressions representing those.
There are two ways to fix that:
Compile your lambda expression to a delegate by using the Compile()
method, and use that for the local query.
The resulting code should look like this:
var Exists = dbSet.Local.SingleOrDefault(lamba.Compile());
Wrap the local collection in an IQueryable<T>
implementation by invoking AsQueryable()
on it.
The resulting code should look like this:
var Exists = dbSet.Local.AsQueryable().SingleOrDefault(lamba);