首页 新闻 会员 周边

关于IQueryable的lamada表达式中使用泛型的问题

0
悬赏园豆:10 [已解决问题] 解决于 2014-03-17 15:52

最近用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表达式转化。
不过现在只是猜想,无从下手,还请高手指点一下,多谢。
shen110的主页 shen110 | 初学一级 | 园豆:158
提问于:2014-03-16 23:25
< >
分享
最佳答案
0

EF 不是有 专门的 通过Key查找吗,为啥 要通过FindAll来查找一条?

EF中的  Find(params object[] keyValues), object类型,不用担心id类型

收获园豆:10
Qlin | 老鸟四级 |园豆:2403 | 2014-03-17 09:00

Find这个我去试一下,泛型类型能自动转成Object吧,先多谢了。

shen110 | 园豆:158 (初学一级) | 2014-03-17 13:06

@shen110: 这个方案可行,多谢了,十分感谢。

shen110 | 园豆:158 (初学一级) | 2014-03-17 15:52
其他回答(1)
0

CommonService<user,dynamic>,我这么干的,可以用了。

happydaily | 园豆:301 (菜鸟二级) | 2014-03-17 08:47

dynamic这个好用,不过在泛型结构中,这种类型的约束性是不是不会太好,不像泛型类型,你可以支持where 约束。当然如果不做过多约束应该是OK。多谢建议

支持(0) 反对(0) shen110 | 园豆:158 (初学一级) | 2014-03-17 13:04

@shen110: 约束你还是约束,实例化时用Dynamic

支持(0) 反对(0) happydaily | 园豆:301 (菜鸟二级) | 2014-03-17 14:32
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册