c# - 关于更新断开实体图的思考

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

我正在尝试设置一个项目以使用断开连接的实体并将我的 DbContext 封装在“Repository”类中。每个断开连接的实体都有一个本地属性来远程跟踪其状态,并在传入该实体时由存储库进行解析以相应地设置 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; }  
}

如果我使用单一方法来更新处于插入/更新状态的实体的整个对象图,我可以使用类似以下接口(interface)的方法。但需要注意的是,如果我要对员工进行更新,我需要始终加载公司和部门的实例。

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 的“企业中的 Entity Framework ”),以便每个存储库都将使用一组相关实体。但我不确定更新这些实体的最佳方法。谢谢您的帮助。

最佳答案

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

根据 Fowler 的存储库

Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.

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

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

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

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

因此存储库可以具有类似 Save 的方法,或Update ,但这些只是告诉映射层一个对象应该被标记为新的或更新的。他们将对象添加到某个上下文中,当存储库早已消失时,这些上下文可能(也可能不会)将对象保存到数据存储中。在 NHibernate 中,这个上下文是 Session ,在 EF 中是 DbContext .

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

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

关于c# - 关于更新断开实体图的思考,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21630915/

相关文章:

c# - 输入命令 `dotnet run` 时浏览器返回错误 404

c# - 尝试返回 json 并填充选择列表

c# - 错误 : No Entity Framework provider found for the ADO. 具有不变名称 'System.Data.SqlClient' 的 NET 提供程序

node.js - 如何在Node JS中构建CQRS/事件源应用程序?

entity - DDD 聚合 : Entity holding identifier to Non-Root Entity in another Aggregate

c# - 如何从项目路径获取 WinRT 中的文件?

C# Double.ToString() 错误结果

sql-server - 在 EF6 中创建具有主键和身份列的实体

sql - 如何实现一个 "Is Current"需求的一对多关系

.net - 如何实现DDD存储库以处理具有多个实体的查询?