I generally use nHibernate to generate the unique ID's for my entities... but I am thinking about generating them in code? Consider the following example: (If I am doing something else wrong please point it out as I am new to DDD):
These are all the classes that would belong in the same assembly i.e. my domain model.
public interface AggregateRootState
{
bool CanAddChild();
bool CanModifyChild();
bool CanDeleteChild();
}
public class AggregateRoot
{
private AggregateRootState aggregateRootState;
public IList<ChildEntity> ChildEntityList {get; internal set;}
public bool CanAddChild()
{
return aggregateRootState.CanAddChild();
}
public void AddChild(ChildEntityParameters childEntityParameters)
{
if (!CanAddChild())
throw new NotImplementedException("aggregate root not in correct state.");
ChildFactory.CreateChildEntity(childEntityParameters);
}
public bool CanModifyChild()
{
return aggregateRootState.CanModifyChild();
}
public void ModifyChild(ChildEntityParameters childEntityParameters)
{
if (!CanModifyChild())
throw new NotImplementedException("aggregate root not in correct state.");
ChildEntity childEntity = ChildEntityList.First(c => c.Id == childEntityParameters.Id);
childEntity.Property1 = childEntityParameters.Property1;
childEntity.Property2 = childEntityParameters.Property2;
}
public bool CanDeleteChild()
{
return aggregateRootState.CanDeleteChild();
}
public void DeleteChild(Guid Id)
{
if (!CanDeleteChild())
throw new NotImplementedException("aggregate root not in correct state");
ChildEntityList.Remove(ChildEntityList.First(c => c.Id == Id));
}
public void Validate()
{
//code to validate the object and ensure it is in a savable state.
}
}
public class ChildEntityParameters
{
public Guid Id {get; set;}
public string Property1 {get; set;}
public string Property2 {get; set;}
}
public class ChildEntity
{
internal ChildEntity() { }
public Guid Id {get; set;}
public string Property1 {get; internal set;}
public string Property2 {get; internal set;}
}
internal static class ChildFactory
{
public static void CreateChildEntity(ChildEntityParameters childEntityParameters)
{
ChildEntity childEntity = new ChildEntity();
childEntity.Property1 = childEntityParameters.Property1;
childEntity.Property2 = childEntityParameters.Property2;
}
}
My Service Layer would then look something like this:
//for simplicity I have arguments rather than using the request / response pattern.
public class ServiceLayer
{
public void AddChildEntity(Guid aggregateRootId, string string1, string string2)
{
AggregateRoot aggregateRoot = aggregateRootRepository.FindBy(aggregateRootId);
ChildEntityParameters childEntityParameters = new ChildEntityParameters();
childEntityParameters.Property1 = string1;
childEntityParameters.Property2 = string2;
aggregateRoot.AddChild(childEntityParameters);
aggregateRoot.Validate(); //will throw exception if there is something wrong.
aggregateRootRepository.Save(aggregateRoot);
}
}
Now this all works well and good. However the problem is what if I wanted to return the ID of the newly created ChildEntity to the presentation layer? It's not currently possible. I would have to return the whole object graph. The only alternative I can think of is to make the following changes to my code:
internal static class ChildFactory
{
public static void CreateChildEntity(ChildEntityParameters childEntityParameters)
{
ChildEntity childEntity = new ChildEntity();
**childEntity.Id = Guid.NewGuid();**
childEntity.Property1 = childEntityParameters.Property1;
childEntity.Property2 = childEntityParameters.Property2;
}
}
public class ServiceLayer
{
public **Guid** AddChildEntity(Guid aggregateRootId, string string1, string string2)
{
**Guid Id;**
AggregateRoot aggregateRoot = aggregateRootRepository.FindBy(aggregateRootId);
ChildEntityParameters childEntityParameters = new ChildEntityParameters();
childEntityParameters.Property1 = string1;
childEntityParameters.Property2 = string2;
**Id = aggregateRoot.AddChild(childEntityParameters);**
aggregateRoot.Validate(); //will throw exception if there is something wrong.
aggregateRootRepository.Save(aggregateRoot);
return Id;
}
}
Is this wrong? or is it perfectly ok? Would be good if someone could clarify!