1

I am considering mutliple options to face a problem. I want to develop software following DDD style. The problem arise when I have to define my entities and I am working with Entity Framework Core, any other ORM would have the same problems.

ORM generates plain POCOs entities that represents the Tables in our DB. That don't fits DDD style.

Ways to accomplish a DDD style entities:

A) Implement Repository/Unit of Work patterns + Mapping: Use some kind of mapping process inside the repositories implementations, between the Ef entities and the Domain entities we work with. We got a set of repositories that makes a facade to EF Core, and all the EF implementation details remains decopupled.

Pros

  • Decopuling achieved
  • Centralized mapping configuration
  • Repositories return DDD style entities, easy to aggregate and follow DDD rules.

Cons

  • Loose of some EF features , autotracking => Less efficient
  • The possibility to launch Expression> queries=> Over-verbose methods in the repos to fit all needs.
  • Our implementation of UoW will be poor compared to Ef/ORM ones

B) Turn EF Core Entities into DDD style.: ORM usually allow us to define our classes before and then map them to a database with some configuration. Following this path you could get , business logic inside entities and DDD related practices( private setters/ aggregation) .See answer of @Flater for more detail.

Pros

  • All the features implemented by specific ORM(EF Core) => efificency, auto tracking , etc
  • We don't have to implement an "overdesign" of Repository/UoW patterns

Cons

  • We lose decoupling between layers, because we introduce dependency on the DbContext which is a specific tech related.

Do you know other approaches? Which pros and cons have them?

  • An Entity Framework DataContext object is a unit of work implementation. Treat it accordingly. – Robert Harvey Mar 15 at 19:32
  • Yeah it is, but how do you use properly the Ef auto generated classes as Domain entities(ddd) – Badulake Mar 15 at 19:36
  • Why do you need to seperate your entity class and model class? You can use your entity classes with EF. – Engineert Mar 15 at 22:16
  • Read comments in Harvey answer. There are some disadvantages I don’t k ow how to face – Badulake Mar 15 at 22:16
  • Do you need any of these two features you said you would miss? Do you think the pros outweigth the cons? – Laiv Mar 15 at 23:38
2

You mention "EF auto generated classes", which suggest you're using a DB-first approach. But you mentioned in the comments that you're open to anything, so I want to suggest switching to a Code First approach.

Robert Harvey's answer isn't wrong, I simply want to offer another viable solution to the problem.

Note: I don't know much about EF Core specifically, my answer uses EF but I assume that there aren't too many differences between the two.


EF has two approaches:

  • Database First - EF generates C# based on an existing database
  • Code First - EF generates a databased based on existing C# classes.

So the idea is simple: create your classes, and then tell EF that you want it to create the database accordingly. This gives you direct control over your classes and where you store them.

A basic example

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class MyContext : DbContext
{
    public MyContext() : base("MyConnectionStringName")
    { 

    }

    public DbSet<User> Users { get; set; }
}

This is enough information for EF to generate a database for you. It will generate a table for every DbSet<T> you specify, and it will generate that table's columns based on the class definition of T.
EF will make some assumptions (e.g. that a property named Id is intended to be the PK of your table). You can change these default behaviors; more on that further in the answer.

There is a lot more information on this subject than I can provide in the answer. Plenty of tutorials and guides exist online (example), I suggest you look into these to learn about the more detailed configuration options that EF puts at your disposal.


However, there is one thing I still want to point out. When you want to adjust your db columns, e.g. putting a max length on a certain string property, there are two ways of doing so.

Firstly, and most commonly found online, you can use attributes on your class:

public class User
{
    public int Id { get; set; }

    [MaxLength(50)]
    public string Name { get; set; }
}

These attributes are mostly provided by EF. Some others (e.g. [NotMapped]) are not provided by EF but EF does observe and respond to them (in the case of [NotMapped], the property will not generate a table column).

As you may suspect, many attributes are available.

But there is a second way, using the Fluent API. This will initially feel more contrived, but it's actually the better option when you want to take a DDD approach. Instead of decorating your entity with attributes, you instead "register" these configurations on the context itself:

public class MyContext : DbContext
{
    public MyContext() : base("MyConnectionStringName")
    { 

    }

    public DbSet<User> Users { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>().Property(p => p.Name).HasMaxLength(50);
    }
}

As far as I'm aware, every attribute has an equivalent Fluent API alternative.

But why use Fluent for DDD?

The reason I want to suggest this is because the attributes require you to have access to the EF dependency in your class definition, which means that your entity will be defined in the data layer.

But you don't want that. You want to have a separate domain layer where your classes are defined and then consumed by the data layer. By using the Fluent API, you can ensure that this is what happens. The MyContext class is already required to be part of the data layer (since it derives from EF's DbContext), so it makes more sense to have it also take care of the EF-specific configuration of the table columns.

  • I see your point. this is what I have actually done in my last project. I think this solution will be part of option B , dont you think so? My question is about anothers ways to handle that problem. I will use your anwer to enrich/explain better the question /option B. Many thanks – Badulake Mar 18 at 10:40
  • @Badulake: Yes, but A/B are not necessarily mutually exclusive. I work with what I would call a "DDD light" approach (purists will probably take heavy offense to me calling what I do DDD but I do at least try to follow the spirit of DDD's guidelines), where I use Code First and repositories/unit of work. Based on the options you list and their pros and cons, I think you grasp the technical elements but aren't seeing every possible way in which to utilize them. I don't quite understand your B con; because wouldn't that apply in all cases of using an EF context, including A? – Flater Mar 18 at 10:49
  • I think it is a common decission to choose, inside your application services layer, between consume custom Repo/UoW or delegate that work to DbContext. That will choose between A or B. If you choose to use both I think you will end with a overdesigned DbCOntext with little advantages, so yes i would say that they are exlusive.Why would you use repos/UoW , and, at the same time, a DbContext? Also I want to know what DDD purists will do in our situation, this is the place to see other options.Thanks by your colaboration – Badulake Mar 18 at 10:54
  • @Badulake: Because you will garner a lot of friction from developers who blindly apply the "everything must be abstracted" approach. I fully agree that (uow+repositories) is just a replication of (context+dbsets). I have written a more in depth answer where I advocate not using them and simply using the context directly. I stand by that notion, but many developers protest at the suggestion of doing so because they consider it a leaky abstraction. – Flater Mar 18 at 10:58
  • You are wrong about EF approaches. There is Model First approach also. – Engineert Mar 18 at 12:02
1

Just use the EF auto-generated classes in your domain models.

For example:

public class Invoice
{
    public int InvoiceID { get; set; }
    public Address BillingAddress { get; set; } 
    public Address ShippingAddress { get; set; }

    public List<InvoiceItem> LineItems { get; set; }
}

Where Address and InvoiceItem are both auto-generated EF entities.

This approach alleviates the need to do mappings of any sort, and preserves your change tracking.

  • Yeah I see your point, but how do you put all your business logic inside that class? Imagine u want to follow DDD style . With private setters and multiple stuff as other child entities (aggregate roots) , Valiue objets, methods with business logic etc – Badulake Mar 15 at 20:14
  • You can do anything you want inside the Invoice class. If you need logic inside your EF entities, those are partial classes. Just create another partial class, for example, partial class Address, and put your logic there. – Robert Harvey Mar 15 at 20:16
  • Ok that will work for business logic, what about private setters?(ef work with them?) And handling of value objects? Have you handled them correctly with this approach? Do you know some github repo where I can have a look? – Badulake Mar 15 at 20:20
  • Let us continue this discussion in chat. – Robert Harvey Mar 15 at 20:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.