存储库模式以及如何管理实体之间的依赖关系

本文关键字:实体 管理 之间 关系 依赖 模式 何管理 存储 | 更新日期: 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的东西就留在DepartmentsEmployees仓库就不用关心其他实体了。

问题 :当工资发生变化时(如果有多个订阅者),可能很难(通过阅读代码或在调试模式下)跟踪会发生什么。如果需要按特定顺序调用订阅者,它也可能会成为一个问题。

存储库模式以及如何管理实体之间的依赖关系

您应该有在数据库中拥有计算字段的理由(性能?我尽量避免这种情况。

原因更新不是唯一的情况:如果您删除员工,您还必须重新计算。

但这可能是危险的(出于一个原因,您有一天使用数据库中的脚本工作,在更新员工的工资后忘记手动更新您的部门表?

所以

  • 您可以在数据库中创建一个触发器(如果您先有代码,则始终可以使用SMO保持"代码"逻辑)

  • 您可以创建数据库视图

  • 您可以在您的部门实体中拥有一个员工 ICollection(或 IList,或......),并获得总工资作为"简单获取财产",它汇总了列表的工资......

在你的情况下,是的,你违反了单一责任原则。

为尊重原则,本行

Departements.ReCalculateTotalSalaries(e.Department.Id);

应该是

e.Department.ReCalculateTotalSalaries();

为此,您必须在数据库和数据库架构中的两个实体之间使用关系。

编辑:请注意,ReCalculateTotalSalaries应该修改属性,但不应该将自己保存在数据库中。因此,由于它不接触数据库本身,因此应将其放置在您的部门实体中,而不是您的部门存储库中

编辑2:当您调用Employees.Update(yourEmployee)时,它还将保存您的员工部门。这就是它的魔力!无需为每个实体调用一个Update()

为什么不直接构造函数将另一个存储库注入(或其他类型)到员工存储库中?

public EmployeeRepository(DepartmentRepository department){}

。然后使用_department满足您的任何需求。这是一种干净的方式。您无法摆脱在代码中进行复杂交互的必然要求。

。或者使用一个"监督"存储库,将两者结合起来 - 并为两者注入了引用 - 并且先做员工的事情,然后调用另一个?也许这更像是你在想的。
主存储库(员工员工,部门部门)... 保存员工() { 先做员工,然后... 呼叫部门 }

希望这对一些有帮助。

编辑:我不会接受这些事件 - 至少对于存储库来说,有原因,但首先是它对 Db 以及数据在哪里感觉并不好。我不明白的第一个选项可能类似于我的主存储库。