0

我有一个使用插件样式方法(ASP.NET MVC 的插件架构)的应用程序来填充我的 EF 代码优先数据库。在 PreApplicationStartMethod 期间,我从每个插件 (dll) 中提取对象列表以加载到实体框架中。我正在尝试使用这种通用方法(将记录插入 DB 的通用方法),但它说 T 是一个对象,而不是我在插件中指定的特定类型。结果插入失败,因为我的上下文中没有对象数据库集。如果我手动将对象转换为其原始类型,也会发生同样的情况。

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

3 回答 3

1

在推断泛型参数时,编译器使用传递的变量的声明类型,而不是该变量在运行时包含的内容。

如果你想以这种方式做事,你可以使用反射来调用具有正确泛型参数的方法:

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

如果要多次调用它,我会创建一个在创建Dictionary<Type, MethodInfo>()MethodInfo 对象时存储它们,因为创建速度很慢。

您还可以使该Add()方法非泛型,并在context.Set<T>()within上使用反射Add()

于 2013-09-06T04:38:44.350 回答
1

此代码正在按应有的方式工作。

在遍历对象列表时,Add(entity) 调用将“对象”分配给 T,因为这是它所知道的类型。

也许这里最好的解决方案是让您的每个实体模块都从给定的接口派生,然后允许您将其强制转换为该接口以向 Context 注册 - 但我无法测试这是否有效。

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

如果是这样,您可以轻松地做到:-

context.Set(entity.GetType()).Add(entity);
于 2013-09-06T04:39:21.033 回答
0

使用接受类型对象而不是泛型类型参数的重载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
    }
}
于 2013-09-06T04:51:24.927 回答