对 EF 的泛型参数使用 Equals 时出错

本文关键字:Equals 出错 参数 EF 泛型 | 更新日期: 2023-09-27 18:20:09

我有以下两个泛型类:

 public abstract class Entity<T> : IEntity<T>, IAuditableEntity,ISoftDeletable where T : struct
    {
        public T Id { get; set; }
        public DateTime CreatedDate { get; set; }
        public string CreatedBy { get; set; }
        public DateTime UpdatedDate { get; set; }
        public string UpdatedBy { get; set; }
        public bool Deleted { get; set; }
    }

    public abstract class Repository<TEntity,TKey> : IRepository<TEntity, TKey> where TEntity :Entity<TKey> where TKey : struct           
    {
        protected DbContext Context;
        protected readonly IDbSet<TEntity> Set;
        protected Repository(DbContext context)
        {
            Context = context;
            Set = Context.Set<TEntity>();
        }
        public TEntity Get(TKey key)
        {               
            var output = Set.FirstOrDefault(o => o.Id.Equals(key));
            return output ;
        }
    }

我的问题是获取方法。我不断收到此错误

无法创建类型为"系统对象"的常量值。只 在此上下文中支持基元类型或枚举类型。

我尝试使用 ==,但它不会编译并说

不能将 == 应用于操作数 TKey 和 TKey

为什么这不起作用? 我的 TKey 应该是一种原始数据类型,TKey:struct 的限制器不是正确的吗?

为什么编译器使用Equals(object(,而有Equals(int(,这就是这个键是什么?

对 EF 的泛型参数使用 Equals 时出错

==比较失败,因为该运算符只能用于预定义的值类型或引用类型,而您的TKey两者都不是。

您在评论中说TKeyint.在您的情况下可能是正确的,但是您的类的用户可以定义一个Entity<List<string>.Enumerator>,因为List<T>.Enumerator是一个struct。在这种情况下,"等于"的含义令人难以置信。

我的观点是,编译器在编译时无法知道除了使用object.Equals之外如何做任何事情。

我想知道你为什么要限制密钥类型为struct。我见过的最常见的ID类型是intstring。通过使用struct,您已经排除了string...

您真的需要灵活性来支持非整数键吗?如果没有,您的课程可能会简单得多。


更新:您可以约束您的TKey,以便它实现IComparable,因为所有数值类型都实现了这一点。然后,这将允许您在Get方法的实现中使用CompareTo

但是,由于您传递给FirstOrDefault的 lambda 实际上将在数据库端执行,因此我不确定会发生什么,即 EF 是否能够将其正确转换为 SQL 表达式。

public abstract class Entity<T> : IEntity<T>, IAuditableEntity,ISoftDeletable where T : struct, IComparable
public abstract class Repository<TEntity,TKey> : IRepository<TEntity, TKey> where TEntity :Entity<TKey> where TKey : struct, IComparable

您可以简单地使用 IDbSet.Find 方法,该方法采用一个或多个 object 类型的键值。

public TEntity Get(TKey key)
{               
    return Set.Find(key);
}

这还有一个额外的好处,即如果实体已经存在于DbContext的本地缓存中,则效率更高(因为它避免了不必要的数据库旅行(。

但是,我怀疑您想要做的不仅仅是检索单个项目,因此您以后可能会遇到同样的问题。