如何使用通用属性类型查询EntityFramework?

3
当我调用DbSet.FirstOrDefault()并传递一个比较泛型类型TId的谓词时,我会收到以下异常:

无法创建类型为'system.object'的常量值。在此上下文中,只支持原始类型或枚举类型。

被查询类型的接口:
interface IEntity<TId>
{
    TId id { get; set; }
}

异常在这里抛出:

public virtual TEntity Get<TEntity, TId>(TId id) where TEntity : class, IEntity<TId>
{
    return dbContext.Set<TEntity>().FirstOrDefault(e => e.Id.Equals(id));
}

只有当TId被限制为struct时,该函数才能正常工作。如何将string包含在支持的类型中?如果不可能,是否可以用其他方法完成任务?

2个回答

2
这也适用于字符串:
public virtual TEntity Get<TEntity, TId>(TId id) 
    where TEntity : class, IEntity<TId>
    where TId: IEquatable<TId>
{
    return dbContext.Set<TEntity>().FirstOrDefault(e => e.Id.Equals(id));
}

我该如何扩展它以使其也适用于这些基元类型的数组?例如:int[]和string[]。谢谢。 - user845279
我认为你做不到。对于集合的相等性(关系型数据库没有数组的概念)太过广泛,SQL 中也没有直接的 == 类似的支持。例如考虑 [1,2][2,1]。它们对你来说是相等的吗?顺序重要吗?再比如 [null, 1][null,1]?你在这里是否关心三值逻辑等等。 - UserControl
我正在使用 MS Sql,它有 Binary[] 类型。它被转换为 System.Byte[]。 - user845279

2
您可以简单地使用Find方法:
public virtual TEntity Get<TEntity, TId>(TId id) where TEntity : class, IEntity<TId>
{
    return dbContext.Set<TEntity>().Find(id);
}

我尝试过这个方法,它对于单一主键的情况可行,但对于复合主键则会失败。 - user845279
很奇怪,你是怎么尝试的?使用了 dbContext.Set<TEntity>().Find(id1, id2); 吗? - Slava Utesinov
就像您在帖子中提到的那样。只是,使用Find(),您无法选择仅使用其中一个键。 - user845279

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接