实体框架代码First GenericTypeArguments

时间:2014-04-10 09:57:03

标签: c# mysql sql-server entity-framework reflection

我有一个不幸的任务是创建一个同时使用MySQL和MSSQL数据库的MVC项目。为此,我首先使用Entity Framework 6代码并在两个数据库上工作。

然而问题是MSSQL支持Schema而MYSQL不支持。如果我添加modelBuilder.Entity<Status>().ToTable("Status", schemaName: "Client");,我会在构建MySQL数据库时出错。

为了解决这个问题,我尝试将自定义属性添加到我的所有DbSet中,以便能够确定我想要使用的模式。在MSSQL中,我将使用模式,在MYSQL中,我将在表格前加上模式名称。

EG:

MSSQL:
Client.Status
Employee.Status

MYSQL:
Client_Status
Employee_Status

现在确定我想要使用反射的类型和模式。很遗憾,我无法在GenericTypeArguments方法中使用OnModelCreating。它说'System.Type' does not contain a definition for 'GenericTypeArguments' and ...

但是,如果我将反射代码复制到我的MVC Controller(单独项目)中的一个动作,它确实有效。

    [TableSchema("Status", "Client")]
    public DbSet<Tables.Status> Status { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //launch debugger to see inspector
        if (System.Diagnostics.Debugger.IsAttached == false)
            System.Diagnostics.Debugger.Launch();

        //use schema or not
        var useSchema = ConfigurationManager.AppSettings["UseSchema"] == "true";

        //get all properties
        PropertyInfo[] properties = typeof(DataContext).GetProperties(BindingFlags.Public | BindingFlags.Instance);

        foreach (PropertyInfo p in properties)
        {
            // Only work with dbsets
            if (p.PropertyType.Name != "DbSet`1") { continue; }

            //get tableschema attribute
            var attribute = p.GetCustomAttributes(typeof(TableSchema), false).First();


            //the line below reports the error on building
            var type = p.PropertyType.GenericTypeArguments.First().Name;


            //the goal is to use something like 
            modelBuilder.Entity<type>().ToTable(attribute.Table, attribute.Schema);

        }
    }

如果我使用var type =取消注释该行并启用调试,我也可以在检查器中看到GenericTypeArguments

那么如何使用GenericTypeArguments或类似的东西动态获取Tables.Status类型或动态更改模式和表名的替代方法。

更新:

我设法通过首先将其转换为动态来获取类型。但是,Moho引入的代码的第二部分失败了

            var type = ((dynamic)p).PropertyType.GenericTypeArguments[0];

            if (type != null)
            {
                var t = modelBuilder.GetType();
                var m = t.GetMethod("Entity", BindingFlags.Public);

                //System.NullReferenceException
                var mgm = m.MakeGenericMethod((Type)type);


                var entityTypeConfig = mgm.Invoke(modelBuilder, new object[] { });

                if (!useSchema)
                {
                    entityTypeConfig.GetType()
                        .GetMethods()
                        .Single(mi => mi.Name == "ToTable" && mi.GetParameters().Count()==1)
                        .Invoke(entityTypeConfig, new object[] { attribute.Schema + "_" + attribute.Table });
                }
                else
                {
                    entityTypeConfig.GetType()
                        .GetMethods()
                        .Single(mi => mi.Name == "ToTable" && mi.GetParameters().Count() == 2)
                        .Invoke(entityTypeConfig, new object[] { attribute.Table, attribute.Schema });
                }


            }

1 个答案:

答案 0 :(得分:1)

你现在正处于反思的范畴。尝试类似下面的内容:

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

        entityTypeConfig.GetType()
            .GetMethods()
            .Single( mi => mi.Name == "ToTable" && mi.GetParameters().Count == 2 )
            .Invoke( entityTypeConfig, new object[] { attribute.Table, attribute.Schema } );