我有一个我的应用程序访问的存储库层,可以用IDataSource
初始化;例如LinqToSqlDataSource,EntityFrameworkDataSource等......
IDataSource分别提供插入,更新,删除和查询数据源的方法。与此问题相关的是,FindAll<T>
会返回IQueryable<T>
。
我的所有基础实体都实现了一个简单的界面,可以通过id通用且方便地查找实体;
public interface IAmIdentifiable<T>
{
T Id { get; set; }
}
以下是我在EntityFramework中遇到问题的FindById<T, TKey>
方法的相关代码。
public class Repository
{
public Repository(IDataSource dataSource)
{...}
public T FindById<T, TKey>(TKey identifier) where T : class, IAmIdentifiable<TKey>
{
return _DataSource.FindAll<T>().SingleOrDefault(i => i.Id.Equals(identifier));
}
...
}
此FindById<T, Tkey>(...)
可与LinqToSql一起使用,但在EntityFramework 4 中不起作用。
使用示例
User user = Repository.FindById<User, int>(someUserId);
Message msg = Repository.FindById<Message, Guid>(someMessageId);
当上述代码与EntityFramework 4 IDataSource实现一起运行时,会产生以下错误;
无法创建“System.Object”类型的常量值。在此上下文中仅支持原始类型(例如Int32,String和Guid')。
我尝试更改此项以对值类型执行==比较。我读到一种将泛型约束为值类型的迂回方法是约束struct
。我相应地更新了所有实体和存储库查找器的基本接口......
public interface IAmIdentifiable<T> where T : struct
{
T Id { get; set; }
}
public T FindById<T, TKey>(TKey identifier)
where T : class, IAmIdentifiable<TKey>
where TKey : struct
{
return _DataSource.FindAll<T>().SingleOrDefault(i => i.Id == identifier);
}
但是,这仍然会导致编译错误;
错误59运算符'=='无法应用于'TKey'和'TKey'类型的操作数
任何人都可以了解我如何将这些实体转换为IAmIdentifiable<T>
接口,以便通过Id获得检索实体的通用方法吗?
答案 0 :(得分:0)
我认为那里的错误在于你试图比较TKey泛型的方式。由于TKey是一种复杂类型,因此必须明确实现==运算符才能进行此比较。现在使用TKey泛型,不能保证它是。也许你可以在TKey上放置另一个通用约束来确保有比较方法可用吗?
答案 1 :(得分:0)
不要问我为什么会这样,但我们设法通过这样做来实现:
i => (object)i.Id == (object)identifier
不知何故,这表现得很好,并编写了正确的SQL WHERE
子句。我们尝试的所有其他替代方案都不起作用。