【问题标题】:Thoughts on Updating Disconnected Entity Graph关于更新断开实体图的思考
【发布时间】:2014-02-07 14:58:50
【问题描述】:

我正在尝试设置一个项目以使用断开连接的实体并将我的 DbContext 封装在“存储库”类中。每个断开连接的实体都有一个本地属性来远程跟踪它们的状态,并在传入时由存储库解析以相应地设置 EntityState 属性。

我的问题是关于更新对象图中的子对象。我应该使用接受经常更新实体的更新方法来设置存储库,还是应该在对象图中为父对象设置一个更新方法并附加/更新它。

举例

public class Company {
   public int CompanyId { get; set; }
   public string CompanyName { get; set; }
   public ICollection<Department> { get; set; }
   public LocalEntityState LocalEntityState { get; set; }  // Enum for tracking disconnected changes 
}

public class Department {
   public int DepartmentId { get; set; }
   public int CompanyId { get; set; }
   public string DepartmentName { get; set; }
   public Company Company { get; set; }
   public ICollection<Employee> Employees { get; set; }
   public LocalEntityState LocalEntityState { get; set; }  
}

public class Employee {
   public int EmployeeId { get; set; }
   public int DepartmentId { get; set; }
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public Department Department { get; set; }
   public LocalEntityState LocalEntityState { get; set; }  
}

如果我使用单一方法来更新处于插入/更新状态的实体的整个对象图,我可以使用类似于以下界面的内容。不过需要注意的是,如果我要更新员工信息,我需要始终加载公司和部门的实例。

public interface ICompanyRepository {
   void InsertOrUpdate(Company company)

   // Other methods for deletion, retrieval, etc..
}

或者我可以使用类似的方法,为在 DbContext 中更改的“主要”对象提供方法。这样,如果我想编辑/插入它们,我只需要在内存中有一个 Employee 实例。

public interface ICompanyRepository {
   void InsertOrUpdate(Company company);
   void InsertOrUpdate(Department department);
   void InsertOrUpdate(Employee employee);
}

我只是想听听其他人对此的看法,以及避免一些常见陷阱的最佳途径是什么。对于我的实际项目,我尝试将较大的 DbContext 拆分为“有界上下文”的较小子集(来自 Julie Lerman 的“企业中的实体框架”),以便每个存储库都可以使用一组相关实体。但我不确定更新这些实体的最佳方法。谢谢你的帮助。

【问题讨论】:

    标签: c# entity-framework domain-driven-design repository-pattern


    【解决方案1】:

    在我看来,处理对象图不是存储库的责任。这是一个类似工作的对象的单位。

    根据Fowler的存储库

    使用类集合接口访问域对象,在域和数据映射层之间进行调解。

    这些词类似集合的界面是至关重要的。您以对象集合的形式访问存储库。所以它有简单的方法来获取和添加对象,就是这样。过去,我没有很好地区分存储库和服务,所以我总是在职责上挣扎。现在我很清楚服务(域服务)处理用例和存储库仅以可预测的通用方式交换数据。另一方面,服务可以公开代表业务流程的各种非常不同的方法。

    存储库不实现业务逻辑。所以OrderRepository 没有像GetOpenOrders 这样的方法,因为它没有任何“开放”的概念。同样,它没有处理对象图的方法,因为对象之间的关联也是业务概念。 (我的意思是,他们的签名中没有方法接受或返回代表集合的对象以外的对象。他们可能返回包含其他对象的对象,但这不是他们的责任)。

    说实话,直到我熟悉了 linq-to sql 和后来的 Entity Framework,我才完全掌握这些概念。这些 ORM 都提供了通用存储库模式的完美实现,L2S 中的 Table&lt;T&gt; 和 EF 中的 DbSet&lt;T&gt;(或有些过时的 ObjectSet)。当我意识到这些存储库不保存数据时,我感到非常惊讶。

    但是等等,他们应该“在域和数据之间进行调解”,不是吗?实际上,不,他们没有。 Fowler 说“在域和数据映射层之间”。啊。这是一个很大的区别。数据映射层是在数据存储之间进行实际数据传输的层。

    所以存储库可以有SaveUpdate 之类的方法,但是这些方法除了告诉映射层一个对象应该被标记为新的或更新的之外什么都不做。他们将对象添加到某些上下文中,当存储库早已消失时,这些上下文可能(或可能不)将对象保存到数据存储中。在 NHibernate 中,这个上下文是 Session,在 EF 中是 DbContext

    Soo...长话短说。您的第一个实现(仅 InsertOrUpdate Company)可以是存储库,第二个不是。

    存储对象图是一项服务方法任务,可能涉及多个存储库,并且通常涉及一个上下文或工作单元。之前已经说过,DbSet 是一个存储库实现,DbContext 是一个工作单元。您可能会决定在这些之上添加额外的存储库/UoW 层甚至是不必要的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-12
      • 2010-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多