繁体   English   中英

EF6-如何针对特定示例以优化的方式加载实体?

[英]EF6 - How to load entities in an optimized way for particular example?

我有Users - Rules具有many-to-many关系的Users - Rules表。 我想删除某个用户的某些规则,并在同一步骤/数据库事务中更新该用户的一个字段,因此我在BL中具有以下伪代码:

this.UnitOfWork.ExecuteTransaction(() =>
{
   // delete rules
   foreach (var rule in ruleList)
       repoRules.DeleteRulesForUser(user, rule);

   // update user field
   repoUser.UpdateUserField(user);
}

在EF资料库中:

public void DeleteRulesForUser(User user, Rule rule)
{
   // check user
   EFUser u = this.dbContext.EFUsers.Find(user.UID);
   if (u == null)
      throw new DBModuleException();

   // check rule
   EFRule r = this.dbContext.EFRules.Find(rule.UID);
   if (r == null)
      throw new DBModuleException();


   // detach previous entities, so that we can attach with relation 
   this.dbContext.ObjectContext.Detach(u);
   this.dbContext.ObjectContext.Detach(r);

   // prepare entities
   var efUser = new EFUser { US_UID = user.UID };
   var efRule = new EFRule { RU_UID = rule.UID };
   efRule.Users.Add(efUser);

   // attach
   this.dbContext.EFRules.Attach(efRule);

   // delete relation
   efRule.Users.Remove(efUser);
}

public void UpdateUserField(User user)
{
    // get updating user
    EFUser efUser = this.dbContext.EFUsers.FirstOrDefault(u => u.UID == user.UID);
    if (efUser == null)
       throw new DBModuleException("Not found!");

    // perform update
    efUser.US_Field = user.Field;
}

我的UnitOfWork实现(仅适用于EF6或更高版本):

public override void ExecuteTransaction(Action transAction)
{
    // make sure to make IsolationLevel flexible later
    using (var dbTransaction = this.dbContext.Database
                              .BeginTransaction(IsolationLevel.ReadCommitted)) 
    {
       try
       {
           transAction();

           // save changes if not done yet
           this.dbContext.SaveChanges();

           // commit transaction
           dbTransaction.Commit();
       }
       catch (System.Data.DataException ex)
       {
           // rollback
           dbTransaction.Rollback();

           // handling exception ceremony comes here
       }
    }

我的问题是DeleteRulesForUser仅向该用户附加UID(如方法中所指定),但随后,在UpdateUserField EF仅向该用户提供UID,而不是因为FirstOrDefault调用数据库而为该用户提供完整的数据。 我假设这就是EF缓存的工作方式(?)。 无论如何,更新操作失败,我想学习如何最好地解决此问题。

我看到有必要有时仅用UID加载实体,而有时却用完整数据加载。

我本来打算在DeleteRulesForUser方法的末尾分离实体,但是由于在BL中有时存在for循环,因此我认为这样做对性能不好。 我还认为也许应该重写我的Update方法,但是还不知道这样做的好方法。

你会推荐什么?

仅供参考:我已禁用LazyLoading。

注意 :BL不使用EF类,但使用专有的域类(后来增加了EF支持)。 不要批评现有的体系结构,我想要一个解决方案。

EDIT1:当我阅读更多内容时,也许AutoDetectChangesEnabled可能会有所帮助,但我需要更多信息来查找。

如果您需要删除成千上万条规则,我建议删除Entity Framework并使用ADO.NET和sql语句(或存储过程),这将更快,更简单。 请参阅批量更新/删除EF5

也没有理由附加或分离对象。 如果使用EF,请从需要的那一刻起创建一个上下文,并尽快对其进行处理。

没有理由将对象与对象状态管理器分离。 仅查看代码,对您要执行的操作并没有多大意义。 也许您没有使用EF的丰富经验,但是我建议您在使用EF之前先阅读一下它的工作原理

您可以简单地加载User实体并将规则包含在批处理操作的结果集中: var dbUser = ctx.Users.Include(x => x.Rules).FirstOrDefault(x => x.UID == user.UID);

现在,您已经拥有了完全填充的用户对象以及与之关联的所有规则,您可以找到要删除的规则: var ruleToDelete = dbUser.Rules.FirstOrDefault(x => x.UID == rule.UID);

现在,您有了要删除的用户的规则,而无需花费您一次返回数据库的费用。 现在,您可以删除规则: ctx.Rules.Remove(ruleToDelete);

现在,当您调用ctx.SaveChanges() ,更改将被推回到数据库中。 您需要了解Entity Framework自动为您包装事务中的所有insertupdatedelete语句。 另外,EF不支持批量insertupdatedelete操作。

//Get the user from the db, should check for null after this
var dbUser = ctx.Users.Include(x => x.Rules).FirstOrDefault(x => x.UID == user.UID);

//Get the rule from the user object you want to remove
var ruleToDelete = dbUser.Rules.FirstOrDefault(x => x.UID == rule.UID);

//Set the state of the object to "Deleted" in the state manager so it will issue a delete statement
ctx.Rules.Remove(ruleToDelete);

//Save the changes to the database in a transaction
ctx.SaveChanges()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM