首页 新闻 会员 周边 捐助

项目中使用EF,遇到导航属性的逻辑问题,不知道该怎么解决

0
悬赏园豆:60 [待解决问题]

项目使用EF的Code first作为ORM框架。

情况是这样的,我给所有的实体都定义了IsDelete属性指示是否被删除,也就是说数据库中不会有数据真正被删除,都是修改isdelete属性。这样做是为了万一数据被误删后可以使用sql语句恢复。也为实现回收站功能提供了可能。

在仓储中,我可以在查找时仅找出isdelete属性为false的数据,这没有什么问题。

但问题是EF自带的延迟加载和动态代理,它们在加载导航属性时是全部加载的,也就是不会理会我写的isdelete属性,这样会带来很严重的逻辑问题。我目前没有很好的办法解决它,下面是我的解决方案:

方案1:在实体类导航属性的访问器中写过滤代码,但实体类是不应该关心这种工作的,这是仓储实现关心的事情,并且这样做代码量不少并且重复。

方案2:将对isdelete的判断写在业务逻辑层,没有比这更恐怖的事了,少写一个就是藏的很深的BUG,多写一个就多一个重复代码。

方案3:禁用EF的代理和延迟加载,这样的话实体类中的导航属性纯属鸡肋,变成了花瓶。

方案4:更改代理的运作方式,在其读取导航属性时进行筛选。这可能是最好的办法了,但我不知道该怎么做。

请问有没有更好的办法?如果没有,方案4该如何实现?

陌客的主页 陌客 | 初学一级 | 园豆:52
提问于:2015-03-31 23:34
< >
分享
所有回答(4)
0

我也在为这个问题发愁。

解决的办法,既治标又治本的当然是你的方案四,只是这个方案~~~需要对EF很熟悉,目前我还没这么熟悉。正在研究ing

519740105 | 园豆:5810 (大侠五级) | 2015-04-01 09:17

等有了进展互相通知下,谢谢

支持(0) 反对(0) 陌客 | 园豆:52 (初学一级) | 2015-04-01 16:30

@外法猎人: 应该的。

支持(0) 反对(0) 519740105 | 园豆:5810 (大侠五级) | 2015-04-01 16:36

@519740105: 一直没有解决,我现在使用方案1,自定义一个代码段解决,妥协的方案。

支持(0) 反对(0) 陌客 | 园豆:52 (初学一级) | 2015-04-04 13:47

@外法猎人: 这几天在学习ASPNET5。

支持(0) 反对(0) 519740105 | 园豆:5810 (大侠五级) | 2015-04-04 14:47
0

导航属性的延迟加载一不小心就会成为性能杀手,建议不用导航属性的延迟加载。需要加载导航属性时,在LINQ查询时进行Include。

dudu | 园豆:30778 (高人七级) | 2015-04-01 09:53

谢谢,但include依然无法解决我遇到的问题

支持(0) 反对(0) 陌客 | 园豆:52 (初学一级) | 2015-04-01 16:30
0
//查询的时候的处理
public IQueryable<TEntity> Get(System.Linq.Expressions.Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "", bool dataHasDel = false)
        {
            IQueryable<TEntity> query = dbSet;

            if (dataHasDel == false)
            {
                if (filter != null)
                {
                    query = query.Where(filter).Where(p => p.IsDel == false);
                }
                else
                {
                    query = query.Where(p => p.IsDel == false);
                }
            }
            else
            {
                query = query.Where(filter);
            }

            foreach (var includeProperty in includeProperties.Split
                (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                query = query.Include(includeProperty);
            }

            if (orderBy != null)
            {
                return orderBy(query).AsNoTracking();
            }
            else
            {
                return query.AsNoTracking();
            }
        }

首先请废弃include include 会打破原子性

 /// <summary>
        /// 删除
        /// </summary>
        /// <param name="entityToDelete"></param>
        public virtual void Delete(TEntity entityToDelete)
        {
            GLRISCRM.Entity.IDelable iDelable = entityToDelete as GLRISCRM.Entity.IDelable;
            GLRISCRM.Entity.ILogicDelable iLogicDelable = entityToDelete as GLRISCRM.Entity.ILogicDelable;
            // 删除没启用
            if (iDelable != null && iDelable.EnableDel == false)
            {
                throw (new Exception("当前数据不可删除!"));
            }
            // 逻辑删除
            if (iLogicDelable != null)
            {
                iLogicDelable.IsDel = true;
                _Update(entityToDelete);
                return;
            }
            // 物理删除
            if (context.Entry(entityToDelete).State == EntityState.Detached)
            {
                dbSet.Attach(entityToDelete);
            }
            dbSet.Remove(entityToDelete);
        }
小眼睛老鼠 | 园豆:2731 (老鸟四级) | 2015-04-07 18:01

但代理类对导航属性的延迟加载似乎无法在这里控制。

还是非常感谢,仓储写的很好。

支持(0) 反对(0) 陌客 | 园豆:52 (初学一级) | 2015-04-07 20:59

@外法猎人: 

我都说了 请废弃食用include 也就是说废弃 导航属性的外键关联

我的项目 查询只有2种情况

一种就是单表 一种就是多表

单表就是我上面写的

多表就是sql语句 说实话 多表的情况 ef 并没有优势

支持(0) 反对(0) 小眼睛老鼠 | 园豆:2731 (老鸟四级) | 2015-04-07 23:06
0

var orders = _dbContext.SalesOrders.Where(a => a.Id == 888).select(a => new {SalesOrder = a, SalesOrderItems = a.OrderItems.Where(b => b.IsDeleted == null || b.IsDeleted == false)}).ToList();

irocker | 园豆:274 (菜鸟二级) | 2015-04-24 14:31
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册