簡體   English   中英

EF代碼優先從對象列表添加方法

[英]EF Code First Generic Add Method From List of Objects

我有一個使用插件樣式方法( ASP.NET MVC的插件架構 )的應用程序來填充我的EF代碼第一個數據庫。 在PreApplicationStartMethod期間,我從每個插件(dll)中提取對象列表以加載到實體框架中。 我正在嘗試使用這種通用方法( 將記錄插入數據庫的通用方法 ),但它說T是一個對象而不是我在插件中指定的特定類型。 因此插入失敗,因為我的上下文中沒有對象dbset。 如果我手動將對象轉換為其原始類型,也會發生同樣的情況。

IModule.cs(主項目)公共接口IModule {List> Entities {get; }}

Module.cs(插件)

public class Module : IModule
{
    public List<List<object>> Entities
    {
        get
        {
            List<List<object>> entities = new List<List<object>>();

            List<object> renderings = new List<object>();
            renderings.Add(new FieldRendering(1, "Text", "String"));
            renderings.Add(new FieldRendering(2, "Date", "Date"));
            renderings.Add(new FieldRendering(3, "Hidden", "Auto"));

            entities.Add(renderings);

            return entities;
        }
    }
}

PreApplicationInit(主項目)

[assembly: System.Web.PreApplicationStartMethod(typeof(Core.Modules.PreApplicationInit), "InitializeModules")]
public class PreApplicationInit
{
    private static Context context;

    public static void InitializeModules()
    {
        // code to pull in the modules (works, so suppressing for brevity)

        context = new Context();

        foreach (List<object> section in module.Entities)
        {
            foreach (object entity in section)
            {
                // Inspecting the entity object here indicates the correct type (FieldRendering)
                Add(entity);
            }

            context.SaveChanges();
        }
    }

    private static void Add<T>(T entity) where T : class
    {
        // Inspecting T here indicates the incorrect type (object)
        // Code fails here
        context.Set<T>().Add(entity);
    }
}

在推斷泛型參數時,編譯器使用傳遞的變量的聲明類型,而不是該變量在運行時包含的內容。

如果您想以這種方式執行操作,可以使用反射來使用正確的泛型參數調用該方法:

var addMethod = typeof(PreApplicationInit)
        .GetMethod("Add", BindingFlags.Static | BindingFlags.NonPublic)
        .MakeGenericMethod(o.GetType());
addMethod.Invoke(null, new[] { entity  });

如果要多次調用它,我會創建一個Dictionary<Type, MethodInfo>()來在創建它時存儲MethodInfo對象,因為創建很慢。

您還可以使Add()方法非泛型,並在Add() context.Set<T>()上使用反射。

這段代碼正常運行。

循環遍歷對象列表時,Add(entity)調用將'object'分配給T,因為它就是它所知道的類型。

也許這里最好的解決方案是讓每個實體模塊都從一個給定的接口派生,然后允許你將它轉換為該接口以向Context注冊 - 我無法測試它是否有效。

Context是否有Set(Type t)方法?

如果是這樣,你可以很容易地做到: -

context.Set(entity.GetType()).Add(entity);

使用重載的DbContext.Set方法接受類型對象而不是泛型類型參數:

foreach (object entity in section)
{
    context.Set(entity.GetType()).Add(entity);
}

泛型類型參數使用的類型在編譯時確定。 在這種情況下,實體的編譯時類型是object 您需要使用實體的運行時類型來獲取要使用的DbSet,而不是使用泛型類型參數。

如果需要不斷向集合中添加新實體,則可以捕獲當上下文保存每個實體的更改時拋出的異常。

foreach (object entity in section)
{
    context.Set(entity.GetType()).Add(entity);

    try
    {
        context.SaveChanges();
    }
    catch (Exception e)
    {
        //do nothing
    }
}

暫無
暫無

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

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