最近用Entity Framework设计一个系统,遇到一个设计的问题。
先贴代码:
public class CommonService<TEntity, TID> : ICommonService<TEntity, TID> where TEntity : IEntity<TID> { private IRepository<TEntity> CommonRepository { get; set; } public IEnumerable<TEntity> FindAll() { return CommonRepository.FindAll(); } public TEntity FindByID(TID id) { return CommonRepository.FindAll().FirstOrDefault(c => c.ID.Equals(ConvertToTID(id.ToString()))); } public void Update(TEntity entity) { if (entity == null) { throw new ArgumentNullException("entity"); } CommonRepository.Update(entity); } public void Delete(TEntity entity) { if (entity == null) { throw new ArgumentNullException("entity"); } CommonRepository.Delete(entity); } public void Add(TEntity entity) { if (entity == null) { throw new ArgumentNullException("entity"); } CommonRepository.Add(entity); } #region Helper Method protected static TID ConvertToTID(string tidStr) { try { var tidType = typeof(TID); var converter = System.ComponentModel.TypeDescriptor.GetConverter(tidType); return (TID)converter.ConvertFromString(tidStr); } catch { } return default(TID); } #endregion }
我们看到这里我设计了一个通用的Service类来实现简单的增,删,查改操作。现在问题就出在
FindByID这个方法中,这里对ID的类型进行了约束,将其设置为泛型,可是我们看到里面的逻辑。
CommonRepository.FindAll()返回的是一个IEnumerable类型,我们知道如果这里不AsQueryable()的话,数据会立即进行查找,将数据缓存在系统的内存中,这样在性能方面会损失不少,所以我们这里应该用AsQuery()将其转成IQueryable类型,问题就来了,在IQueryable的where表达式中我们不知道TID具体类型,所以在表达这里就会出现异常,传统的写法
CommonRepository.FindAll().AsQueryable().Where(c => c.ID.Equals(id));
这样就会报一个异常:
无法将类型“*****”强制转换为类型“Drifter.Common.IEntity`1[[System.Int16, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]”。LINQ to Entities 仅支持强制转换 EDM 基元或枚举类型。
这个问题让我纠结了半天,我们知道IQueryable在进行执行的时候实际上是编译成sql script语句了,如果lamad表达式中出现sql 语句无法转换的方法,就会报这个类似的异常。
个人感觉是应该扩展一个IQueryable的方法,用实现自己的lamad表达式转化。
不过现在只是猜想,无从下手,还请高手指点一下,多谢。
EF 不是有 专门的 通过Key查找吗,为啥 要通过FindAll来查找一条?
EF中的 Find(params object[] keyValues), object类型,不用担心id类型
Find这个我去试一下,泛型类型能自动转成Object吧,先多谢了。
@shen110: 这个方案可行,多谢了,十分感谢。
CommonService<user,dynamic>,我这么干的,可以用了。
dynamic这个好用,不过在泛型结构中,这种类型的约束性是不是不会太好,不像泛型类型,你可以支持where 约束。当然如果不做过多约束应该是OK。多谢建议
@shen110: 约束你还是约束,实例化时用Dynamic