如何从聚合根内部使用DB中的数据填充子实体?

时间:2015-10-08 04:45:41

标签: c# entity-framework domain-driven-design solid-principles

我有一个聚合根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方法的参数,因此我的域名未与数据库耦合。然后,我验证initialStatus以确保其id匹配Status.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; }
}

1 个答案:

答案 0 :(得分:3)

你工厂里的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。我想你想要避免这种情况,但它比将数据库与数据库耦合更清晰(我会不惜一切代价避免)。

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

另外,不要将subEntityFactory作为参数传递。工厂是一种特殊的服务,所以它应该注入施工人员而不是传递给他们。这使Entity对工厂的依赖性明确,这很好。

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