一位朋友报告了计算列,实体框架和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表定义的相关部分:
CREATE TABLE [dbo].[Person]( [ID] [bigint] IDENTITY(1,1) NOT NULL, [FirstName] [varchar](100) NULL, [MiddleName] [varchar](100) NULL, [LastName] [varchar](100) NOT NULL, [FullName] AS ((([Patient].[LastName]+',') + isnull(' '+[Patient].[FirstName],'')) + isnull(' '+[Patient].[MiddleName],'')), ...
我的朋友告诉我相应的“Code First”类看起来像这样:
public class Person { public int ID {get; set;} public string FirstName {get; set;} public string MiddleName {get; set;} public string LastName {get; set;} public string FullName {get; set;} ... }
这个问题的答案解释了问题并提供了解决方案。
答案 0 :(得分:1)
每个看着这个的人都想知道为什么有一个FullName
的计算列,其次,为什么这个属性会暴露给客户端。
让我们假设计算列有一个很好的理由,这是模型从表中获取值而不是计算值本身的一个很好的理由,并且有充分的理由将其发送到客户端而不是客户计算它。以下是他告诉我的事情;
“我们需要在查询中包含
FullName
”
生活有时会以这种方式运作。
请注意,FullName
属性具有公共设置器。 Person
类的EF元数据生成器无法判断这是否为只读属性。 FullName
看起来就像LastName
。元数据说“这是正常的读/写属性。”
微风也没有看到任何区别。客户端应用可能不会触及此属性,但Breeze必须在创建新Person
时为其发送值。回到服务器上,Breeze EFContextProvider
认为它应该在创建EF实体时传递该值。舞台是为灾难而设的。
如果(a)您无法更改表格并且(b)您无法更改模型的FullName
属性定义,您可以做什么?
EF需要你的帮助。你应该告诉EF这实际上是一个数据库计算属性。您可以使用EF流利界面或使用如下所示的属性:
[DatabaseGenerated(DatabaseGeneratedOption.Computed)] public String FullName { get; set; }
添加此属性,EF知道此属性是只读的。它将生成适当的元数据,您可以干净地保存新的Person
。省略它,你会得到例外。
请注意,这仅适用于Code First。如果他生成模型Database First,则EF知道该列是计算的,并且不会尝试设置它。
请注意存储生成密钥的类似问题。整数键的默认值是“存储生成的”,但Guid键的默认值是“客户端生成的”。如果在您的表中,数据库实际设置了Guid,则必须使用[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
标记ID
属性