【问题标题】:Is it acceptable to use UnitOfWork from inside an entity从实体内部使用 UnitOfWork 是否可以接受
【发布时间】:2014-01-12 01:01:31
【问题描述】:

我一直在自己从头开始开发一个ASP.NET MVC4 项目,并为我的数据访问层使用单独的项目。我正在使用Entity Framework 5Code First 工作流,并且我已经实现了我认为非常标准的Repository pattern 加上Uint Of Work 将数据层与业务逻辑分开。

一切都按预期进行,我已经有很多业务逻辑,但我没有太多经验(总共大约 9 个月),现在一位非常有经验的开发人员正在加入该项目,突然我开始了解这个错误:

无法定义两个对象之间的关系,因为 它们附加到不同的 ObjectContext 对象。

我的项目结构是这样的-

只是我的UnitOfWork 课程的一部分:

 public class UnitOfWork : IDisposable
{
    private MyDbContext context = new MyDbContext ();

    private MenuRepository мenuRepository;
    public MenuRepository MenuRepository
    {
        get
        {
            if (this.мenuRepository == null)
                this.мenuRepository = new MenuRepository(context);
            return мenuRepository;
        }
    }

    //register other repositories...
}

我的存储库具有标准外观:

 public class MenuRepository : GenericRepository<Menu>, IMenuRepository
 {
     public MenuRepository(MyDbContext context) : base(context) { }
 }

我知道这不足以判断实施是否足够好,但它运行了几个月而没有发现任何问题。今天我正在实现一个用子菜单编辑菜单的逻辑:

Menu menu = unitOfWork.MenuRepository.GetById(model.MenuID);
    long menuItemId = menu.MenuItems[0].MenuItemID;
    if (menu != null)
    {
      menu.Name = model.MenuName;
      MenuItem menuItem = unitOfWork.MenuItemRepository.GetById(menuItemId);
      menuItem.Name = "Test";

      unitOfWork.MenuRepository.Update(menu);

      return View(model);
    }

这一切都发生在我的控制器中:

private UnitOfWork unitOfWork = new UnitOfWork();

因此,当我尝试执行此代码时,我从上面得到了 ..attached to different ObjectContext objects. 的错误。

在代码开始崩溃之前我注意到的唯一变化是从其他人直接添加到 Menu 实体中:

//private DAL.UnitOfWork.UnitOfWork unitOfWork = new DAL.UnitOfWork.UnitOfWork();
    public Menu()
    {
        MenuItems = new List<MenuItem>();
    }

    public int MenuID { get; set; }
    //private int menuId;
    //public int MenuID {
    //    get
    //    {
    //        return menuId;
    //    }
    //    set
    //    {
    //        menuId = value;
    //        if (MenuItems.Count == 0)
    //        {
    //            MenuItems = unitOfWork.MenuItemRepository.GetBy(x => x.MenuID == menuId).ToList();
    //        }
    //    }
    //}

在我评论了上面的所有内容并将其返回给public int MenuID { get; set; } 之后,没有附加逻辑,删除数据库并重新创建它,我能够继续从控制器中使用我的Update 逻辑,而不会出现其他对象的错误上下文。

所以我的问题是 - 直接从完全可以接受的实体中使用UnitOfWork。我已经实现了Data Access Layer,但我使用了来自不同文章的大量信息,我不能说我完全理解这一切背后的原因。但是在我看来,以这种方式使用它不仅会导致代码崩溃,而且与使用 RepositoriesUnitOfWork 管理数据的整个想法背道而驰。另一方面,添加此代码的人有超过 10 年的编程经验,所以我不能只告诉他必须更改他的代码。那么实际上是否可以像上面的示例一样从实体本身内部使用unitOfWork,如果确实如此,那么我该如何解决使用不同对象上下文的错误?

【问题讨论】:

标签: c# design-patterns ef-code-first entity-framework-5 unit-of-work


【解决方案1】:

在我看来(这不一定有效,我几乎没有 ASP 经验),在这种情况下,实体绝对不应该使用 UnitOfWork,甚至不应该意识到它。

如果您已经配置了实体框架正在管理的 Menu 实体,并且您已经设置了多个现有存储库来进一步抽象和管理您的数据库交互,那么污染您的模型是没有意义的。

我假设出现错误是因为其他开发人员在模型中定义的新UnitOfWork 是一个新上下文,并且Menu 实体已经从另一个上下文(您的MenuRepository)获得,你已经想通了。

在设置 MenuID 时,如果 Menu 实体中不存在任何内容,则其他开发人员似乎正在尝试加载子 MenuItems。我并不完全清楚那里发生了什么,似乎他们希望该项目的 ID 发生变化,然后想要使用新 ID 获得属于 MenuMenuItems(我不是确定您为什么要更改 ID)。

MenuItem 加载应该可以在检索实体时进行,或者之后取决于实体的映射/配置方式,使用 LazyEagerExplicit 加载。

当然值得与其他开发人员交谈并了解他们想要实现的目标,不要担心某人拥有(或说他们拥有)的经验,其中许多概念对他们来说可能是新的同样,或者他们可能一直在强化坏习惯,优秀的程序员应该总是愿意就各种方法进行讨论。

关于加载的一些额外信息:http://msdn.microsoft.com/en-us/data/jj574232.aspx

【讨论】:

  • @Christ 我也不清楚。导航属性已设置并且延迟加载正在按其描述的那样工作,所以我真的不知道通过这样填充属性可以实现什么,但正如我所说,我远不是我希望的专家把它变成一个双赢的局面,我要么学习一些关于如何使用这种模式的新东西,要么能够捍卫你似乎分享的观点,UOW 不应该以这种方式使用。感谢您的回答。
  • @Leron 我也不是专家 =D 似乎另一个开发人员是 Menu 实体,可能会被重新分配以代表不同的 Menu 实体,并且想要以确保如果发生这种情况,加载正确的孩子。对于您的设计(存储库和 uow 模式),不需要这样做。绝对值得讨论。希望更多的答案能产生一些意见。
猜你喜欢
  • 2013-10-27
  • 1970-01-01
  • 1970-01-01
  • 2011-07-30
  • 2017-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多