2

I have a hierarchy and I want to configure it in one class. Is it possible?

Currently I have N implementations for IEntityTypeConfiguration<> interface - one per each entity in the hierarchy.

Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
Pavel Voronin
  • 13,503
  • 7
  • 71
  • 137

1 Answers1

4

Sure it is possible. After all, you are not forced to use IEntityTypeConfiguration<> at all - you can configure all your entities inside OnModelCreating. Also all the ApplyConfiguration generic method does is to call Configure method of the class implementing the IEntityTypeConfiguration<TEntity> interface passing EntityTypeBuilder<TEntity> instance which you normally get from modelBuilder.Entity<TEntity>() call (or receive as an argument of the Action<> of the second overload of that method).

Hence you can put your code in any static or instance class method receiving the ModelBuilder instance. If you want to use class, it shouldn't implement IEntityTypeConfiguration<> because there is no way to get ModelBuilder from ``EntityTypeBuilder`, and you need it in order to be able to configure both base and derived entities.

For instance, something like this:

class MyHierarchyConfiguration
{
    public void Apply(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<MyBaseEntity>(builder =>
        {
            // base entity configuration here
        });
        modelBuilder.Entity<MyDerivedEntity1>(builder =>
        {
            // derived entity configuration here
        });
        modelBuilder.Entity<MyDerivedEntity2>(builder =>
        {
            // derived entity configuration here
        });
        // etc.
    }
}

and inside OnModelCreating:

new MyHierarchyConfiguration().Apply(modelBuilder);
Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
  • This is sure a working solution, but maybe it’s worth accepting `modelBuilder` in constructor and then wrapping it with class/interface exposing API which constraints the types just to hierarchy. On one hand it is an overkill, on the other hand it is a clear expression of intention - configuring the hierarchy. – Pavel Voronin Dec 07 '18 at 07:52
  • Since it is encapsulating all the configuration code, I don't see how you can constrain it or provide API. In fact this approach is not constrained to hierarchies - it can be used to encapsulate fluent configuration of any set of (related) entities. If the intent is just to share common base configuration, then the solution is different - generic base configuration class (`MyEntityConfiguration where TEntity : BaseEntity`) and derived configuration classes for each derived entity inheriting it (to configure the specific aspects). But that's not "one class" solution. – Ivan Stoev Dec 07 '18 at 08:12
  • And I didn't use constructor / class state because I wanted to indicate the stateless nature of the configuration - the `Apply` method can be made static, or the class could be made singleton. DI cannot be used to resolve `ModelBuilder` instance (it's an argument of `OnConfiguring`), so no real benefit of using constructor/state. Just a shared piece of code moved out from the `DbContext`. – Ivan Stoev Dec 07 '18 at 08:21
  • But generic version allows us to define the base class. `abstract class ConfigureHierarcy`. Implementors have to override `Configure` which accepts “special” builder which constraints types of configured entities to inheritors of `TBase`. – Pavel Voronin Dec 07 '18 at 08:29
  • Yes, it does. But note that it must be called with the *actual* class, in other words, for each derived class. It's more suitable for hierarchies which don't use EF inheritance - just base classes. If that's what you asked, the answer would be different - for instance https://stackoverflow.com/questions/49990365/entity-framework-core-2-0-how-to-configure-abstract-base-class-once/49997115#49997115 – Ivan Stoev Dec 07 '18 at 08:38
  • Just curious why would anyone need to configure the hierarchy without using EF inheritance capabilities:) – Pavel Voronin Dec 07 '18 at 08:48
  • Because people use base classes just to share some common properties (like `DateCreated`, `DateModified`, `TenantId` etc., or even just `int Id`). They don't want polymorphic queries, also don't want to store their entities in a single table (what current EF Core does by supporting only TPH). But still they can write generic code against such entities, like `FindById` etc. – Ivan Stoev Dec 07 '18 at 08:58
  • I see. But that's a kinda abuse of OOP due to the lack of structural typing and templating. – Pavel Voronin Dec 07 '18 at 09:33
  • Agreed hundred percent. But it's what it is. And we use what we have (is given to us) by the language :) – Ivan Stoev Dec 07 '18 at 09:48