【发布时间】: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 个视图,我不想逐个检查。
为什么这种行为发生了变化,我可以(全局)启用一个设置来纠正这个问题吗?
编辑:
所以根据答案,我已经能够收集到三种方法来防止这个问题。
- 将每个组成表中的所有主键值添加到视图中
- 在视图中使用
nullif()技巧来强制列不可为空,并由 EF 添加到键中 - 自己在模型中手动添加实体键
但这并不能真正解释为什么会发生这种情况,以及它怎么可能是期望的行为? 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