Breeze正在尝试更新计算数据库列

时间:2013-04-06 03:56:36

标签: entity-framework breeze

一位朋友报告了计算列,实体框架和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;}
      ...
}

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

1 个答案:

答案 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属性