Consider the following scenario:
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);
}
}
Documents
can be shared with User
Obviously this does not scale very well, because of the need to check the SharedWith
for user existence, resulting in the ORM lazy-loading the entire collection into memory. I could do the existence check in the application service, but I consider this domain logic, and so it makes the most sense to me that I keep it in the Document class.
I can't seem to figure out how this should be done with DDD? And what if I am unable to use an ORM, how does one do this sort of stuff?
I suppose I should have a Document Aggregate and a User Aggregate?
I've looked at various DDD resources (I have not read the book though), but I can't seem to find an answer to this particular scenario.
this was quickly done up so it's not perfect but you get the gist of it:
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);
}
}