EntitySet System.InvalidOperationException - “实体类型不是当前上下文模型的一部分”

时间:2012-11-29 21:12:42

标签: c# entity-framework dbcontext ef-model-first csdl

类似问题

The entity type <classname> is not part of the model for the current context - 和 - EF 4.1 Code First error - The entity type SomeType is not part of the model for the current context是类似的问题,但它们只是“代码优先”的视角,具有更简单的数据模型,并解决连接字符串和映射问题。请仔细看看这个。

症状

// HomeController.cs
public ActionResult Index()
{
    var _db = new MealsContext();

    var m = _db.Meals.ToList();
    var d = _db.Drinks.ToList();

    return View();
}

检索Drinks集合时会抛出异常:

The entity type Drink is not part of the model for the current context.

代码

// Meal.cs
public class Meal
{
    public int Id { get; set; }
    public string Stuff { get; set; }
    public virtual ICollection<Meat> Meats { get; set; }
    public virtual ICollection<Vegetable> Vegetables { get; set; }
}

// Meat.cs
public class Meat
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int MealId { get; set; }
}

// Vegetable.cs
public class Vegetable 
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int MealId { get; set; }
}

// Drink.cs
public class Drink
{
    public int Id { get; set; }
    public string Name { get; set; }
}

是的,我知道在现实世界中,肉类和蔬菜与膳食之间的关系可能是多对多的,但不要挂在这里。

// MealsContext.cs
public class MealsContext: DbContext
{               
    public MealsContext() : base("ConnectionString")

    public DbSet<Meal> Meals{ get; set; }
    public DbSet<Meat> Meats{ get; set; }
    public DbSet<Vegetable> Vegetables { get; set; }
    public DbSet<Drink> Drinks{ get; set; }
}

我的经验是使用Model First方法。 EDMX文件是在POCO之后构建的。

在连接字符串中是映射到已解析的EDMX资源(metadata=res://*/Models.MealsModels.csdl|res://*/Models.MealsModels.ssdl|res://*/Models.MealsModels.msl;)的元数据部分。

我检查了EDMX文件的基础XML,显示了Conceptual和Store模型中的所有实体,并且所有实体都已完全映射。 WTF?

疑难解答

首先尝试完全摆脱商店并映射EDMX数据(SSDLMSL部分)。消防,现在有两个例外:

  1. 检索Meals投掷MSL, error 2062 No mapping specified for instance of the EntitySet and AssociationSet in the EntityContainer

  2. 检索Drinks继续抛出The entity type Drinkis not part of the model for the current context

  3. Meals引发的错误是预期的,我修改了映射和商店模型 - 检查_db向我显示Meals - &gt; InternalSet - &gt; EntitySet属性是正确的,只是没有映射。

    Drinks引发的错误是我被困住的地方。仔细检查_db会告诉我Drinks - &gt; InternalSet - &gt; EntitySet抛出SystemInvalidOperation异常,表明实体不在模型上下文中。

    这是EDMX的CSDL在XML格式中的样子:

    <edmx:ConceptualModels>
      <Schema ...>
        <EntityContainer Name="MealsContext" annotation:LazyLoadingEnabled="true">
          <EntitySet Name="Meals" EntityType="Models.Meal" />
          <EntitySet Name="Meats" EntityType="Models.Meat" />
          <EntitySet Name="Vegetables" EntityType="Models.Vegetable" />
          <EntitySet Name="Drinks" EntityType="Models.Drink" />
          <!-- AssociationSets here for the FKs -->
        </EntityContainer>
        <!-- All are present, but here's the culprit Drink -->
        <EntityType Name="Drink">
          <Key>
            <PropertyRef Name="Id" />
          </Key>
          <Property Type="Int32" Name="Id" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
          <Property Type="String" Name="Name" Nullable="false" MaxLength="200" FixedLength="false" Unicode="true" />
        </EntityType>
        <!-- Associations here -->
      </Schema>
    </edmx:ConceptualModels>
    

    问题

    如果DbContext具有所有DbSet属性,并且正在使用连接字符串,其中包含CSDL正确定义实体类型Drink的模型的元数据, 为什么在地狱中它不是上下文的一部分?

    我可以看到Drink唯一不同的是它与任何其他实体无关,并且没有关联...

2 个答案:

答案 0 :(得分:4)

解决。

上半场是我的疏忽。下半场......好吧,我没说错。这不是一个真正的错误或不兼容,但非常不方便,间歇性和难以弄清楚。首先是摘要,然后是那些关心的人的长度解释:

尽管存在错误消息建议,但它不是概念模型(CSDL)的问题,而是间歇性地重新创建自身的列映射问题。

使用EdmxWriter构建概念模型来解析DbContext及其基础部分。

然后,该模型用于生成SQL脚本以将架构推送到新数据库。诀窍是,数据库是Oracle。

Oracle是一个婴儿,不接受长列名称。因此,必须修改生成的EDMX和SQL脚本,以构建概念模型的部分并将其映射为截断的列名。

没什么大不了的。它工作正常。那么事情出了什么问题?

Oracle不支持“代码优先”。即使它是手动完成的,使用EdmxWriter构成了Oracle眼中的代码优先方法。因此,当解析第一个EDMX模式时,它就是关于布尔映射的。解决方案是暂时从我的C#模型中删除bool,手动将它们添加到EDMX并进行Oracle建议的web.config映射(将bool映射到NUMBER(1,0))。

一切都很时髦。但为什么它会不断重演?

在整个开发过程的不同时间,协议的某些目标 - C#,EDMX或Oracle - 都会被更改。每次,似乎列都被自动重新映射,我不知道。如果从Oracle刷新EDMX模型,则映射指向不存在的C#属性(短列名称)。如果从C#代码刷新模型,则不会保留映射,并且它们会尝试映射到Oracle中不存在的长列名称。

采用这种方法(首先是混合代码,首先是模型)的糟糕表现是,如果我想继续管理我自己的模型并处理Oracle小宝贝态度所必需的自定义,我必须非常小心并监控EDMX文件的内容。

答案 1 :(得分:0)

您需要为实体指定映射:

public class MealsContext: DbContext
{               
    public MealsContext() : base("ConnectionString")

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // mappings 
    }    

    public DbSet<Meal> Meals{ get; set; }
    public DbSet<Meat> Meats{ get; set; }
    public DbSet<Vegetable> Vegetables { get; set; }
    public DbSet<Drink> Drinks{ get; set; }
}

在我开始使用Entity Framework Power Tools

之前,我遇到了同样的问题

使用它可以生成明确的实体,如业务对象和映射类。 帮助我创建出色的数据访问层的好文章:Reverse Engineer Code First