存储库模式以及如何管理实体之间的依赖关系
本文关键字:实体 管理 之间 关系 依赖 模式 何管理 存储 | 更新日期: 2023-09-27 18:30:43
假设我有一个包含员工和部门的数据库。我创建了一个简单的对象模型来处理这个问题:
class Employee
{
decimal Salary;
Department Department;
}
class Department
{
decimal TotalSalaries; //calculated as the sum of all employees salaries
//stored in database, not just a C# property
}
和。。
class Employees
{
void Create(Employee e);
void Update(Employee e);
void Delete(Employee e);
...
}
class Departments
{
...
}
如果我想更新员工,我只需执行以下操作:
Employee emp = Employees.GetById(1);
emp.Salary += 100; //salary increase
Employees.Update(emp);
我希望每次更新其中一名员工的Salary
时自动重新计算Department
TotalSalaries
我可以执行以下操作:
void Update(Employee e)
{
... //
... // sql stuff to update employee fields.
Departments.ReCalculateTotalSalaries(e.Department.Id);
}
但如果我这样做,我认为我违反了单一责任原则。 为什么员工更新方法应该关心Departments
?这是一个非常简单的示例,但是如果我在实体之间有很多依赖关系,代码可能会变得非常混乱。
我已经考虑了其他方法来做到这一点:
1)为员工创建一个服务类:EmployeeService
。然后在此类中,定义一个Update()
更新员工的方法。该方法将更新员工并重新计算部门总数(当然是通过调用存储库方法)。
void Update(Employee e)
{
Employees.Update(e);
Departments.ReCalculateTotalSalaries(e.Department.Id);
}
问题:如果我的数据模型中有很多依赖项,我几乎必须"加倍"我的模型层(类数 x2)。另外:我如何确保控制器(或视图)将始终调用服务方法,而不是直接调用存储库?
2)在仓库Employees
有一个事件OnSalaryChange()
,从Update()
方法调用。存储库Departments
将订阅它,并在需要时执行必要的操作(换句话说:调用ReCalculateTotalSalaries()
)。那么,属于Departments
的东西就留在Departments
,Employees
仓库就不用关心其他实体了。
问题 :当工资发生变化时(如果有多个订阅者),可能很难(通过阅读代码或在调试模式下)跟踪会发生什么。如果需要按特定顺序调用订阅者,它也可能会成为一个问题。
您应该有在数据库中拥有计算字段的理由(性能?我尽量避免这种情况。
原因更新不是唯一的情况:如果您删除员工,您还必须重新计算。
但这可能是危险的(出于一个原因,您有一天使用数据库中的脚本工作,在更新员工的工资后忘记手动更新您的部门表?
所以
-
您可以在数据库中创建一个触发器(如果您先有代码,则始终可以使用SMO保持"代码"逻辑)
-
您可以创建数据库视图
-
您可以在您的部门实体中拥有一个员工 ICollection(或 IList,或......),并获得总工资作为"简单获取财产",它汇总了列表的工资......
在你的情况下,是的,你违反了单一责任原则。
为尊重原则,本行
Departements.ReCalculateTotalSalaries(e.Department.Id);
应该是
e.Department.ReCalculateTotalSalaries();
为此,您必须在数据库和数据库架构中的两个实体之间使用关系。
编辑:请注意,ReCalculateTotalSalaries应该修改属性,但不应该将自己保存在数据库中。因此,由于它不接触数据库本身,因此应将其放置在您的部门实体中,而不是您的部门存储库中
编辑2:当您调用Employees.Update(yourEmployee)
时,它还将保存您的员工部门。这就是它的魔力!无需为每个实体调用一个Update()
!
为什么不直接构造函数将另一个存储库注入(或其他类型)到员工存储库中?
public EmployeeRepository(DepartmentRepository department){}
。然后使用_department满足您的任何需求。这是一种干净的方式。您无法摆脱在代码中进行复杂交互的必然要求。
。或者使用一个"监督"存储库,将两者结合起来 - 并为两者注入了引用 - 并且先做员工的事情,然后调用另一个?也许这更像是你在想的。
主存储库(员工员工,部门部门)... 保存员工() { 先做员工,然后... 呼叫部门 }
希望这对一些有帮助。
编辑:我不会接受这些事件 - 至少对于存储库来说,有原因,但首先是它对 Db 以及数据在哪里感觉并不好。我不明白的第一个选项可能类似于我的主存储库。