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

one*_*mer 6 c# entity-framework csdl dbcontext ef-model-first

类似的问题

实体类型<classname>不是当前上下文的模型的一部分 - 并且 - EF 4.1 Code First错误 - 实体类型SomeType不是当前上下文的模型的一部分是类似的问题但它们是"代码优先"透视只有更简单的数据模型,并解决连接字符串和映射问题.请仔细看看这个.

症状

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

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

    return View();
}
Run Code Online (Sandbox Code Playgroud)

抛出异常会检索Drinks集合:

The entity type Drink is not part of the model for the current context.
Run Code Online (Sandbox Code Playgroud)

// 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; }
}
Run Code Online (Sandbox Code Playgroud)

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

// 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; }
}
Run Code Online (Sandbox Code Playgroud)

我的经验是使用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.

抛出的错误Meals是预期的,我修改了映射和存储模型 - 检查_db显示我Meals- > InternalSet- > EntitySet属性是正确的,只是没有映射.

抛出的错误Drinks是我被困住的地方.检查_db更接近显示我Drinks- > InternalSet- > 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>
Run Code Online (Sandbox Code Playgroud)

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

Drink我能看到的唯一不同之处在于它与任何其他实体无关,并且没有关联......

one*_*mer 4

解决了。

前半部分是我的疏忽。下半场……好吧,我不知道哪里出了问题。这并不是真正的错误或不兼容,而是非常不方便、间歇性且难以弄清楚的东西。首先是摘要,然后是对关心的人的长度解释:

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

概念模型是使用 来EdmxWriter解析DbContext及其底层部分构建的。

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

Oracle 还处于起步阶段,不接受长列名。因此,必须修改生成的 EDMX 和 SQL 脚本,以构建部分概念模型并将其映射到截断的列名称。

没什么大不了的。效果很好。那么到底哪里出了问题呢?

Oracle 不支持“代码优先”。尽管它是手动完成的,但EdmxWriter在 Oracle 看来,使用它构成了代码优先的方法。因此,当解析第一个 EDMX 模式时,它会抱怨布尔映射。解决方案是暂时从我的 C# 模型中删除布尔值,手动将它们添加到 EDMX 并进行 Oracle 建议的 web.config 映射(映射boolNUMBER(1,0))。

一切又变得时髦了。但为何屡屡发生?

在整个开发过程的不同时间,协议的某些部分(C#、EDMX 或 Oracle)会发生变化。每次,似乎列都会自动重新映射,而我却没有意识到。如果从 Oracle 刷新 EDMX 模型,映射将指向不存在的 C# 属性(短列名称)。如果从 C# 代码刷新模型,则不会保留映射,并且它们会尝试映射到 Oracle 中不存在的长列名称。

这种方法(有点混合代码优先和模型优先)的缺点是,如果我想继续管理自己的模型并处理 Oracle 小婴儿态度所需的自定义,我必须非常小心并监控 EDMX 文件。