【问题标题】:Entity Framework - entity using a view giving duplicate data实体框架 - 使用视图提供重复数据的实体
【发布时间】:2014-04-23 09:12:03
【问题描述】:

我有以下观点(如果重要,SQL Server 2012):

SELECT
 EntityId
,EntityType
,StateId
FROM
 SomeTable 
 INNER JOIN SomeOtherTable

当我为此视图(EF 6 - 数据库优先)生成实体时,它在 EDMX 文件中如下所示:

<EntityType Name="VW_MyView">
   <Key>
      <PropertyRef Name="EntityId" />
      <PropertyRef Name="EntityType" />
   </Key>
   <Property Name="EntityId" Type="Int32" Nullable="false" />
   <Property Name="EntityType" Type="String" Nullable="false" MaxLength="2" FixedLength="false" Unicode="false" />
   <Property Name="StateId" Type="Int32" />
</EntityType>

如您所见,模型生成器在前两列创建了一个实体键。问题是,前两列不保证唯一性。

例如,我可以在视图中拥有这样的数据:

EntityId   EntityType   StateId
--------   ----------   -------
1234       CR           1
1234       CR           2
1234       CR           3

当我使用 linq 查询数据时,例如:

using (ContextA context = new ContextA())
{
    var zList = context.VW_MyView.Where(f => f.EntityId == 1234 
                                    && f.EntityType == "CR").ToList();
}

我得到一个包含三个项目的列表,但是像这样(通知 stateid 重复):

EntityId   EntityType   StateId
--------   ----------   -------
1234       CR           1 <-- dupe
1234       CR           1 <-- dupe
1234       CR           1 <-- dupe

我将完全相同的代码从 EF 4(对象上下文模板)迁移到 EF 6(dbcontext 模板),但在迁移之前它并没有像这样执行。

我知道我可以手动将 EntityKey 添加到 StateId 列,它会正常工作,但我的模型中有超过 100 个视图,我不想逐个检查。

为什么这种行为发生了变化,我可以(全局)启用一个设置来纠正这个问题吗?

编辑:

所以根据答案,我已经能够收集到三种方法来防止这个问题。

  1. 将每个组成表中的所有主键值添加到视图中
  2. 在视图中使用 nullif() 技巧来强制列不可为空,并由 EF 添加到键中
  3. 自己在模型中手动添加实体键

但这并不能真正解释为什么会发生这种情况,以及它怎么可能是期望的行为? EF linq 查询只是返回完全不正确的数据,没有任何异常或警告。我无法想象这是正确的。

【问题讨论】:

  • 在 T-SQL 中运行相同的查询是否提供相同的 3 个结果?
  • StateId 是否为空?设计器没有将 StateId 属性作为键的一部分,因为它被标记为可为空。如果它实际上不可为空,您可以在 edmx 中作弊并将其标记为不可为空并包含为密钥。此外,如果您包含 StateId 属性 - 它会使复合键始终唯一吗?
  • @mxmissile - 在 SQL 中运行查询会返回正确的结果(stateid 为 1、2 和 3)。
  • @Pawel - StateId 永远不会为空。我不介意它是否没有将其标记为键,我只是看不出 EF 在这种情况下返回带有“错误”数据的 3 行是如何正确的。
  • EF 创建的查询是什么样的?对 SQL Server 执行查询时的结果是什么?最后是否需要视图定义中的 INNER JOIN 以及它如何影响结果?

标签: entity-framework sql-server-2012 entity-framework-6 sql-view


【解决方案1】:

我在 EF4 中有同样的“问题”(使用 ObjectContext 数据库优先方法的 .edmx 文件) - 不知道为什么它对你有用。

对于实体框架,如果它没有指定的主键(例如在表上),它将回退到使用该对象的所有 non-nullable 列(此处:您的视图) 作为其复合 PK。

这些不可为空的列现在是表/视图的键,因此,该键只能存在一个值。

为了解决这个问题,您需要在视图中包含更多列以使自动检测到的键真正唯一(例如通过包含所有基础基表的主键),或者您需要手动设置键适合适合你的东西。

【讨论】:

  • 所以我认为没有批发方法可以防止这种情况发生?我必须去每个实体/视图并单独更正?
【解决方案2】:

我找到的另一个解决方案是将实体的 MergeOption 设置为 NoTracking。

 using (ContextA context = new ContextA())
{
  context.VW_MyView.MergeOption = System.Data.Objects.MergeOption.NoTracking;
  //Rest code goes here...
}

在这个thread找到解决方案

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-26
    • 1970-01-01
    • 2011-12-06
    • 1970-01-01
    相关资源
    最近更新 更多