Dynamically changing schema in Entity Framework Core

后端 未结 10 2299
刺人心
刺人心 2020-11-28 09:02

UPD here is the way I solved the problem. Although it\'s likely to be not the best one, it worked for me.


I have an issue with working with EF

10条回答
  •  无人及你
    2020-11-28 09:27

    maybe I'm a bit late to this answer

    my problem was handling different schema with the same structure lets say multi-tenant.

    When I tried to create different instances of the same context for the different schemas, Entity frameworks 6 comes to play, catching the first time the dbContext was created then for the following instances they were creates with a different schemas name but onModelCreating were never called meaning that each instance was pointing to the same previously catched Pre-Generated Views, pointing to the first schema.

    Then I realized that creating new classes inheriting from myDBContext one for each schema will solve my problem by overcoming entity Framework catching problem creating one new fresh context for each schema, but then comes the problem that we will end with hardcoded schemas, causing another problem in terms of code scalability when we need to add another schema, having to add more classes and recompile and publish a new version of the application.

    So I decided to go a little further creating, compiling and adding the classes to the current solution in runtime.

    Here is the code

    public static MyBaseContext CreateContext(string schema)
    {
        MyBaseContext instance = null;
        try
        {
            string code = $@"
                namespace MyNamespace
                {{
                    using System.Collections.Generic;
                    using System.Data.Entity;
    
                    public partial class {schema}Context : MyBaseContext
                    {{
                        public {schema}Context(string SCHEMA) : base(SCHEMA)
                        {{
                        }}
    
                        protected override void OnModelCreating(DbModelBuilder modelBuilder)
                        {{
                            base.OnModelCreating(modelBuilder);
                        }}
                    }}
                }}
            ";
    
            CompilerParameters dynamicParams = new CompilerParameters();
    
            Assembly currentAssembly = Assembly.GetExecutingAssembly();
            dynamicParams.ReferencedAssemblies.Add(currentAssembly.Location);   // Reference the current assembly from within dynamic one
                                                                                // Dependent Assemblies of the above will also be needed
            dynamicParams.ReferencedAssemblies.AddRange(
                (from holdAssembly in currentAssembly.GetReferencedAssemblies()
                 select Assembly.ReflectionOnlyLoad(holdAssembly.FullName).Location).ToArray());
    
            // Everything below here is unchanged from the previous
            CodeDomProvider dynamicLoad = CodeDomProvider.CreateProvider("C#");
            CompilerResults dynamicResults = dynamicLoad.CompileAssemblyFromSource(dynamicParams, code);
    
            if (!dynamicResults.Errors.HasErrors)
            {
                Type myDynamicType = dynamicResults.CompiledAssembly.GetType($"MyNamespace.{schema}Context");
                Object[] args = { schema };
                instance = (MyBaseContext)Activator.CreateInstance(myDynamicType, args);
            }
            else
            {
                Console.WriteLine("Failed to load dynamic assembly" + dynamicResults.Errors[0].ErrorText);
            }
        }
        catch (Exception ex)
        {
            string message = ex.Message;
        }
        return instance;
    }
    

    I hope this help someone to save some time.

提交回复
热议问题