Asp.net mvc 3 C、 MVC3,如何使用运行时定义类型的非泛型数据库集?

Asp.net mvc 3 C、 MVC3,如何使用运行时定义类型的非泛型数据库集?,asp.net-mvc-3,entity-framework-4,ef-code-first,dbset,Asp.net Mvc 3,Entity Framework 4,Ef Code First,Dbset,我是MVC和EF的新手。我的应用程序是一个简单的代码,首先是几个POCO类和一个DBContext,如下所示: public class ExpDefContext : DbContext { public DbSet<Experiment> Experiments { get; set; } public DbSet<Research> Researches { get; set; } ... …并为接受运行时类型并设置

我是MVC和EF的新手。我的应用程序是一个简单的代码,首先是几个POCO类和一个DBContext,如下所示:

   public class ExpDefContext : DbContext
   {
      public DbSet<Experiment> Experiments { get; set; }
      public DbSet<Research> Researches { get; set; }
      ...
…并为接受运行时类型并设置新数据库集的上下文创建了构造函数:

        public ExpDefContext(Type LogRecType)
        {
            Log = Set(LogRecType);
        }
顺便说一下,类型是使用Reflection.Emit构建的

在控制器中,我创建了名为LogRec的类型,并将其传递给一个新的DBContext实例。然后我创建一个LogRec实例并尝试将其添加到数据库:

    Type LogRec;
    LogRec = LogTypeBuilder.Build(dbExpDef, _experimentID);
    var dbLog = new ExpDefContext(LogRec);
    var testRec = LogRec.GetConstructor(Type.EmptyTypes).Invoke(Type.EmptyTypes);
    dbLog.Log.Add(testRec);
    dbLog.SaveChanges();
我从dbLog.Log.AddtestRec中得到一个异常:

实体类型LogRec不是当前上下文的模型的一部分

我做错了什么? 有没有更好的方法来做到这一点,最好不要深入实体框架


谢谢

我怀疑EF只会反映派生DbContext中的通用DbSet属性,并在内存中创建模型时忽略任何非通用DbSet属性

但是,另一种方法可能是在OnModelCreating中使用fluentapi将动态类型作为实体添加到模型中

首先,只有在首次加载AppDomain时在内存中构建模型时,才能向模型添加类型。每个AppDomain只构建一个模型。如果除了重载构造函数之外,您还有一个默认的上下文构造函数,并且使用这个默认构造函数创建和使用了一个上下文实例,那么您的模型将只使用静态类型构建,并且只要AppDomain存在,您就不能再使用动态类型作为实体。这将导致与您的情况完全相同的异常

另一个要考虑的问题是数据库模式的创建。如果您的类型在编译时未知,则数据库架构在编译时未知。如果在下一次运行应用程序时,模型因新类型而更改,则需要以某种方式更新数据库架构,方法是从头开始重新创建数据库,或者定义一个自定义数据库初始值设定项,该初始值设定项仅删除LogRec表,并根据LogRec类型的新布局创建一个新表。或者代码优先迁移可能会有所帮助

关于使用Fluent API的可能解决方案:

删除DbSet并将类型成员添加到上下文中,并重写OnModelCreating:

…它将与静态LogRec类型一起使用,这只会使EF知道该类型是实体。这与向上下文类添加DbSet属性完全相同

您应该能够通过使用访问动态实体的实体集

context.Set(LogRecType)
…将返回一个非泛型DbSet


我不知道这是否可行,也没有对它进行测试,但我有一些希望。

我怀疑EF只反映派生DbContext中的泛型DbSet属性,并在内存中创建模型时忽略任何非泛型DbSet属性

但是,另一种方法可能是在OnModelCreating中使用fluentapi将动态类型作为实体添加到模型中

首先,只有在首次加载AppDomain时在内存中构建模型时,才能向模型添加类型。每个AppDomain只构建一个模型。如果除了重载构造函数之外,您还有一个默认的上下文构造函数,并且使用这个默认构造函数创建和使用了一个上下文实例,那么您的模型将只使用静态类型构建,并且只要AppDomain存在,您就不能再使用动态类型作为实体。这将导致与您的情况完全相同的异常

另一个要考虑的问题是数据库模式的创建。如果您的类型在编译时未知,则数据库架构在编译时未知。如果在下一次运行应用程序时,模型因新类型而更改,则需要以某种方式更新数据库架构,方法是从头开始重新创建数据库,或者定义一个自定义数据库初始值设定项,该初始值设定项仅删除LogRec表,并根据LogRec类型的新布局创建一个新表。或者代码优先迁移可能会有所帮助

关于使用Fluent API的可能解决方案:

删除DbSet并将类型成员添加到上下文中,并重写OnModelCreating:

…它将与静态LogRec类型一起使用,这只会使EF知道该类型是实体。这与向上下文类添加DbSet属性完全相同

您应该能够通过使用访问动态实体的实体集

context.Set(LogRecType)
…将返回一个非泛型DbSet


我不知道这是否有效,也没有测试,但我有一些希望。

非常感谢。我以前看过罗文·米勒的建议,但可以说,你把它放在了正确的背景下。关于我的代码有一个默认构造函数,并且模型是在调用参数化构造函数之前构建的,您也说得对。我不知道如何克服这个问题,因为我的动态类型是dependent
t取决于实验数据集的值。它就像一步一步地构建模型:首先是实验,用户选择一个值来决定类型,然后是非泛型LogRec。有什么建议,线索吗?@user1707621:我有两个想法你可以试试:1.context.Database.Initializetrue;:参数true是强制初始化。我不确定这是否会在内存中重新创建模型,或者只运行DB初始化器。请再次查看intellisense中的描述。2您可以尝试使用两个不同的上下文类,一个没有LogRecType,另一个有LogRecType。两个上下文类应该在内存中产生两个模型。这都是非常困难和先进的东西。我建议,如果你被卡住了,你可以提出新的问题。非常感谢。我以前看过罗文·米勒的建议,但可以说,你把它放在了正确的背景下。关于我的代码有一个默认构造函数,并且模型是在调用参数化构造函数之前构建的,您也说得对。我不知道如何克服这个问题,因为我的动态类型依赖于来自Dbset的值。它就像一步一步地构建模型:首先是实验,用户选择一个值来决定类型,然后是非泛型LogRec。有什么建议,线索吗?@user1707621:我有两个想法你可以试试:1.context.Database.Initializetrue;:参数true是强制初始化。我不确定这是否会在内存中重新创建模型,或者只运行DB初始化器。请再次查看intellisense中的描述。2您可以尝试使用两个不同的上下文类,一个没有LogRecType,另一个有LogRecType。两个上下文类应该在内存中产生两个模型。这都是非常困难和先进的东西。我建议,如果你陷入困境,你可以提出新的问题。
modelBuilder.Entity<LogRec>();
context.Set(LogRecType)