Search code examples
c#asp.net-mvcmodel-view-controllerdomain-driven-designrepository-pattern

Domain models and the List / Detail page


I need some advice on the question I have been battling with on DDD.

I have a domain model which is an aggregate root

public class  Objective {
   public int ObjectiveId { get; private set; }

        public string ObjectiveDescription { get; private set; }

        public DateTime StartDate { get; private set; }

        public DateTime TargetDate { get; private set; }

        public DateTime? CompletedDate { get; private set; }

        public int EmploymentId { get; private set; }

        public List<Skill> RelatedSkills { get; private set; }

        public List<Goal> RelatedGoals { get; private set; }
       // few more properties.
} 

I have 2 views one is a ListView and another is a Details View.

The ListView has an IEnumerable which has just 3 fields

class ObjectiveListVM{
   public int ObjectiveId { get; private set; }
    
            public string ObjectiveDescription { get; private set; }
    
            public DateTime StartDate { get; private set; }
}

The Details view has an ObjectiveDetailViewModel which has 90 percent of the fields from the Objective domain model plus a few more.

I have a repository which gets me either a list or one objective

IObjectiveRepo
{
   Objective GetById();
   IEnumerable<Objective> GetList();
}

This is how I have implemented the DDD and Repository pattern. My question is this, my GetList query is really expensive, it only needs data from 3 columns but since my Repositories should always return domain objects, I End up returning a list of the entire Objective domain object which has child lists and lots of fields.

The solution I thought of is to have another ObjectiveSummary domain model which just has a few fields and is returned by the GetList repo method. But it then breaks some other principles of DDD mainly that ObjectiveSummary is an Anemic Domain model. It's not a model, it's more of a DTO in my head.

This is such a common scenario that I feel I am missing something very basic in my implementation or interpretation of DDD / repository patterns.

Can some of the experts point out the mistake I have made in the implementation or highlight a way to address this problem without expensive queries?

Note: I can think few ways of getting around this problem. However, I am more interested in finding the correct way that does not break the principles of the architecture/pattern that I am using.


Solution

  • You should not query your domain model. An aggregate is always loaded in its entirety so it does not lend itself well to querying.

    As soon as you think about lazy-loading you are probably not using an optimal approach. Lazy-loading is evil. Don't do it :)

    What you are after is a query layer of sorts. This is directly related to CQRS. The query side only returns data. It has no behaviour and you return the most basic structure that you can. In the C# world that I am also in I use a DataRow or IEnumerable<DataRow>. If it is really complex I may opt for a DTO:

    public interface IObjectiveQuery
    {
        DataRow ForList(int id);
        bool Contains(string someUniqueKey);
    
        IEnumerable<DataRow> Search(string descriptionLike, DateTime startDate);
    
        string Description(int id);
    }
    

    Give it a go. I think you'll find it simplifies things immensely. Your domain should only be concerned about the command/write side of things.