【问题标题】:Entity Framework Code First GenericTypeArguments实体框架代码优先 GenericTypeArguments
【发布时间】:2014-05-23 23:00:36
【问题描述】:

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

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

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

EG:

MSSQL:
Client.Status
Employee.Status

MYSQL:
Client_Status
Employee_Status

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

但是,如果我将反射代码复制到我的 MVC 控制器(单独的项目)中的操作,它确实可以工作。

    [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 });
                }


            }

【问题讨论】:

  • 使用 FluentAPI 在 OnModelCreating 本身中应用表/模式名称而不是在 TableSchema 属性上使用反射不是更容易吗?
  • 虽然一开始这需要做更多的工作,但我认为将所有表格设置集中在一个地方会在未来的开发中受益,因此我不需要在代码顶部添加表格和然后还在OnModelCreating方法的底部添加对它的引用

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


【解决方案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 } );

【讨论】:

  • 谢谢。但问题是首先获得type,因为我不能使用p.PropertyType.GenericTypeArguments。经过一番摆弄后,我设法通过将其转换为动态类型来获得类型,然后我可以使用GenericTypeArguments 并且检查器显示正确的类型。但是当我在你的代码中使用它时,我在.MakeGenericMethod( type ) 上得到了一个空引用异常
  • 所以问题不在于类型,而在于GetMethod( "Entity", BindingFlags.Public ) 部分。显然这不是公共方法,但GetMethod( "Entity") 解决了它。谢谢!
猜你喜欢
  • 1970-01-01
  • 2017-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-29
  • 2012-05-31
  • 2012-12-30
  • 2015-04-09
相关资源
最近更新 更多