Architecture s的视图模型表,可供管理层查看当前工资支出。这种轮询的频率取决于所需信息的频率。也许他们需要这些数据在一小时内有效,或者也许每天都是令人满意的

Architecture s的视图模型表,可供管理层查看当前工资支出。这种轮询的频率取决于所需信息的频率。也许他们需要这些数据在一小时内有效,或者也许每天都是令人满意的,architecture,domain-driven-design,cqrs,business-logic,Architecture,Domain Driven Design,Cqrs,Business Logic,同样,要有一个“潜在工资”表,但只要员工更新他们的时间表或员工的工资发生变化,该表就会更新。使用此选项,数据将保持接近实时 无论哪种方式,计算的聚合数据都使用域生成的数字,并且在查询之前完成,因此查询非常简单,最重要的是,非常快速 编辑2-仅作总结 在我看来,域应该负责进行计算,因此需要计算的结果才能做出决定。查询/读取端为了合计和聚合数据而进行计算是绝对正确的,只要这不是查询本身的一部分,请考虑报告本身可以是一个整体有界上下文。因此,它的体系结构可能与您为核心域选择的体系结构完全不同 也许CQ

同样,要有一个“潜在工资”表,但只要员工更新他们的时间表或员工的工资发生变化,该表就会更新。使用此选项,数据将保持接近实时

无论哪种方式,计算的聚合数据都使用域生成的数字,并且在查询之前完成,因此查询非常简单,最重要的是,非常快速

编辑2-仅作总结


在我看来,域应该负责进行计算,因此需要计算的结果才能做出决定。查询/读取端为了合计和聚合数据而进行计算是绝对正确的,只要这不是查询本身的一部分,请考虑报告本身可以是一个整体有界上下文。因此,它的体系结构可能与您为核心域选择的体系结构完全不同

也许CQRS很适合核心领域,但不适合报告领域。尤其是当您希望在生成报告之前根据不同的场景应用各种计算时。想想BI


请记住,CQR可能不应该应用于整个应用程序。一旦您的应用程序足够复杂,您就应该识别其有界上下文,并对每个上下文分别应用适当的体系结构模式,即使它们使用的是相同的数据源。

请考虑报告本身可以是一个整体有界上下文。因此,它的体系结构可能与您为核心域选择的体系结构完全不同

也许CQRS很适合核心领域,但不适合报告领域。尤其是当您希望在生成报告之前根据不同的场景应用各种计算时。想想BI


请记住,CQR可能不应该应用于整个应用程序。一旦您的应用程序足够复杂,您应该识别其有界上下文,并对每个上下文分别应用适当的体系结构模式,即使它们使用相同的数据源。

我的理解是,CQR与DDD相结合将生成一个查询端,该查询端在有界上下文中聚合数据,而命令端则严格根据该特定命令的有界上下文执行命令

这将使您的报告可以在需要时检索其数据

然后,您可以将一些ICalculator注入到读取端的查询处理程序中,以进行业务逻辑计算

例如:

公共类EmployeeQueryHandler:EmployeeIQueryHandler
{
专用只读INetWageCalculator\u calculator;
私人只读雇员储蓄库;
公共存储库(INetWageCalculator、IEmployeeRepository repo)
{
_计算器=计算器;
_回购=回购;
}
公共列表执行器()
{
var employees=_repo.GetEmployeeList();
foreach(员工中的var emp)
{
//你必须从某个地方获得税收,也许它是作为一种形式传入的
//一个参数。。。
emp.NetWages=_calculator.Calculate(emp.GrossWages,Tax);
}
返回员工;
}
}
公共类EmployeeRepository:IEEmployeeRepository
{
列表GetEmployeeList()
{
List empList=新列表;
string query=“选择EMP_名称,员工工资”;
...
..
while(reader.Read())
{
雇主。添加(
新EmployeeViewModel
{
EmpName=读卡器[“EMP_NAME”],
GrossWages=读卡器[“工资”],
//此行移动到查询处理程序。
//NetWages=reader[“saughts”]-(reader[“saughts”]*Tax)/100/*我们可以在这里调用函数,但由于我们不使用业务层,因此该函数将在DAL层中定义*/
}
);
}
}
}
这允许您使用相同的计算器服务在其他地方重用计算净工资的业务逻辑


为了演出,,如果不想在结果中循环两次,也可以将计算器注入存储库。

我的理解是,CQR与DDD相结合将生成一个查询端,该查询端在有界上下文中聚合数据,而命令端则严格按照该特定命令的有界上下文执行命令

这将使您的报告可以在需要时检索其数据

然后,您可以将一些ICalculator注入到读取端的查询处理程序中,以进行业务逻辑计算

例如:

公共类EmployeeQueryHandler:EmployeeIQueryHandler
{
专用只读INetWageCalculator\u calculator;
私人只读雇员储蓄库;
公共存储库(INetWageCalculator、IEmployeeRepository repo)
{
_计算器=计算器;
_回购=回购;
}
公共列表执行器()
{
var employees=_repo.GetEmployeeList();
foreach(员工中的var emp)
{
//你必须从某个地方获得税收,也许它是作为一种形式传入的
//一个参数。。。
emp.NetWages=_calculator.Calculate(emp.GrossWages,Tax);
}
返回员工;
}
}
公共类EmployeeRepository:IEEmployeeRepository
{
列表GetEmployeeList()
{
List empList=新列表;
s
public class EmployeeQueryHandler : EmployeeIQueryHandler
{
    private readonly INetWageCalculator _calculator;
    private readonly IEmployeeRepository _repo;

    public Repository(INetWageCalculator calculator, IEmployeeRepository repo)
    {
        _calculator = calculator;
        _repo = repo;
    }

    public List<EmployeeViewModel> ExecuteQuery()
    {
        var employees = _repo.GetEmployeeList();

        foreach(var emp in employees)
        {
            // You have to get tax from somewhere, perhaps its passed in as
            // a parameter...
            emp.NetWages = _calculator.Calculate(emp.GrossWages, Tax);
        }

        return employees;
    }
}


public class EmployeeRepository : IEmployeeRepository
{

    List<EmployeeViewModel> GetEmployeeList()
    {
        List<EmployeeViewModel> empList = new List<EmployeeViewModel>;
        string query = "SELECT EMP_NAME, WAGES FROM EMPLOYEE";      
        ...
        ..
        while (reader.Read())
        {
            empList.Add(
                new EmployeeViewModel
                {
                    EmpName = reader["EMP_NAME"],
                    GrossWages = reader["WAGES"],

                    // This line moves to the query handler.
                    //NetWages = reader["WAGES"] - (reader["WAGES"] * Tax) / 100 /*We could call a function here but since we are not using the business layer, the function will be defined in the DAL layer*/
                }
            );
        }
    }
}