views:

114

answers:

3

We are trying to find out the best practice when using DDD and we are having some discussions on what makes the most sense or is the "right way".

Note: All code is pseudo code.

Conceder the following:

public interface IDomainEntityAService
{
    void CreateMyObject(DomainEntityA myobject);
    DomainEntityA RetrieveDomainEntityA(long someId);
    //Other operations that handle the business logic dealing with MyObject
}

We also have another service that uses portions of IDomainEntityAService to facilitate a specialized need.

public interface IDomainEntityBService
{
    DomainEntityB GetDomainEntityB();
}

where OtherInformation contains the following:

public class DomainEntityB
{
    public string Name { get; set; }
    public IList<DomainEntityA> DomainEntityAList { get; set; }
}

Now comes our question. We are looking into using a repository to persist OtherInformation like the following:

public interface IDomainEntityBRepository
{
    void Add(DomainEntityB information);
    DomainEntityB Get(long someId);
}

Since we wish to keep things as DRY as possible we would ideally want to reuse the logic of IDomainEntityAService to retrieve the list of DomainEntityAList for DomainEntityB. Which one makes the most sense?

A) have a reference to IDomainEntityAService in the IDomainEntityBRepository e.g.

public class SqlDomainEntityBRepository : IDomainEntityBRepository
{

    public SqlDomainEntityBRepository(IDomainEntityAService domainEntityAService, Database database)
    {

    }

    public void Add(DomainEntityB information)
    {
        //save DomainEntityB to SQL
    }
    public DomainEntityB Get(long someId)
    {
        //Get OtherInformation.Name from SQL
        //use domainEntityAService.Get() to populate the list of DomainEntityAList
        //return DomainEntityB
    }
}

B) IDomainEntityBRepository only handles the SQL stuff and we use the service layer for IHaveOtherInformation to populate the list of MyObjects

public class DomainEntityBService : IDomainEntityBService
{
    public DomainEntityBService(IDomainEntityAService domainEntityAService, IDomainEntityBRepository repo)
    {
    }
    public DomainEntityB GetDomainEntityB()
    {
        var domainEntityB = _repo.Get(someId);
        domainEntityB.DomainEntityAList = _domainEntityAService.GetAll(someId);
        return domainEntityB;
    }
}

C) We make a specific DAL object for OtherInformation and we use the service layer to compose an instance of OtherInformation

public class DomainEntityBDAL
{
    public string Name { get; set; }
    public IList<int> DomainEntityAListIds { get; set; }
}

We then would have a repository to retrieve the OtherInformationDAL and then the code would look like the following:

public class DomainEntityBService : IDomainEntityBService
{

    public DomainEntityBService(IDomainEntityAService domainEntityAService, IDomainEntityBRepository repo)
    {
    }
    public DomainEntityB GetDomainEntityB()
    {

        var domainEntityBDAL = _repo.Get(someId);
        DomainEntityB result = new DomainEntityB() { Name = domainEntityBDAL.Name };
        foreach (var id in domainEntityBDAL.DomainEntityAListIds)
        {
            result.DomainEntityAList.Add(_domainEntityAService.Get(id));
        }
        return result;
    }
}

D) Wow we are completely off base do this instead!!!

I hope this makes sense and thanks for your help.

Edit Notes:

Maybe an english description can help describe my question better. We have DomainEntityA which is an aggregate root. There is a corresponding service to handle all logic that deals with DomainEntityA.

Now we also have DomainEntityB which is an aggregate root. However DomainEntityB has a list of DomainEntityAs. DomainEntityAs can live by itself, however DomainEntityB can not live without a list of DomainEntityAs

How would we load up the list of DomainEntityA items in DomainEntityB and maintain all the logic for DomainEntityA.

Reuse DomainEntityAService in DomainEntityBService?
Create a separate DomainEntityARepository in the DomainEntityBService?

We currently use EntLib but are looking more on information on design then the DAL implementation.

A: 

I'm making the assumption here that you're going to be storing to a database.

The answer to this depends quite heavily on what you're using as your persistence engine. If you have hand rolled your own persistence then C is not an option because you're going to see N+1 Queries. B would most likely be my first choice because it offers the most code reuse with, hopefully, non-awful performance.

Having said that if you're using something like NHibernate I'd recommend NOT using the repository pattern and instead

  • Encapsulating complex queries as objects (which can then be unit tested).
  • Use the session directly

I hope this helps!

jonnii
We most likely are going to be using EntLib for our DAL.
Mark
Have you had any information why A would be considered bad? Is it bad practice for a repository to return an object which is gathered from more then one location? e.g. to create an instance of a domain model I need to query from SQL, XML, and a file? Or should a repository only touch one data store?
Mark
A: 

Interesting post on the general topic of the repository pattern: http://ayende.com/Blog/archive/2009/04/17/repository-is-the-new-singleton.aspx

brian
A: 

How about you instead use a general interface that lets you plug in the type? Like so:

public interface IRepository<T>
{
    T Get(object id);
    void Save(T value);
    void Update(T value);
    void Delete(T value);
    IList<T> GetAll();
}

Whatever implementation you use should be able to read the type and know how it fits into the database. That is the repository pattern in a nutshell. If you're not completely set on Entlib, explore NHibernate. I've found that it complements the repository pattern well. I've written extensively on this topic on my blog, so you can go there if you want to know more.

James Jones
Thanks for the information, however see my edits. If a child of T is also an aggregate root (in a completely different domain), how would you handle loading up those items in the repository?
Mark
NHibernate can handle "children of T" (aka inheritance). I don't know what you could possibly mean by "aggregate root in a different domain" but NHibernate can handle pretty much any relationship you can come up with.
James Jones
I don't mean inheritance, "B" has a list of "A"'s. "A" can live by it self and be consumed by other services/applications. Now "B" needs a list of "A"'s to be a valid instance of "B". Say to get all of the "A"'s (for an instance of "B") it will need to make a webservice call. Where should that call live? Should the call to load up the "A"'s for "B" live in the DAL, Service layer, or something else?
Mark
B should merely store a list of A identifiers (probably integers?). You should create repository implementations for each system, where both implementations inherit the IRepository interface. To elaborate, you would have one repo for system A (which consumes the web service), and one repo for system B (which uses NHibernate). The reason you would want two different repositories is to decouple the two systems, so that when system A changes, you can simply create a new version of its repository and not disturb system B's repository. This works well in practice.
James Jones