EF -不能应用运算符'=='to类型为'TId'和& # 39;tid # 39;

本文关键字:不能 tid TId 应用 EF to 类型 运算符 | 更新日期: 2023-09-27 18:14:01

我有这个通用类,它使用实体框架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; }
}

我的问题是它不编译。我得到这个错误:

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

我试着把它改成x => Equals(x.Id, id),但是EF无法翻译。还有别的办法吗?

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

't运算符==可以应用于c#中的泛型类型吗?

如何求解Operator '!='不能应用于'T'和& # 39;t # 39;

EF -不能应用运算符'=='to类型为'TId'和& # 39;tid # 39;

Update:这是一个使用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));

等。

只有当您将TId类型约束为引用类型时才会编译:

public class GenericRepository<TEntity, TId> 
    where TEntity: class, IIdentifyable<TId> 
    where TId: class

但是,这可能不适合您的情况,因此您必须创建不同的类来支持GUID, int或长id值。

这是因为您不能通过==操作符比较泛型类型和泛型类型。而是使用等号运算符在你的代码中:

 public virtual TEntity GetById(TId id)
{
    using (var context = new DbContext())
    {
        var dbSet = context.Set<TEntity>();
        var currentItem = dbSet.FirstOrDefault(x => x.Id.Equals(id));
        return currentItem;
    }
}