0

需要很酷的软件架构师:)

我有两个实体:公司和用户。

当用户被添加到公司时,会创建一个员工实体。员工代表用户和公司之间的联系。没有访问列表,员工实体是无用的。换句话说,我有一些不变量:父实体(员工)必须与子实体(访问列表)一起创建。

我正在寻找在 c# 代码中实现这个不变量的设计解决方案。

Employee 实体具有带有必需参数的构造函数:

public class Employee
{
    public Employee(EmployeeCreationParams creationParams)
    {
        this.Company = creationParams.Company;
        this.User = creationCommand.User;
    }

    public Company { get; protected set; }

    public User { get; protected set; }

    // other state and logic
}

子实体:

public class EmployeeAccessList
{
    public EmployeeAccessList(EmployeeAccessListCreationParams creationParams)
    { /* initialization logic */ }

    public Employee { get; protected set; }

    public OperationEnum Operation { get; protected set; }
}

有通用存储库服务:

public class Repository
{
    public void Persist<TEntity>(TEntity entity)
    {
        // internal stuff
    }
}

Employee 被创建然后持久化:

var employee = new Employee(creationParams);

_repository.Persist(employee);

并且 acl 也得到了持久化:

var accessList = CreateAccessList();

foreach(var acl in accessList)
{
    _repository.Persist(acl);
}

我找不到在员工创建逻辑中注入访问列表创建登录的正确方法。因此,父母和孩子都被视为一个整体。

我尝试将子创建逻辑添加到父构造函数中:

public class Employee
{
    public Employee(EmployeeCreationParams creationParams)
    {
        this.Company = creationParams.Company;
        this.User = creationCommand.User;

        var accessList = CreateAccessList();

        foreach(var acl in accessList)
        {
            _repository.Persist(acl);
        }
    }
}

..但这个解决方案看起来不正确。子对象在父实体之前被持久化。

4

3 回答 3

3

我认为您正试图将大量非常不同的东西放入太少的对象中。创建 Employee 时,您应该区分 3 个单独的职责:

  • 员工实例化逻辑,换句话说,更新员工和所有相关实体。这与应用程序无关,应在域层中定义。由于创建 Employee 看起来有些复杂,因此Factory可能是该工作的理想人选,而不是臃肿的 Employee 构造函数。

  • 员工坚持。这属于基础设施层,在您的 ORM 和存储库实现中。在保存 Employee 时,最好利用 DDD 中的聚合概念和 ORM 来自动保存聚合中的所有实体(包括 AccessLists)。

  • 决定何时保存新员工。这是特定于应用程序的,可以在创建员工的用例结束时在您的应用程序层服务中执行。

于 2012-11-30T16:25:54.057 回答
1

那这个呢?

public class Employee
{
    public Employee(EmployeeCreationParams creationParams, EmployeeAccessList accessList)
    {
        this.Company = creationParams.Company;
        this.User = creationCommand.User;
        this.Access = accessList
    }
}

public class Repository
{
    public void Persist<TEntity>(TEntity entity)
    {
        // encapsulate the fact that ACLs are stored in a separate way than Employees
    }
}

然后,您将获得作为公司-用户关系一部分的访问权限,这是有道理的。作为实现细节,您可能希望将它们存储在单独的表中,但客户端Repository<Employee>不需要关心这一点,您可以稍后更改该实现细节而无需更改这些客户端。您还可以控制这两个数据库调用的事务性,而无需向Repository客户端公开事务性实现。

于 2012-11-30T14:21:52.937 回答
1

这是混合有界上下文的一个相当“经典”的案例。你有一个身份和访问控制 BC,你有一个员工 BC(或任何对你来说有意义的东西——人力资源、组织等)。在您的 Employee 中有一个 UserId 是可以的,但是通过在您的 Employee BC 中包含一个 User 对象,您可能会让生活变得比需要的更难。不过,拥有一个用户值对象是可以的。

希望有帮助。

于 2012-12-01T05:15:18.033 回答