EF - 不能将运算符'=='应用于'TId'和'TId'类型的操作数

smo*_*nes 12 c# generics entity-framework

我有这个泛型类,它使用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 ;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这些接口:

public interface IIdentifyable : IIdentifyable<int>
{
}

public interface IIdentifyable<out TId>
{
    TId Id { get; }
}
Run Code Online (Sandbox Code Playgroud)

和看起来像这样的实体:

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; }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是它没有编译.我收到此错误:

不能将运算符' =='应用于' TId'和' TId' 类型的操作数

我试图将其更改为x => Equals(x.Id, id),但EF无法翻译它.有什么办法吗?

我知道我可以用Find()而不是FirstOrDefault.但我需要的不仅仅是上面提到的方法.有没有什么办法可以让EF比较TIdTId TId目前只有guidint.我已经看过下面的问题了,但他们没有处理有关转换为SQL的问题.

运算符==不能应用于C#中的泛型类型吗?

如何解决算子'!='不能应用于'T'和'T'类型的操作数

Iva*_*oev 13

这是泛型的已知问题,通常通过使用GenericRepository而不是Equals运算符来处理.但是,这种方法不适用于LINQ to Entities.

解决它的一种方法是使用命名空间中的EqualityComparer<T>.Default类动态构建谓词,==如下所示:

where TId : IEquatable<TId>
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

x => x.Id.Equals(id);
Run Code Online (Sandbox Code Playgroud)

要么

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

等等

更新:这是另一种适用于EF的方式.

将以下约束添加到Expression类中

dbSet.FirstOrDefault(EqualsPredicate(id));
Run Code Online (Sandbox Code Playgroud)

然后使用System.Linq.Expressions方法

dbSet.Any(EqualsPredicate(id));
Run Code Online (Sandbox Code Playgroud)