Entity Framework 6 (7) vs NHibernate 4: DDD perspective

By Vladimir Khorikov

There is quite a bit of Entity Framework vs NHibernate comparisons on the web already, but all of them cover mostly the technical side of the question. In this post, I’ll compare these two technologies from a Domain Driven Design (DDD) perspective. I’ll step through several code examples and show you how both of these ORMs let you deal with problems.

Onion architecture

Entity Framework vs NHibernate: Onion architecture

Onion architecture

Nowadays, it is common to use onion architecture for complex systems. It allows you to isolate your domain logic from other pieces of your system so that you can focus your effort on the problems that are essential to your application.

Domain logic isolation means that your domain entities should not interact with any classes except other domain entities. It’s one of the core principles you should follow to make your code clean and coherent. Of course, it’s not always possible to achieve that level of isolation but it’s certainly worth trying.

The picture below shows onion architecture using the classic n-tier scheme.

Entity Framework vs NHibernate: Onion architecture from the N-tier perspective

Onion architecture from the N-tier perspective

Persistence Ignorance

While using an ORM, it is vital to sustain a good degree of persistence ignorance. It means that your code should be structured in such a way that allows you to factor the persistence logic out of your domain entities. Ideally, domain classes should not contain any knowledge about how they are being persisted. That allows us to adhere to the Single Responsibility Principle and thus keep the code simple and maintainable.

If you tend to write code like in the sample below, you are on the wrong path:

public class MyEntity

{

    // Perstisted in the DB

    public int Id { get; set; }

    public string Name { get; set; }

 

    // Not persisted

    public bool Flag { get; set; }

}

If your domain logic is separated from persistence logic, you can say that your entities are persistence ignorant. That means that you can change the way you persist their data without affecting the domain logic. Persistence ignorance is prerequisite to the domain logic isolation.

Case #1: Deleting an entity from aggregate root

Let’s go through the real-world code examples.

Order

Order aggregate

Here is an aggregate that contains two classes at the diagram above. Order class is the aggregate root, which means that Order controls the Lines collection’s lifespan. If an Order is deleted, its Lines are deleted with it; OrderLine has no meaning without an Order.

Let’s assume that we want to implement a method that deletes a single line from an order. Here is how it can be implemented if you don’t have to save your entities in the database (i.e. without any ORM):

public ICollection<OrderLine> Lines { get; private set; }

public void RemoveLine(OrderLine line)

{

    Lines.Remove(line);

}

You just delete it from the collection, and that’s it. As long as Order is the root of the aggregate, any other classes must retrieve an Order’s instance in order to get access to its lines. If there’s no such line, we can say that it is deleted.

Now, if you try to do it with Entity Framework, you’ll get an exception:

The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable.

There’s no way to instruct Entity Framework to delete orphaned items from the database. You need to do that yourself:

public virtual ICollection<OrderLine> Lines { get; set; }

public virtual void RemoveLine(OrderLine line, OrdersContext db)

{

    Lines.Remove(line);

    db.OrderLines.Remove(line);

}

Passing OrdersContext parameter to the entity’s method breaks the Separation of Concerns principles, because the Order class becomes aware of how it is stored in the database.

Here’s how it can be done in NHibernate:

public virtual IList<OrderLine> Lines { get; protected set; }

public virtual void RemoveLine(OrderLine line)

{

    Lines.Remove(line);

}

Note that the code is almost identical to the code that is not bound to any ORM. You can instruct NHibernate to delete the orphaned line from the database by using this mapping:

public class OrderMap : ClassMap<Order>

{

    public OrderMap()

    {

        Id(x => x.Id);

        HasMany(x => x.Lines).Cascade.AllDeleteOrphan().Inverse();

    }

}

Case #2: Link to a related entity

Order line

Order line reference

Let’s say you need to introduce a link to a related entity. Here’s a code that is not bound to any ORM:

public class OrderLine

{

    public Order Order { get; private set; }

    // Other members

}

This is the default way to do that with Entity Framework:

public class OrderLine

{

    public virtual Order Order { get; set; }

    public int OrderId { get; set; }

    // Other members

}

The default way to do that in NHibernate:

public class OrderLine

{

    public virtual Order Order { get; set; }

    // Other members

}

As you can see, by default, Entity Framework requires an additional Id property to work with the reference. This approach violates SRP because Ids represent an implementation detail of how entities are stored in a database. Entity Framework impels you to work directly with the database’s concepts whereas a better approach in this situation would be just a single Order property.

Moreover, this code breaks the DRY principle. Declaring both OrderId and Order properties enables OrderLine class to easily fall into an inconsistent state:

Order = order; // An order with Id == 1

OrderId = 2;

Now, EF does allow for declaring a single Order property instead. But still, there are two problems with it:

  • Accessing the Id property of the related entity leads to loading that entity from the database, although that Id is already in memory. In contrary, NHibernate is smart enough to not do that. With NHibernate, the loading would be executed only if you refer to an Order’s property other than Id.
  • Entity Framework impels developers to use Ids instead of just related entity reference. Partly, because it’s the default way of doing this sort of things, and partly because all the examples use this approach. In contrast to Entity Framework, the default way to create a reference in NHibernate is the first one.

Case #3: Read-only collection of related entities

If you need to make the lines collection read-only for the Order’s clients, you could write this code (not bound to any ORM):

private List<OrderLine> _lines;

public IReadOnlyList<OrderLine> Lines

{

    get { return _lines.ToList(); }

}

The official way of doing it in EF:

public class Order

{

    protected virtual ICollection<OrderLine> LinesInternal { get; set; }

    public virtual IReadOnlyList<OrderLine> Lines

    {

        get { return LinesInternal.ToList(); }

    }

 

    public class OrderConfiguration : EntityTypeConfiguration<Order>

    {

        public OrderConfiguration()

        {

            HasMany(p => p.LinesInternal).WithRequired(x => x.Order);

        }

    }

}

public class OrdersContext : DbContext

{

    protected override void OnModelCreating(DbModelBuilder modelBuilder)

    {

        modelBuilder.Configurations.Add(new Order.OrderConfiguration());

    }

}

Clearly, this is not how you’d like to build your domain entities as you directly include an infrastructure class in your domain class. Unofficial solution is hardly better:

public class Order

{

    public static Expression<Func<Order, ICollection<OrderLine>>> LinesExpression =

        f => f.LinesInternal;

 

    protected virtual ICollection<OrderLine> LinesInternal { get; set; }

    public virtual IReadOnlyList<OrderLine> Lines

    {

        get { return LinesInternal.ToList(); }

    }

}

 

public class OrdersContext : DbContext

{

    protected override void OnModelCreating(DbModelBuilder modelBuilder)

    {

        modelBuilder.Entity<Order>()

        .HasMany(Order.LinesExpression);

    }

}

Still, you need to include infrastructure code in the Order class. Entity Framework doesn’t offer anything to factor this logic out.

Here’s how it can be done with NHibernate:

public class Order

{

    private IList<OrderLine> _lines;

    public virtual IReadOnlyList<OrderLine> Lines

    {

        get { return _lines.ToList(); }

    }

}

public class OrderMap : ClassMap<Order>

{

    public OrderMap()

    {

        HasMany<OrderLine>(Reveal.Member<Order>(“Lines”))

        .Access.CamelCaseField(Prefix.Underscore);

    }

}

Again, the way we do it with NHibernate is almost identical to the way we would do it without any ORM whatsoever. The Order class here is clean and doesn’t contain any persistence logic, and thus allows us to focus on the domain, dealing with one problem at a time.

NHibernate’s approach has one drawback, though. This code is vulnerable to refactoring as the property’s name is typed in as a string. I consider it to be a reasonable trade-off because it allows us to better separate the domain code from the persistence logic. Besides, such errors are really easy to detect either by manual testing or integration auto tests.

Case #4: Unit of Work pattern

Here’s another example. Below is the code from a task I worked on a couple years ago. I’ve omitted details for brevity, but you should get the point:

public IList<int> MigrateCustomers(IEnumerable<CustomerDto> customerDtos,

    CancellationToken token)

{

    List<int> ids = new List<int>();

 

    using (ISession session = CreateSession())

    using (ITransaction transaction = session.BeginTransaction())

    {

        foreach (CustomerDto dto in customerDtos)

        {

            token.ThrowIfCancellationRequested();

 

            Customer customer = CreateCustomer(dto);

            session.Save(customer);

 

            ids.Add(customer.Id);

        }

 

        transaction.Commit();

    }

 

    return ids;

}

The method takes some data, converts it to domain objects and saves them after that. It returns a list of customers’ Ids. The caller code has an ability to cancel the migration process using CancellationToken which is passed in as well.

If you use Entity Framework for this task, it will insert your entities in the database in order to get their Ids because, for integer identifiers, EF doesn’t allow for choosing any id generation strategy other than database identity. This approach works well for most of the cases, but it has a major flaw – it breaks the Unit of Work pattern. If the method is canceled, EF would have to delete all the records that have been inserted so far, which itself causes massive performance impact.

With NHibernate, you can choose Hi/Lo id generation strategy so that customers are simply not saved until the session is closed. Ids are generated on the client side, so there’s no need to touch the database to retrieve them. NHibernate can save a huge amount of time with this type of tasks.

Case #5: Working with cached objects

Let’s say your customer list is pretty stable and don’t change often. You may decide to cache them so that you can use customer list without querying the database. Now, let’s also say that the Order class has a precondition to belong to one of the customers. This precondition can be implemented using a constructor:

public Order(Customer customer)

{

    Customer = customer;

}

This way, we are sure that no order can be created without a customer.

With Entity Framework, you can’t set a detached object as a reference to a new object. If you use a constructor like the one above, EF will try to insert the customer in the database because it wasn’t attached to the current context. To fix it, you need to explicitly specify that the customer is already in the database:

public Order(Customer customer, OrdersContext context)

{

    context.Entry(customer).State = EntityState.Unchanged;

    Customer = customer;

}

Again, such approach breaks SRP. In contrast, NHibernate can detect an object’s state by its Id and doesn’t try to insert this object if it’s already in the database, so the NHibernate’s version would be the same as the non-ORM one.

Entity Framework vs NHibernate: results

There’s one simple method of how to measure an ORM’s persistence ignorance degree. The closer the code that uses an ORM is to a code that isn’t bound to any database, the cleaner this ORM, and the more it is persistence ignorant.

EF is too tightly coupled to the database notions. When you model your application with Entity Framework, you still need to think in terms of foreign-key constraints and table relationships. Without a clean and isolated domain model, your attention is constantly distracted, you can’t focus on the domain problems that are essential for your software.

The trick here is that you actually may not notice such distractions until your system grows in size. And when it does, it becomes really hard to sustain the pace of development because of increased maintainability costs.

That said, NHibernate is still way ahead of Entity Framework. Besides the better separation of concerns, NHibernate has a bunch of useful features that Entity Framework doesn’t: 2nd level cache, concurrency strategies, rich mapping capabilities and so on and so forth. Probably, the only feature that EF can boast of is async database operations.

Why is it so? Isn’t Entity Framework being actively developed for many years? EF was initially created as a tool for working on simple CRUD applications and only several years after got some really good features, such as code-first mapping. It seems that this initial purpose is still leaking out, even after all these years of active development. It means that while Entity Framework is a good tool in many situations, if you want to create a domain model which fully adheres to the DDD principles, you are still better off choosing NHibernate.

I believe Entity Framework can replace NHibernate eventually, but the EF team will need to adjust its approach to building the ORM in order to achieve it (although, admittedly, they did a very good job since the version 1).

Update 12/1/2014

The Entity Framework program manager Rowan Miller replied that some of this issues will be addressed in EF7, although, still, not all of them. Nevertheless, EF seems to be going in a right direction, so let’s cross our fingers.

If you want to learn more about how to build a rich domain model having an ORM at hand, you can watch my Pluralsigh course Domain-Driven Design in Practice.





  • Lucus

    Just came across your article when trying to figure out how to delete a child object from its parents collection using DDD and EF. The object was not getting deleted just orphaned in the DB its Foreign Key was set to null (which was a mistake in my system since I should have entity set up so that the FK is required but even so I would have just got the FK null exception on saving)
    I guess I will have to pass in the context to the delete method to get is to work properly with EF.

    Thanks for the post and comparison with Non-ORM and NHibernate.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      That’s right, EF tries to set the Foreign Key column to null when deleting an object from the parent’s collection. Unfortunately, passing the context to the delete method is the only simple way to make it work.

      Thanks for the comment!

      • http://keyboard.ninja Josh Rogers

        Actually you can take care of orphaned objects. You just have to register to listen for the collection change events through the DbContext. Whenever an element is removed you can then iterate through the child elements and mark them for removal as well. So then when you call save the Context (Unit of Work) has the changes registered and deletes the orphans along with the parent.

        Here is a small extension method and sample of how to use it:
        https://gist.github.com/anonymous/0f5e5d2de8e47bd0bcbd

    • Janus Knudsen

      Imagine what you could with some sort of DSL, truly amazing magic I guess 😛

      • John Caccavaro

        see Frameworks – http://www.JohnCaccavaro.com. It is a DSL that emits NHibernate mappings, queries, business object (entities), etc.

        • Janus Knudsen

          Just sarcasm from my side… hint SQL is a perfect DSL, so why try to make things more complicated. I simply can’t see the logic 🙂

  • http://forloop.co.uk/ Russ Cam

    Great post, thanks for sharing!

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Thank you!

  • Дмитрий Наумов

    Being big fan of NH I tempted myself to use EF in pet projects just to put my fingers into it and get better understanding of pros and cons NH vs. EF. But after reading your article I lost my last doubts and will continue to use NH where it suits. Actually with CQRS NH and RDBMS play less important role in my projects, but that’s another story. Thanks for nice article!

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Thank you for your comment!

  • c_world_poster

    My thoughts of EF is that is much like EJB 1/2. Way too heavy weight and does the wrong things. They didn’t seem to learn anything from NHibernate or EJB 1/2.

    I have only used EF on one app and was highly disappointed (and frustrated)

    The other part of this equation is something like Spring Framework. I just don’t use NHibernate (or Hibernate). I use it with Spring for things like IoC and AOP. So in your Case #4 the method would just be annotated with Transactional and be done with it. I cannot seem to find something like this for EF.

    Also, does EF let you do things like “select new SomeTypeSafeObject(…)” or “new List/Map”? I do this a lot .

    https://docs.jboss.org/hibernate/orm/3.3/reference/en-US/html/queryhql.html#queryhql-select

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Actually, querying features in EF are quite nice. There’s a good LINQ support in EF, so you can easily fetch objects in a strongly typed manner:
      db.Orders
      .Where(x => Name == “name”)
      .Select(x => new SomeTypeSafeObject(…));

      As for your comparison with EJB – I couldn’t agree more. Thanks for you comment!

  • Daskul

    isn’t it that NHibernate is dead? but lately Im seeing some pulse on the project commit. Are they trying to revive it?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Well, NHibernate is certainly not dead 🙂 It’s true that it is being developed much slower that EF, but that’s true for any pair of projects one of which is backed by a big vendor and the other one is supported by enthusiasts.

      The sad thing is, even with the higher pace of development, EF is still way behind of NH in terms of functionality, as well as modeling capabilities.

      • Daskul

        with that being said, would you still recommend NHibernate today instead of EF7?

        • http://enterprisecraftsmanship.com/ Vladimir Khorikov

          I didn’t have a chance to work with EF7 yet, so take my answer with a bit of skepticism.

          What I saw in preview videos and feature lists is that EF team makes a good effort towards cleaning the code base up. For example, they are going to abandon non-code first approach completely, which is a good thing.

          But still, NH has richer mapping capabilities (issue #1 is still true for EF7 so far) and overall is smarter than EF (issue #5, for example). So yes, I still recommend using NH today instead of EF7, and I do use it on new projects myself.

          • Daskul

            thank you for the information. I really wanna try NHibernate but I have doubt that I wont find a job using it it the future

  • http://hojjatk.com Hojjat K

    Comparing to EF, NHibernate misses Async support. Some people argue that there is no benefit in using async calls for database

    http://blogs.msdn.com/b/rickandy/archive/2009/11/14/should-my-database-calls-be-asynchronous.aspx

    However, I think sometimes it would help and providing usefull async api can help developers to not write codes to get the same result as async call.

    What do you think about this?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      You are right, async support is the only feature that NHibernate misses comparing to EF.

      Regarding whether or not I think this feature is useful. Well, I don’t find myself using it very often on EF projects. Database is usually a primary component of most of the typical applications, so if there are any problems with its performance, it is better to optimize it instead of querying it asynchronously. In a situation where the application needs the database access with every operation, async operations don’t provide any value.

      At the same time, I do think async operations are helpful in some situations. For example, if you query multiple IO sources in a single service call (2 databases, database + external service, etc.) async operations help do that simultaneously without spending CPU threads.

      • Milo Cabs

        i think async would be beneficial for after the fact operations. e.g. Auditing tables, flat tables.

        Not sure though. 🙂

  • youzer

    Can’t use interfaces with Entity Framework.
    If I build my domain model in a vacuum and I implement interface members on my domain class, you can forget about being able to map them to a persistence model.

    And that’s another thing. Domain model for me isn’t the same as my persistence model. Most of the time I’m working with an existing database. I develop my domain model, again in a vacuum, and when it’s time to persist, I’m struggling with mappings and relationships. It’s not ideal at all.

    I doubt my struggle would be any different with another ORM. I just can’t find an easy way to map a domain model to a persistence model when working with an existing database.

    Oh! And enums! No enum support.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Indeed, creating an app while working with a legacy database is always a pain. I know of only one good solution here – refactoring the database along with building the domain model.

      Mappings (even those of NHibernate) are not always capable to handle all the difficulties we encounter when creating a new domain model on top of an existing database.

  • Dipen Lama

    Nice article, I recently was evaluating nHibernate 4 with EF 6. I hope lot from EF 6, but for bulk operations (update, insert, delete) there is nothing in EF 6, some third party have develop for SQL Server only. How can EF team missing such a common thing like Bulk Operation, 2nd Level caching. For now i have to choose nHibernate because of performance.

  • MacGyver

    Very nice article. I’m using EF6 in my projects however right now I’m about to build some rich long-term DDD application and I’m wondering which ORM (if any) should I use. What would you recommend? NHibernate or EF7? Do you know if the rest of your persistance ignorance points in this article’s list are fixed in the newest version of EF?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Thanks.

      I would choose NHibernate. As far as I know, EF7 is going to handle only #1 and #4 from that list; other points are either of low priority or not in the backlog at all.

      Regarding whether or not you should use an ORM at all: I do think you need one if you work with a relational DB. Here I write about it in more detail: http://enterprisecraftsmanship.com/2015/11/30/do-you-need-an-orm/

  • Alexander Gannouni

    Indeed a nice article, it puts things in perspective! However, I have searched the EF7 documentation and found that as of EF7 it is possible to implement a Cascade on Delete. This means that the problem in Case 1 has been solved by a new version of EF. I know this article stretches as far as EF6 so it’s just to inform you that as of EF7 it is possible to Cascade on Delete.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Good to know, thanks for sharing!

  • BBI

    One major problems with all these ORM frameworks is their high complexity, that people need to know about all: programming, design and relational databases. The Persistence Ignorance is something unusual for many, especially if the ORM has misleading method names like Load(), Get(), Save(), Update(), which suggest that the ORM works like manually coded SQL or file access. So people start to program with NHib/EF in a load-modify-save style, rather than with Unit of Work and PI, then wonder why a Save() doesn’t lead to an immediate SQL Insert/Update on the DB, or why object changes get stored without a Save() call ever made. In the worst case, the ORM is forced to work in this inefficient style, SELECT N+1 included. There may in some cases be as much efforts to break down a sophisticated ORM to this style, as a micro ORM or manual SQL would require to be optimized to a certain degree.

    Also, everything working with RDBMS has a problem with object aggregates, which, if normalized correctly, can easily consist of a graph of a dozen tables. Joins bloat this into a cartesian product of all result sets, while separate selects may return inconsistent results (dependent/child rows deleted by other between read of parents and dependent – dependent table not locked/snapshot made until actually selected from). Perhaps, relational databases will have to give way to more suitable data storages (which also don’t require all the manual indexing, normalization and query tweaking), as it is already going on with NoSQL. For the ACID dependent part, maybe object or graph databases. Perhaps these highly complex ORM are only a legacy, as well as classic relational databases.

    Perhaps, when EF finally reaches the level of NHibernate, hardly anybody will still need it.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      I agree. Indeed, many people struggle with ORMs and just want to make them work, Persistence Ignorance and domain model isolation is often not the first priority for them, which is perfectly understandable.

      And indeed, polyglot persistence is one of the ways to mitigate the problem of the paradigm mismatch. Another viable option I see here is to use functional languages; that can help attack the problem from the other end.

  • Michael G.

    Good article. It touches on the same issues that I have found when using EF, and goes into deeper detail on some than I have been able to figure out myself.

    One question though:
    Using NHibernate, where there are no DAOs to use in a repository, how do you map polymorphic Domain Objects?

    Consider that you have a base class: Vehicle

    And several classes, which derive from Vehicle
    Car
    Boat
    Airplane

    How would this mapping be done in NHibernate, considering that the data for all stored in the same database table, with unique derivative values stored in separate related tables?

    To add more complexity to it, how would it be done, if Car had two further derivatives?
    Truck
    Camper

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      The type of inheritance mapping you described with vehicle is one of the 3 types supported by most ORMs (both NHibernate and EF support them). I think I’ll write a blog post with the detailed explanation of their pros and cons soon. In short, the one where classes have 1-to-1 correspondence to tables is called Table Per Type (aka Table Per Subclass): http://nhibernate.info/doc/nhibernate-reference/inheritance.html

      You can nest the mapping as much as you want, so the two further derivatives can also be mapped. Here’s a good article on how to do that in NH: http://www.codeproject.com/Articles/232034/Inheritance-mapping-strategies-in-Fluent-Nhibernat

      BTW, I recommend using the Table Per Hierarchy strategy by default. It is more performant and easier to manage from the DB standpoint.

  • some dude

    You bring a lot of great weakness in EF but you forget what NHibernate have since the dawn of time,
    1. Despite being bloated it was not easy to setup
    2. “Still” haunted by Hibernate
    3. abandonware, despite not having async none of the contributor have any intention of adding it

    Sure you want to boost the feature in NHibernate but let be real, none of that really necessary, Hi-Lo, multiple guid, etc, who in their right mind use that, database job is to save data, let them handle the guid and id making shall we, you violate DRY by using all that crap.

    The session for getting id without commiting is good, but when migrating to EF I dont miss that anymore. Also EF support concurrency who say it doesn’t? The cache is annoying, btw EF have 1st level cache and I also find those annoying as well, when I call select I want the newest one stop giving me old record, if I want to cache I will use Redis.

  • dave barnett

    Hi Vladimir,

    Regarding case 1.
    It looks to me like creating a composite key solves the problem when using entity framework. See the answer in this stackoverflow post
    http://stackoverflow.com/questions/13473511/remove-an-item-from-collection-using-entity-framework

    What do you think?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Looks like a hack but seems that it indeed works, didn’t know about this feature. I’ll need to try it myself, will probably update the article after that.

      Thanks for the reference!

  • Anders Baumann

    Hi Vladimir.

    I am about to start a new .Net MVC project and I am in doubt about what technologies to choose. I have experience with both Entity Framework and NHibernate and just like you I also prefer NHibernate. But what about .Net Core and .Net MVC Core? I would like to stay up-to-date with technologies and I want to make sure that the technologies I choose will be supported for many years to come. But as far as I understand NHibernate is not migrated to .Net Core (https://nhibernate.jira.com/browse/NH-3807). I plan on hosting the project in Azure and I don’t have any need cross-platform needs. What would you recommend that I choose?

    Thanks in advance,
    Anders

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      That’s a tough one. I too find myself in similar situations now. My personal rule of thumb here is this. If you need Linux support (either now or in the near future), then choose EF, there’s no other viable option at this point, unfortunately. If you plan to host on Windows only, then it depends on how complex the project is. For simple projects, EF might work just fine, even with all its shortcomings. For complex ones, I would go ahead and use NH.

      There is some hope, though. Hazzik ( https://disqus.com/by/hazzik/ ) does a great job supporting NHibernate, and it could be that we will get a working version for .Net Core 2.0 soon.

  • dave falkner

    What are your thoughts on using an EF DbContext like a statically-typed ADO.NET, but still with a persistence and mapping layer that is separate from your domain layer?
    That is to say, having domain entities that are completely separate and distinct from your EF “entities.” That is the pattern I tend to find myself falling into, but it it seems to work pretty well for me, and seems to create a sort of best-of-both-words compromise. I still need a mapping/transformation layer, but then avoid having to deal with embedded sql strings, run-time type mismatches, etc.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      From my experience, separating domain entities from EF “entities” rarely pays off. It works for simple cases only and gets really complicated when you try to persist something more or less complex. And even in simple cases, I don’t see a lot of benefits. If the domain model is so simple, no need to create manual mapping in the first place, straight EF “entities” would suffice.

      Here I wrote about it in more detail: http://enterprisecraftsmanship.com/2016/04/05/having-the-domain-model-separate-from-the-persistence-model/