如何编写包含多个实体的 ASP.NET MVC 存储库接口?
问题:
我是存储库模式的新手,我正在尝试使用它来实现新的 ASP.NET MVC 应用程序。在实现“包含”/代表多个实体的存储库时,我有些困惑。我看到它指出,不应为每个实体拥有一个存储库,而应为每个聚合根拥有一个存储库。
如果我的聚合包含多个实体(或物理模型中的表),则该聚合的基本 ASP.NET MVC 存储库会是什么样子?
示例:
如果有一个具体的示例可以帮助您,假设我们有一个包含聚合的应用程序,Employees。员工聚合包含三个实体,由数据库中的三个表表示:员工、员工类型和就业状态。
Employee
========
EmployeeID (PK)
EmployeeFullName
EmployeeTypeCode (FK)
EmployeeTypes
=============
EmployeeTypeCode (PK)
EmployeeTypeCodeDescription
EmploymentStatus
================
EmployeeID (PK)
EmploymentStatusCode (PK)
EmploymentStatusStartDate (PK)
EmploymentStatusEndDate
这种结构允许我们拥有员工,定义他们是什么类型的员工,并拥有状态记录(受雇于一个职位、晋升到另一个职位、解雇、重新雇用等)。实际上,结构看起来与此不同,但我们以它为例。
一个实体的不完整存储库(此示例基于 Steven Sanderson 在 Pro ASP.NET MVC 2 Framework 中给出的存储库),该存储库将为我们提供一份员工列表并允许我们保存员工是这个接口:
public interface IEmployeesRepository
{
IQueryable<Employee> Employees { get; }
void SaveEmployee(Employee employee);
}
以及这个实现(在本例中使用 Linq to SQL;它可以是 NHibernate 或 Entity Framework):
using System;
using System.Data.Linq;
using System.Linq;
using MyApp.Domain.Abstract;
using MyApp.Domain.Entities;
namespace MyApp.Domain.Concrete
{
public class SqlEmployeesRepository : IEmployeesRepository
{
private Table<Employee> employeesTable;
public SqlEmployeesRepository(string connectionString)
{
employeesTable = (new DataContext(connectionString)).GetTable<Employee>();
}
public IQueryable<Employee> Employees
{
get { return employeesTable; }
}
public void SaveEmployee(Employee employee)
{
if (employee.EmployeeID == 0)
employeesTable.InsertOnSubmit(employee);
else if (employeesTable.GetOriginalEntityState(employee) == null)
{
employeesTable.Attach(employee);
employeesTable.Context.Refresh(RefreshMode.KeepCurrentValues, employee);
}
employeesTable.Context.SubmitChanges();
}
}
}
Question:
I'm new to the repository pattern, and I'm attempting to implement a new ASP.NET MVC application using it. I have some confusion when it comes to implementing a repository that "contains" / represents multiple entities. I've seen it stated that one should not have one repository per entity but instead one repository per aggregate root.
If my aggregate contains multiple entities (or tables, in my physical model), what would a basic ASP.NET MVC repository look like for this aggregate?
Example:
If it helps to have a concrete example to work with, let's say we have an application containing an aggregate, Employees. The Employees aggregate contains three entities, represented by three tables in the DB - Employees, EmployeeTypes, and EmploymentStatus.
Employee
========
EmployeeID (PK)
EmployeeFullName
EmployeeTypeCode (FK)
EmployeeTypes
=============
EmployeeTypeCode (PK)
EmployeeTypeCodeDescription
EmploymentStatus
================
EmployeeID (PK)
EmploymentStatusCode (PK)
EmploymentStatusStartDate (PK)
EmploymentStatusEndDate
This structure allows us to have employees, define what type of employee they are, and have a record of status (hired in 1 position, promoted to another position, fired, re-hired, etc.). In reality the structure would look different than this, but let's use it as the example.
An incomplete repository (this example is based on one given in Pro ASP.NET MVC 2 Framework, by Steven Sanderson) for one entity that would give us a list of employees and allow us to save an employee could be this interface:
public interface IEmployeesRepository
{
IQueryable<Employee> Employees { get; }
void SaveEmployee(Employee employee);
}
And this implementation (in this case using Linq to SQL; it could be NHibernate or Entity Framework):
using System;
using System.Data.Linq;
using System.Linq;
using MyApp.Domain.Abstract;
using MyApp.Domain.Entities;
namespace MyApp.Domain.Concrete
{
public class SqlEmployeesRepository : IEmployeesRepository
{
private Table<Employee> employeesTable;
public SqlEmployeesRepository(string connectionString)
{
employeesTable = (new DataContext(connectionString)).GetTable<Employee>();
}
public IQueryable<Employee> Employees
{
get { return employeesTable; }
}
public void SaveEmployee(Employee employee)
{
if (employee.EmployeeID == 0)
employeesTable.InsertOnSubmit(employee);
else if (employeesTable.GetOriginalEntityState(employee) == null)
{
employeesTable.Attach(employee);
employeesTable.Context.Refresh(RefreshMode.KeepCurrentValues, employee);
}
employeesTable.Context.SubmitChanges();
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您的存储库看起来不应该有任何不同。它的接口根本不应该暴露您的聚合根具有任何特定子子实体的事实。显然,存储库的实现必须处理对这些子实体的更改,但是您的 Employee 存储库提供的接口应该与这些子实体没有任何关系。它们应该封装在聚合根内。
Your repository shouldn't look any different. It's interface should not at all expose the fact that your Aggregate Root has whatever particular child sub-entities. Obviously, the implementation of the repository will have to deal with changes to those child entities, but the interface your Employee repository presents should have nothing at all to do with those sub-entities. They should be encapsulated inside the Aggregate Root.