我有这个泛型类,它使用Entity Framework 6.x。
public class GenericRepository<TEntity, TId> where TEntity, class, IIdentifyable<TId>
{
public virtual TEntity GetById(TId id)
{
using (var context = new DbContext())
{
var dbSet = context.Set<TEntity>();
var currentItem = dbSet.FirstOrDefault(x => x.Id == id);
return currentItem;
}
}
public virtual bool Exists(TId id)
{
using (var context = new DbContext())
{
var dbSet = context.Set<TEntity>();
var exists = dbSet.Any(x => x.Id == id);
return exists ;
}
}
}
这些接口:
public interface IIdentifyable : IIdentifyable<int>
{
}
public interface IIdentifyable<out TId>
{
TId Id { get; }
}
看起来像这样的实体:
public class CustomerEntity : IIdentifyable<int>
{
public string Name { get; set; }
public int Id { get;set; }
}
public class ProductEntity : IIdentifyable<Guid>
{
public string Name { get; set; }
public Guid Id { get;set; }
}
我的问题是它没有编译。我收到此错误:
无法应用运营商&#39;
==
&#39;对于&#39;TId
&#39;类型的操作数和&#39;TId
&#39;
我尝试将其更改为x => Equals(x.Id, id)
,但EF无法翻译它。有什么方法吗?
我知道我可以使用Find()
代替FirstOrDefault
。但我需要的不仅仅是上面提到的方法。 我有什么方法可以让EF将TId
与TId
进行比较? TId
目前只有guid
和int
。我已经看过下面的问题,但他们没有处理有关转换为SQL的问题。
Can't operator == be applied to generic types in C#?
How to solve Operator '!=' cannot be applied to operands of type 'T' and 'T'
答案 0 :(得分:10)
更新:这是一种简单易用的方式,适用于EF。
将以下约束添加到GenericRepository
类
where TId : IEquatable<TId>
然后使用Equals
方法
x => x.Id.Equals(id);
原始回答:
这是泛型的已知问题,通常使用EqualityComparer<T>.Default
而不是==
运算符来处理。但是,这种方法不适用于LINQ to Entities。
解决它的一种方法是使用System.Linq.Expressions
命名空间中的Expression
类动态构建谓词,如下所示:
public class GenericRepository<TEntity, TId> where TEntity: class, IIdentifyable<TId>
{
protected static Expression<Func<TEntity, bool>> EqualsPredicate(TId id)
{
Expression<Func<TEntity, TId>> selector = x => x.Id;
Expression<Func<TId>> closure = () => id;
return Expression.Lambda<Func<TEntity, bool>>(
Expression.Equal(selector.Body, closure.Body),
selector.Parameters);
}
}
并像这样使用它:
dbSet.FirstOrDefault(EqualsPredicate(id));
或
dbSet.Any(EqualsPredicate(id));
等
答案 1 :(得分:-1)
This only compiles if you constrain the TId
type to be a reference type:
public class GenericRepository<TEntity, TId>
where TEntity: class, IIdentifyable<TId>
where TId: class
However, this may not be suitable in your case, so you would have to create different classes to support GUID, int or long id values.