0

一位朋友报告了计算列、实体框架和 Breeze 的问题

我们有一个表,其中包含由数据库计算的“FullName”列。创建新的Person时,Breeze 将FullName属性值发送到服务器,即使它根本没有设置,并且在尝试插入新Person实例时会触发错误。数据库抛出此异常:

The column "FullName" cannot be modified because it is either a computed column or is the result of a UNION operator.

下面是 SQL 表定义的相关部分:

创建表 [dbo].[Person](
      [ID] [bigint] IDENTITY(1,1) 非空,
      [名字] [varchar](100) 空值,
      [中间名] [varchar](100) NULL,
      [姓氏] [varchar](100) 非空,
      [FullName] AS ((([Patient].[LastName]+',') + isnull(' '+[Patient].[FirstName],'')) + isnull(' '+[Patient].[MiddleName] ,'')),
      ...

我的朋友告诉我相应的“代码优先”类看起来像这样:

公共类人{
      公共 int ID {get; 放;}
      公共字符串名字 {get; 放;}
      公共字符串 MiddleName {get; 放;}
      公共字符串姓氏{get; 放;}
      公共字符串 FullName {get; 放;}
      ...
}

这个问题的答案解释了问题并提供了解决方案。

4

1 回答 1

1

设计问题

看到这个的每个人都想知道为什么会有一个计算列FullName,其次,为什么这个属性会暴露给客户端。

让我们假设计算列有充分的理由,模型有充分的理由从表中获取值而不是计算值本身,并且有充分的理由将其发送给客户端而不是让客户端计算它. 这是他告诉我的;

“我们需要FullName在查询中包含”

生活有时会这样。

结果

请注意,该FullName属性有一个公共设置器。该类的 EF 元数据生成器Person无法判断这是一个只读属性。FullName看起来就像LastName。元数据说“这是正常的读/写属性”。

Breeze也看不出有什么不同。客户端应用程序可能不会触及此属性,但 Breeze 在创建新的Person. 回到服务器上,BreezeEFContextProvider认为它应该在创建 EF 实体时传递该值。舞台已经为灾难做好了准备。

如果 (a) 您无法更改表格并且 (b) 您无法更改模型的FullName属性定义,您该怎么办?

一个解法

英孚需要你的帮助。您应该告诉 EF 这实际上是一个数据库计算属性。您可以使用 EF fluent 接口或使用如下所示的属性:

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
公共字符串全名 { 获取;放; }

添加此属性,EF 知道此属性是只读的。它将生成适当的元数据,您可以Person干净地保存新的元数据。省略它,你会得到异常。

请注意,这仅对 Code First 是必需的。如果他首先生成了模型 Database First,则 EF 知道该列已计算并且不会尝试设置它。

请注意与商店生成的密钥类似的问题。整数键的默认值是“存储生成的”,但 Guid 键的默认值是“客户端生成的”。如果在您的表中,数据库实际上设置了 Guid,则必须ID使用 [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 标记该属性

于 2013-04-06T03:56:36.253 回答