Efcore: DBSET as List in dbcontext, dynamic loading dbset from assembly (Concept Question)

Created on 11 Mar 2018  Β·  11Comments  Β·  Source: dotnet/efcore

Good day friends.
It is possible to make DBSET as list ?

For example there a many dbset in DbContext And all types must defined directly

public class MyAppContext : DbContext
{
    public MyAppContext () : ;

    public DbSet<Table1> Table1 { get; set; }
    public DbSet<Table2> Table2 { get; set; }
    /////Many dbset references
}

It's possible to make this kinf of code.
1.Motivation, add entity in dbset dynamically, clear code of dbcontext!
2.Loading Entities from dynamic assembly ! Dynamic Linking!

public class MyAppContext : DbContext
{
    public MyAppContext () : ;
    public List <DbSet<T>> EntityList{ get; set; }

    public MyAppContext () ;
    {
     List<type> Types= Scanassebly(internal_assembly).types;

          for each(typ in Types)
          {
           list.add(typ)
          }
    }

}

A have seen this repo
https://github.com/bricelam/Sample-SplitMigrations
But in code of dbcontext we must have defined manually all dbset that will use !
I know about SET method, but it not so comfortable to used with reflection!

closed-question

Most helpful comment

Hoooouuu , Hoooouuu!!!
Acrtually I do it that way.

Just i'am searching more comfortable way to access to entityes !
like context.Blogs or context.Comments with dymanic assemblyes!

Its not so easy to load entites via assembly and using it with dynamic object!
But I know when we use the Reflection is killing our perfomance!

 //public class Record1
    //{
    //    public int id{ get; set; }
    //    public string name{ get; set; }
    //    public bool active { get; set; }
    //}


    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        var myAssembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(@"c:\Users\TOTEM\YandexDisk\0PROJECTS\Assembly_DAL\ClassLibrary1\ClassLibrary1\bin\Debug\netcoreapp2.0\ClassLibrary1.dll");

        var myType = myAssembly.GetType("ClassLibrary1.Record1");
        var myInstance = Activator.CreateInstance(myType);

        // ΠΊΠΎΠ΄ динамичСски добавляСт 

        Type[] paramTypes = { myType };
        foreach (Type type in paramTypes)
        {
            if (type.IsClass)
            {

                var method = modelBuilder.GetType().GetMethod("Entity", new Type[] { });
                method = method.MakeGenericMethod(new Type[] { type });
                method.Invoke(modelBuilder, null);
            }
        }

        base.OnModelCreating(modelBuilder);

    }


    //And usage

    [HttpGet]
    public DefinitionEntity GetEntity(long id)
    {
        var myAssembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(@"C:\Users\diaskhani0112\YandexDisk\0PROJECTS\Assembly_DAL\ClassLibrary1\ClassLibrary1\bin\Debug\netcoreapp2.0\ClassLibrary1.dll");
        Type myType = myAssembly.GetType("ClassLibrary1.Record1");

        var dbSetMethodInfo = typeof(DbContext).GetMethod("Set");
        dynamic dbSet = dbSetMethodInfo.MakeGenericMethod(myType).Invoke(_context, null);
        dynamic Rec = Activator.CreateInstance(myType);

        Rec.active = true;
        dbSet.Add(Rec);
        _context.SaveChanges();

        return null;

    }


All 11 comments

@Diaskhan There is no need to create DbSet properties on the context in order to get entity types into the model. Instead, use an .Entity call on the ModelBuilder in OnModelCreating.

We have discussed in the past doing dynamic discovery for you, but ultimately decided against it, partly because scanning assemblies can be a tricky business to do correctly across all platforms. It's much easier if you know, because you control it, that certain problematic cases will not arise--for example, certain kinds of security exception in .NET Framework due to certain kinds of types in the assembly. Therefore, we leave it up to you to do the scanning, followed by a simple call to .Entity to register the type once found.

Hoooouuu , Hoooouuu!!!
Acrtually I do it that way.

Just i'am searching more comfortable way to access to entityes !
like context.Blogs or context.Comments with dymanic assemblyes!

Its not so easy to load entites via assembly and using it with dynamic object!
But I know when we use the Reflection is killing our perfomance!

 //public class Record1
    //{
    //    public int id{ get; set; }
    //    public string name{ get; set; }
    //    public bool active { get; set; }
    //}


    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        var myAssembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(@"c:\Users\TOTEM\YandexDisk\0PROJECTS\Assembly_DAL\ClassLibrary1\ClassLibrary1\bin\Debug\netcoreapp2.0\ClassLibrary1.dll");

        var myType = myAssembly.GetType("ClassLibrary1.Record1");
        var myInstance = Activator.CreateInstance(myType);

        // ΠΊΠΎΠ΄ динамичСски добавляСт 

        Type[] paramTypes = { myType };
        foreach (Type type in paramTypes)
        {
            if (type.IsClass)
            {

                var method = modelBuilder.GetType().GetMethod("Entity", new Type[] { });
                method = method.MakeGenericMethod(new Type[] { type });
                method.Invoke(modelBuilder, null);
            }
        }

        base.OnModelCreating(modelBuilder);

    }


    //And usage

    [HttpGet]
    public DefinitionEntity GetEntity(long id)
    {
        var myAssembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(@"C:\Users\diaskhani0112\YandexDisk\0PROJECTS\Assembly_DAL\ClassLibrary1\ClassLibrary1\bin\Debug\netcoreapp2.0\ClassLibrary1.dll");
        Type myType = myAssembly.GetType("ClassLibrary1.Record1");

        var dbSetMethodInfo = typeof(DbContext).GetMethod("Set");
        dynamic dbSet = dbSetMethodInfo.MakeGenericMethod(myType).Invoke(_context, null);
        dynamic Rec = Activator.CreateInstance(myType);

        Rec.active = true;
        dbSet.Add(Rec);
        _context.SaveChanges();

        return null;

    }


Good day All,

I have successfully create database and table at runtime by using code below on OnModelCreating method
fyi, i'm using netcoreapp2.0

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        Assembly modelInAssembly = Assembly.Load(new AssemblyName("ModuleApp"));
        var entityMethod = typeof(ModelBuilder).GetMethod("Entity", new Type[] { });
        var exportedTypes = modelInAssembly.ExportedTypes;

        foreach(Type type in exportedTypes)
        {
            if(type.BaseType is System.Object && type.AssemblyQualifiedName.Contains("Models"))
            {
                entityMethod.MakeGenericMethod(type)
                    .Invoke(modelBuilder, new object[] { });
            }     
        }

        base.OnModelCreating(modelBuilder);
    }

and i also added code below on startup class as shown

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, CustomDbContext context)
    {
        context.Database.EnsureCreated();

       ...
    }

i guesse context.Database.Migrate(); dosent work, why I dont know !

@febrynas You'll need to create a migration before calling Migrate will do anything.

The main problem that when we compile assembly net core doesnt provide unload assemlbyes! And each change we must reload our net core app? Do u think is right ?

Surelly to get migrate schema by code is need to !

1.Create model class!
2.Invoke code from (https://github.com/aspnet/EntityFrameworkCore/issues/10872) for create migration
3.Compile migrations in one assembly!
4.Reload appliaction, and apply migrations!

Is'n fluent.

Hi All,

You can choose one of two ways to create database and table at runtime


  1. RelationalDatabaseCreator databaseCreator = (RelationalDatabaseCreator) context.Database.GetService<IDatabaseCreator>(); databaseCreator.CreateTables();

2.
context.Database.EnsureCreated();

To check whether the physical DB is already exist you can use the code below
databaseCreator.Exists()

Below is good article for automatic migration in EF core
https://stackoverflow.com/questions/42355481/auto-create-database-in-entity-framework-core?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa

http://www.koderdojo.com/blog/ef-core-migrations

https://www.bricelam.net/2014/12/16/ef7-migrations-designtime.html#automatic-migrations

https://romiller.com/2012/03/26/dynamically-building-a-model-with-code-first/

@febrynas the main problem that I need to create not only tables, I want that migrations runs in runtime !
Creating column.deleting columns.

@Diaskhan for migration at runtime you can follow code below, it will create __EFMigrationsHistory table
context.Database.EnsureCreated();
context.Database.Migrate();

For deleting column at runtime, it is a lot of work since EF Core doesn't support automatic migration
You can refer to this article https://www.bricelam.net/2014/12/16/ef7-migrations-designtime.html#automatic-migrations

I think below is a good article which tell us the logic to do automatic migration, but i don't know to code this
https://github.com/aspnet/EntityFrameworkCore/issues/6214#issuecomment-239519498

  1. Compare the current model to the previous model (see step 4) using the MigrationsModelDiffer
  2. Convert the resulting operations into SQL using the MigrationsSqlGenerator
  3. Execute the SQL using the MigrationCommandExecutor
  4. Store a serialized version of the model in the database. In EF6, we stored a gziped copy of the EDMX in the [__MigrationHistory].[Model] column. Note, there is currently no serialized model format in EF Core.

check out my rep https://github.com/imaa/DynamicDbContext it's new still under development

Was this page helpful?
0 / 5 - 0 ratings