繁体   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