簡體   English   中英

實體框架代碼優先GenericTypeArguments

[英]Entity Framework Code First GenericTypeArguments

我有一個不幸的任務是創建一個同時使用MySQL和MSSQL數據庫的MVC項目。 為此,我首先使用Entity Framework 6代碼,並且在兩個數據庫上都可以使用它。

但是,問題在於MSSQL支持模式,而MYSQL不支持。 如果添加modelBuilder.Entity<Status>().ToTable("Status", schemaName: "Client"); 我在構建MySQL數據庫時出錯。

為了解決這個問題,我嘗試將自定義屬性添加到所有DbSet中,以便能夠確定要使用的架構。 在MSSQL中,我將使用架構,而在MYSQL中,我將在表前添加架構名稱。

例如:

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


            }

您現在處於反思的境界。 嘗試如下所示的方法:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM