【问题标题】:Responsibility of Domain Object领域对象的责任
【发布时间】:2013-12-21 07:10:09
【问题描述】:

我有一个域,员工可以在其中拥有一个角色列表。还有一个新的角色添加功能。在添加新角色时,我们需要检查员工是否已经拥有“VP”角色。如果它已经存在,则不应添加新角色。此逻辑需要存在于 Employee Domain 实体中。

我通过添加一个方法名 IsNewRoleAllowed() 开始它,它将返回一个布尔值。如果为真,业务层会将新角色插入数据库。

但为了更自然OO,我决定通过创建一个函数AddRole 来更改Employee 对象的职责。它将执行添加职责的角色,而不是返回布尔值。

我通过接收Action<int, int> 作为参数实现了上述目标。它工作正常。

问题

将 DAL 方法传递给实体是正确的做法吗?

更新

@ThomasWeller 添加了我同意的重要观点...

  1. 拥有角色是 BL 的纯粹概念。它与 DAL 无关。

  2. 在这种方法中,BL 将依赖于驻留在 DAL 中的代码。当 DAL 甚至不存在时,它 (BL) 甚至应该可以工作。

但是,由于我没有使用 ORM,我将如何修改代码以按照建议的方法工作?

参考文献

  1. Grouping IDataRecord individual records to a collection

代码

域实体

public class Employee
{
    public int EmployeeID { get; set; }
    public string EmployeeName { get; set; }
    public List<Role> Roles { get; set; }

    //Add Role to Employee
    public int AddRole(Role role, Action<int, int> insertMethod)
    {
        if (!Roles.Any(r => r.RoleName == "VP"))
        {
            insertMethod(this.EmployeeID, role.RoleID);
            return 0;
        }
        else
        {
            return -101;
        }
    }


    //IDataRecord Provides access to the column values within each row for a DataReader
    //IDataRecord is implemented by .NET Framework data providers that access relational databases.

    //Factory Method
    public static Employee EmployeeFactory(IDataRecord record)
    {
        var employee = new Employee
        {
            EmployeeID = (int)record[0],
            EmployeeName = (string)record[1],
            Roles = new List<Role>()
        };

        employee.Roles.Add(new Role { RoleID = (int)record[2], RoleName = (string)record[3] });
        return employee;

    }
}

BusinessLayer.Manager

public class EmployeeBL
{
    public List<Employee> GetEmployeeList()
    {
        List<Employee> employees = EmployeeRepositoryDAL.GetEmployees();
        return employees;
    }

    public void AddRoleToEmployee(Employee emp, Role role)
    {
        //Don't trust the incoming Employee object. Use only id from it
        Employee employee = EmployeeRepositoryDAL.GetEmployeeByID(emp.EmployeeID);
        employee.AddRole<Employee>(role, EmployeeRepositoryDAL.InsertEmployeeRole);
        //EmployeeRepositoryDAL.InsertEmployeeRole(emp.EmployeeID, role.RoleID);
    }
}

DAL

    public static void InsertEmployeeRole(int empID, int roleID)
    {
        string commandText = @"INSERT INTO dbo.EmployeeRole VALUES (@empID, @roleID)";

        List<SqlParameter> commandParameters = new List<SqlParameter>()
                                                {
                                                    new SqlParameter {ParameterName = "@empID", 
                                                                      Value = empID, 
                                                                      SqlDbType = SqlDbType.Int},
                                                    new SqlParameter {ParameterName = "@roleID", 
                                                                      Value = roleID, 
                                                                      SqlDbType = SqlDbType.Int}
                                                };


        CommonDAL.ExecuteNonQuery(commandText, commandParameters);

    }

【问题讨论】:

  • 为什么你的AddRole 方法需要一个通用参数——你从不使用它。那又怎样?

标签: c# oop domain-driven-design


【解决方案1】:

没有。拥有一个角色首先是 BL 的一个纯粹概念,它与 DAL 无关。此外,在您的方法中,BL 将依赖于驻留在 DAL 中的代码,这将是错误的方向。 BL 应该是persistence agnostic(即它不应该以任何方式依赖于 DAL 中会发生的事情——它甚至应该在 DAL 甚至不实际存在时工作。)。此外,DAL 的职责只是 persist 对象 - 不处理驻留在内存中的任何集合。

尽量简单,然后做:

public int AddRole(Role role)
{
    if (!Roles.Any(r => r.RoleName == "VP"))
    {
        Roles.Add(role.RoleName);
        return 0;
    }
    else
    {
        return -101;
    }
}

...在您的Employee 课程中,让 DAL 处理所有与持久性相关的问题(如果您使用 ORM,它无论如何都会进行级联更新)。

【讨论】:

  • 我完全同意你的观点-Having a role is a pure concept of the BL. It has nothing to do with the DAL. In your approach, the BL would have a dependency of code that resides in the DAL. It (BL) even should work when a DAL does not even physically exist. 但是由于我没有使用ORM,我该如何修改代码才能像这样工作?
  • 因此,如果您不使用 ORM,则必须手动跟踪所有修改。你确定要这样做吗?
  • 我也觉得没有 ORM 去实现这个目标是不切实际的......因为我不去 ORM 我将不得不远离实现这些目标.. 我的代码不会可测试.. 但我觉得我目前的方法很好地将业务逻辑包含在实体中
【解决方案2】:

将 DAL 方法传递给实体是正确的做法吗?

我避免将 DAL 逻辑注入到我的域模型中。

一旦域实体(例如Employee)更新,就不需要更新数据库。

常见的解决办法是:

  1. 将要更新的实体从数据库加载到内存中(Identity Map,PoEAA)。
  2. 在内存中创建/更新/删除实体
  3. 将所有更改保存到数据库中

为了跟踪新的/脏的/删除的实体Unit of Work 模式

常用:

【讨论】:

  • 我没有使用任何 ORM...你的答案是针对 ORM 的吗?
  • 不,它不是特定于 ORM 的。 ORM 为您提供了开箱即用的功能。如果您不使用任何 ORM,那么您可以自己实现所有这些模式。
  • 您能否推荐任何博客/文章来完全展示具有 Employee-Role 域且易于理解的 UoW...我已经更新了问题...您能否用这些更新您的答案详情?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-26
  • 1970-01-01
相关资源
最近更新 更多