How Do I Use OnModelCreating Inside the Model itself in Entity Framework Core 2.0?

c# entity-framework-core model

Question

I'm very new to Entity Framework, so go easy on me, but I would like to keep the fluent API for my models a little closer to usage and put it inside the model object itself. I couldn't find anything in the documentation or via Google search for a built in way to do this, so I thought perhaps I could just call a static method on the model if it exists from the DbContext.OnModelCreating() method. Here's what I come up with, but it doesn't seem to work whenever I run Add-Migration, and Script-Migration, even if I remove all migrations first. Any idea where I'm going wrong on this? or perhaps a better way to do it?

Trademark.cs (the model)

public class Trademark
{
    public string Name { get; set; }
    // ... 
    protected static void OnModelCreating( ModelBuilder modelBuilder )
    {
        modelBuilder.Entity<Trademark>().HasIndex(x=>x.Name).IsUnique();
    }
}

PartDbContext.cs (DbContext)

public class PartDbContext: DbContext
{
    // ...
    public DbSet<Trademark> Trademarks { get; set; }
    public PartDbContext( DbContextOptions options ): base(options)
    {
    }
    protected override void OnModelCreating( ModelBuilder modelBuilder )
    {
        dynamic m = modelBuilder.Model.GetType().GetMethod("OnModelCreating",System.Reflection.BindingFlags.Static);
        if( m != null )
            m.OnModelCreating(modelBuilder);
    }
}

I'm thinking the issue is that modelBuilder.Model.GetType() returns typeof(IMutableModel) and not typeof(Trademark). So, perhaps I just need to know how to get the type of the model of the model from modelBuilder.

Note: If I put modelBuilder.Entity<Trademark>().HasIndex(x => x.Name).IsUnique(); inside PartDbContext.OnModelCreating(), the unique constraint is added. So, I know I at least got that bit correct.


UPDATE

For anyone else interested in doing this, I decided to narrow the usage down a bit more and only pass the EntityTypeBuilder instead of the whole ModelBuilder.

PartDbContext.cs

protected override void OnModelCreating( ModelBuilder modelBuilder )
{
    foreach( var entityType in modelBuilder.Model.GetEntityTypes() )
    {
        var method = entityType.ClrType.GetMethod("OnEntityCreating",BindingFlags.Static|BindingFlags.NonPublic);
        if( method != null )
        {
            var entityBuilder = new object[] {
                typeof(ModelBuilder)
                .GetMethod("Entity",new Type[]{})
                .MakeGenericMethod(entityType.ClrType)
                .Invoke(modelBuilder,null)
            };
            method.Invoke(null,entityBuilder);
        }
    }
}

Trademark.cs

public class Trademark
{
    public string Name { get; set; }
    protected static void OnEntityCreating( EntityTypeBuilder<Trademark> entityBuilder )
    {
        entityBuilder.HasIndex(x=>x.Name).IsUnique();
    }

}
1
2
1/19/2018 8:37:32 PM

Accepted Answer

You can iterate all discovered entity types and invoke the custom method (if defined) via reflection:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    var parameters = new object[] { modelBuilder };
    foreach (var entityType in modelBuilder.Model.GetEntityTypes())
    {
        var method = entityType.ClrType.GetMethod("OnModelCreating", BindingFlags.Static | BindingFlags.NonPublic);
        if (method != null)
            method.Invoke(null, parameters);
    }
}
5
1/19/2018 6:10:35 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow