C# – Data Entities, Domain entities and the repositories

cdomain-driven-designrepository-pattern

I'm trying to get my head around DDD but I'm stuck.
This is how I setup my project:

Data Access Layer
 -Entity models that map to the db
 -Db connection stuff
 -Repositories implementations

Domain Layer
 -Models that represent the DAL entity models
 -Repositories interfaces

Application Layer
 -MVC application that uses Domain models

The first problem I see here is that the Domain models are exactly the same as the Entity models, and I have a serious problem with this: the entity models obviously have validation configured into them, things like "max length", "nullable", "required", etc. Now, to conform to what I understand is DDD, I can't directly use these models anywhere, except the DAL, so I created my domain layer. In the domain layer, I have all these validation rules duplicated for UI validation, and what's even worse, is that if I need to change a rule, I will have to change it in two places: the DAL and the Domain.

Example:

User Entity in DAL
Name (required)
Last name (required)
Email (required, maxlen 120)
Username (required, maxlen 120)

User Domain Model
Name (required)
Last name (required)
Email (required, maxlen 120)
Username (required, maxlen 120)

Another thing that I find very weird is that the repositories organization in this architecture.
Following what I read, I created a GenericRepository interface, and a UserRepository interface, which inherits the GenericRepository, all in the Domain layer.
I implemented the GenericRepository in the DAL, and the implementation creates a DAO for the type of the entity used to create the repository. So far, so good.

Then, I proceeded to implement the UserRepository, and here I have another problem: the UserRepository interface expects the Domain User model, and when I try to implement the interface in the DAL, I need to implement it using the Domain User model, which causes the DAO to be created for a Domain model, not a DAL model, and this doesn't make any sense. The only to fix it would be to reference the DAL in the Domain layer, which is wrong.

Domain Layer:

public interface IGenericRepository<TEntity>
{
    TEntity FindById(TKey id);
}

public interface IUserRepository : IGenericRepository<Domain.User>
{
    Task<User> FindByUserNameAsync(string userName);
}


DAL:

public abstract class GenericRepository<TEntity> : IGenericRepository<TEntity>
{
    protected DbContext ctx;
    protected DAO<Entity> dao;

    public GenericRepository(DbContext context)
    {
        ctx = context;
        dao= ctx.Dao<TEntity>();
    }

    public virtual TEntity FindById(TKey id)
    {
        return dao.Find(id);
    }
}

 public class UserRepository : GenericRepository<Domain.Models.User>, IUserRepository
{
    public UserRepository(DbContext context)
        : base(context)
    {
       // THIS WILL CREATE A DAO FOR A DOMAIN MODEL
    }

    // rest of code...
}

Can anybody shed a light on what I'm missing from DDD?

Best Answer

Okay. There is a lot to unpack here, but the I think the root cause of some of your confusion is stemming from starting this process with the physical model at the forefront. This commonly causes all sorts of issues for individuals first trying to implement DDD. The goal of DDD is to model the behavior of a system such that the result is a useful abstraction of the function requirements of the core domain. For now, just forget about your DAL. It's an implementation detail.

Start by modelling your system by organizing the models by behavior into bounded contexts. It's the behavior of models that truly relates them. The data/attributes that entities contain is rarely a good starting point for modelling the functional requirements of a complex system. I'd love to provide some examples, but you didn't specify your domain so I'll just give you some tips:

Starting with your User domain model. I'd bet the kitchen sink that the only reason this exists is because you have a User entity. The issue with this is that User implies little to no behavior (uses what?), probably encompasses too much knowledge, and is therefore too abstract. What do your users do (authentication aside)? Shop? Shopper. Comment? Commenter/Poster. Sell? Seller. The important part is that these are not mutually exclusive! One User can be all of these things depending on the behavior in which they are going to engage. The fact that they all map to the same database table is an implementation detail.

You see where I'm going here? You may have a Shopping context that has Shopper, ShoppingCart, and CartItem and a Billing context that has Buyer, PurchaseRequest, and LineItem where the models in each respectively map to a [User], [Order], and [OrderItem] database table. Your model should be the absolute focus of this process. Not how it is persisted.

As for a direct answer to your question. There are a number common objects found in a domain. DomainModels and ValueObjects are the cornerstones of your model, but you will often find Repositories and Factories playing a supporting role. Because repositories and factories nearly always need to know the implementation details of your domain, they are usually part of your domain model (but not part of the diagram, for example).

Related Topic