首页 文章

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

提问于
浏览
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表定义的相关部分:

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 回答

  • 1

    设计问题

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

    让我们假设计算列有一个很好的理由,这是模型从表中获取值而不是计算值本身的一个很好的理由,并且有充分的理由将它发送到客户端而不是让客户端计算它 . 以下是他告诉我的事情;

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

    生活有时会以这种方式运作 .

    后果

    请注意, FullName 属性具有公共setter . Person 类的EF元数据生成器无法判断这是否为只读属性 . FullName 看起来就像 LastName . 元数据说"this is normal read/write property."

    微风也没有看到任何区别 . 客户端应用程序可能不会触及此属性,但Breeze必须在创建新的 Person 时为其发送值 . 回到服务器上,Breeze EFContextProvider 认为它应该在创建EF实体时传递该值 . 舞台是为灾难而设的 .

    如果(a)你可以改变模型的 FullName 属性定义,你能做什么?

    解决方案

    EF需要你的帮助 . 你应该告诉EF这实际上是一个数据库计算属性 . 您可以使用EF流利界面或使用如下所示的属性:

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public String FullName { get; set; }
    

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

    请注意,这仅适用于Code First . 如果他生成模型Database First,则EF知道该列已计算,并且不会尝试设置该列 .

    请注意存储生成密钥的类似问题 . 整数键的默认值为"store-generated",但Guid键的默认值为"client generated" . 如果在您的表中,数据库实际设置了Guid,则必须使用[DatabaseGenerated(DatabaseGeneratedOption.Identity)]标记 ID 属性

相关问题