对 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(,这就是这个键是什么?
==
比较失败,因为该运算符只能用于预定义的值类型或引用类型,而您的TKey
两者都不是。
您在评论中说TKey
是int
.在您的情况下可能是正确的,但是您的类的用户可以定义一个Entity<List<string>.Enumerator>
,因为List<T>.Enumerator
是一个struct
。在这种情况下,"等于"的含义令人难以置信。
我的观点是,编译器在编译时无法知道除了使用object.Equals
之外如何做任何事情。
我想知道你为什么要限制密钥类型为struct
。我见过的最常见的ID类型是int
和string
。通过使用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
的本地缓存中,则效率更高(因为它避免了不必要的数据库旅行(。
但是,我怀疑您想要做的不仅仅是检索单个项目,因此您以后可能会遇到同样的问题。