我如何从一个聚合根内填充数据从DB的子实体

本文关键字:填充 数据 实体 DB 一个 | 更新日期: 2023-09-27 18:16:29

我有一个聚合根Entity,它在请求时执行一些处理。如果在处理过程中满足某个条件,则必须初始化SubEntity。问题是,SubEntity也有一个子实体Status,必须初始化的起始值,来自数据库。

我正在努力密切遵循SOLID和DDD原则,但我在这方面是新手。我现在让它工作的方式是通过使用工厂,但对我来说这看起来是错误的,因为我不喜欢让这个工厂由消费者类服务(为了遵循DIP),因为这是该实体中的域逻辑的一部分。

我这样做对吗?这是设计此类类的正确方法吗?我有什么选择?

public class Entity
{
    public virtual SubEntity SubEntity { get; private set; }
    public void Process(int someData, ISubEntityFactory subEntityFactory)
    {
        if (SomeConditionIsMet)
        {
            SubEntity = subEntityFactory.Create(this);
        }
    }
}
public class SubEntity
{
    public SubEntity(Entity entity, Status status)
    {
        Entity = entity;
        Status = status;
    }
    public virtual Entity Entity { get; private set; }
    public virtual Status Status { get; private set; }
}
public class Status
{
    public const int StartingId = 1;
    public int Id { get; set; }
    public string Description { get; set; }
    public virtual ICollection<SubEntity> SubEntity { get; private set; }
}
public class SubEntityFactory : ISubEntityFactory
{
    // property and constructor omitted
    public SubEntity Create(Entity entity)
    {
        var status = UnitOfWork.StatusRepository.GetByID(Status.StartingId);
        return new SubEntity(entity, status);
    }
}

解决方案

基于dmi的伟大答案,我决定接收initialStatus变量作为Process方法的参数,因此我的域不耦合到DB。然后验证initialStatus以确保其idStatus.StartingId匹配。在那之后,我甚至不再需要工厂了,它看起来干净多了。

public class Entity
{
    public virtual SubEntity SubEntity { get; private set; }
    public void Process(int someData, Status initialStatus)
    {
        ValidateInitialStatus(initialStatus);
        if (SomeConditionIsMet)
        {
            SubEntity = new SubEntity(this, initialStatus);
        }
    }
    private void ValidateInitialStatus(Status initialStatus)
    {
        if (initialStatus == null)
        {
            throw new ArgumentNullException("initialStatus");
        }
        if (initialStatus.Id != Status.StartingId)
        {
            throw new ArgumentException("Initial status is invalid");
        }
    }
}
public class SubEntity
{
    public SubEntity(Entity entity, Status status)
    {
        Entity = entity;
        Status = status;
    }
    public virtual Entity Entity { get; private set; }
    public virtual Status Status { get; private set; }
}
public class Status
{
    public const int StartingId = 1;
    public int Id { get; set; }
    public string Description { get; set; }
    public virtual ICollection<SubEntity> SubEntity { get; private set; }
}

我如何从一个聚合根内填充数据从DB的子实体

你们工厂的UnitOfWork.StatusRepository.GetByID(Status.StartingId)看起来很可疑。尽量避免将工厂与存储库耦合(尽管另一种方式也是可以的,例如在重构期间使用工厂)。

一个干净的解决方案如下:

public class Entity
{
    private readonly ISubEntityFactory _subEntityFactory; 
    public Entity(ISubEntityFactory subEntityFactory) {
        _subEntityFactory = subEntityFactory;
    }
    public void Process(int someData, Status initialStatus)
    {
        if (SomeConditionIsMet)
        {
            SubEntity = _subEntityFactory.Create(this, initialStatus);
        }
    }
}

这样做的结果是initialStatus必须由调用的应用程序服务检索。我猜你想避免这种情况,,但它比将域耦合到DB(我将不惜一切代价避免)干净得多。

如果可以,将initialStatus重新设计为值对象。我不知道这在你的情况下是否可行,但这会使设计更健壮。

同样,不要将subEntityFactory作为参数传递。工厂是一种特殊类型的服务,因此它应该被注入到构造函数中,而不是四处传递。这使得Entity对工厂的依赖显式,这是很好的。

请注意,实体中存在服务依赖关系通常会导致最好通过工厂创建或重构实体的结论。这样,工厂就可以在构建特定实体时提供其所需的所有服务。始终记住,对象构造是一个实现细节,客户端不需要知道它就可以使用对象