DDD 逻辑和持久性无知

DDD logic and Persistence Ignorance

考虑以下场景:

public class Document 
{
  private ISet<User> sharedWith;

  public Document(string name) 
  {
    this.sharedWith = new HashSet<User>();
    this.Name = name;
  }

  public string Name { get; private set; }

  public IEnumerable<User> SharedWith 
  {
    get 
    {      
      return this.sharedWith;
    }
  }

  public void ShareWith(User user) 
  {
    if (this.SharedWith.Contains(user)) 
    {      
      throw new Exception("This document is already shared with that user.");
    }

    this.sharedWith.Add(user);
  }
}

显然这不能很好地扩展,因为需要检查 SharedWith 用户是否存在,导致 ORM 将整个集合延迟加载到内存中。我 可以 在应用程序服务中进行存在性检查,但我考虑到这个域逻辑,所以对我来说,将它保存在文档 class 中最有意义。

我似乎无法弄清楚应该如何使用 DDD 来完成这项工作?如果我无法使用 ORM 怎么办,如何做这类事情?

我想我应该有一个 Document Aggregate 和一个 User Aggregate?

我查看了各种 DDD 资源(虽然我还没有读过这本书),但我似乎无法找到这个特定场景的答案。

我想如果你在基于 paper/actor 的世界中对此进行建模,那么有人将负责编组谁可以访问哪些文档,这可能依赖于某种基于纸张的文件人工制品。要获得对文档的访问权限,您必须填写文档申请表,这可能会经过审批流程。

在基于纸张的世界中,这种形式将成为多对多链接实体,成为用户访问安全文档的关键。这将使 UserDocumentDocumentRequestForm 成为三个独立的实体。

这很快就完成了,所以它并不完美,但你明白了它的要点:

public class User { public Guid UserId { get; set; } }

public class Document
{
    public string Name { get; private set; }

    private ICollection<User> sharedWith = new List<User>();

    private DateTime? publishedOn;

    public Document(string name)
    {
        if (string.IsNullOrWhiteSpace(name))
        {
            throw new ArgumentException("Name is required");
        }

        this.Name = name;
    }

    public void Publish()
    {
        if (this.publishedOn.HasValue == false)
        {
            this.publishedOn = DateTime.UtcNow;
        }
    }

    public void SharedWith(User user)
    {
        if (this.publishedOn.HasValue == false)
        {
            throw new InvalidOperationException("Document must be published for sharing is allowed.");
        }

        sharedWith.Add(user);
    }
}

public interface IDocumentRepository
{
    Document documentOfId(Guid id);

    bool IsAlreadySharedWith(Guid documentId, Guid userId);
}

public interface IUseRepository
{
    User userOfId(Guid id);
}

public class ShareDocumentService
{
    private readonly IUseRepository userRepository;
    private readonly IDocumentRepository documentRepository;

    public void ShareWith(Guid userId, Guid documentId)
    {
        if (documentRepository.IsAlreadySharedWith(documentId, userId))
            throw new InvalidOperationException("Document has already been shared with user.");

        User user = userRepository.userOfId(userId);

        Document doc = documentRepository.documentOfId(documentId);

        doc.SharedWith(user);
    }
}