【问题标题】:How should I access a computed column in Entity Framework Code First?我应该如何访问 Entity Framework Code First 中的计算列?
【发布时间】:2011-08-04 16:16:57
【问题描述】:

我在我的 ASP.NET MVC 应用程序中首先使用实体​​框架代码。我的一门课有几列加在一起。我通过在数据库初始化程序中运行更改表脚本将这些列存储为表中的计算列。假设这个类看起来像:

public class Bond
{
        public decimal ParAmountOfIssuance { get; set; }
        public decimal AccruedInterest { get; set; }
        public decimal Premium { get; set; }
        public decimal OriginalIssueDiscount { get; set; }
}

修改脚本类似于:

alter table Bonds
add TotalSources as (ParAmountOfIssuance + AccruedInterest + Premium - OriginalIssueDiscount)

我希望Total Sources 列可以在网络应用程序中查看。实现这一目标的最佳方法是什么? [DatabaseGenerated(DatabaseGeneratedOption.Computed)] 属性不起作用,因为 EF Code First 在运行 alter 脚本之前从类创建表。

欢迎提出任何建议。

【问题讨论】:

  • 你不能使用 [NotMapped] 并在代码中计算它吗?这种方式并不是“代码优先”。为什么需要更改脚本中的架构?
  • 恐怕您已经找到的是最终结果:不可能让 EF 创建具有计算列的数据库(除了时间戳或行版本属性)。但是您必须Computed 属性放在属性上,以便让EF 正确处理计算列(只读取,不写入)。结果是它仅适用于映射到现有数据库,但不适用于 EF Code-First 创建的数据库。另请参阅此处:msdn.microsoft.com/en-us/library/gg193958.aspx 在“DatabaseGenerated”部分的第 2 段中。
  • @obrad,我不想在代码中执行计算,因为我不确定我的应用程序是唯一会更改列值的应用程序。 alter 脚本创建计算列。也就是说,除非你问我是否应该在编辑/查看数据时在代码中执行计算,这就是我目前正在做的事情。这似乎不是最好的做法。
  • @robert-s 如果您需要在数据库中包含一些逻辑,那么如果您接受权衡,那就可以了。如果您使用 CodeFirst 并生成数据库,这意味着您的数据库取决于您的应用程序。但是,如果您不确定是否必须在多个应用程序中使用数据库,那么权衡是 CodeFirst。如果您使用 CodeFirst,那么您应该完全不了解数据库,它是抽象的,如果您需要共享数据,则可以选择 odata 或其他服务。由于在当前版本的 CF 中没有脚本就无法做到这一点,这意味着 CF 不支持它:S
  • 如果您使用 [DatabaseGenerated(DatabaseGeneratedOption.Computed)] 或 [DatabaseGenerated(DatabaseGeneratedOption.None)] 属性,然后从脚本中仅使用公式更改此列怎么办?这样 CF 就不会写入该字段,您将能够读取它。这种方式与使用现有数据库没有什么不同,并且是受支持的。

标签: c# entity-framework ef-code-first


【解决方案1】:

我有一个解决方法。

您只能在现有数据库上使用计算字段。

如果您将属性添加到 CF 对象:

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public decimal TotalSources { get; set; }

如果您在脚本中添加一行将删除有关该数据库生成的信息:

DELETE FROM [dbo].[EdmMetadata]

CF 会假设它是现有的数据库并且它会工作,我刚刚尝试过。

更新我忘记了,如果您像这样向您的 Bond 实体添加属性,那么在您的脚本中您需要更改它以使其计算,而不是添加它:) 您甚至可以手动“同步”数据库和模型 - 在没有此字段的情况下您可以让一切正常工作,将其添加到模型中作为计算,并在表中作为计算。当您从 edm 元数据表中删除哈希时,CF 将正常工作,而无需尝试使用数据库重新生成模型。

【讨论】:

    【解决方案2】:

    这是definitely not supported - 在自定义属性上定义Computed 选项将引发异常。代码优先 = 代码中的逻辑。如果您需要自定义计算属性,请先使用数据库。代码优先支持的唯一数据库逻辑是标识列和时间戳。

    问题是您需要将该列标记为已计算,但创建数据库不允许这样做。如果该列未标记为已计算,它将是可更新的 = EF 将生成更新语句尝试更新该列,这将在数据库中失败。

    【讨论】:

      【解决方案3】:

      我正在像这样在 CF (WinForms) 中做计算列(我不知道这是否是最好的):

      这是一个实体:

      public class Result
      {
          public int ResultId { get; set; }
          public int StudentId { get; set; }
          public Student Student { get; set; }
          public float Arabic { get; set; }
          public float English { get; set; }
          public float Math { get; set; }
          public float Science { get; set; }
          public float Total { get; set; }
      }
      

      这是Form2:

          private void Form2_Load(object sender, EventArgs e)
          {
              Model1 model = new Model1();//Model1 : DbContext
              model.Database.CreateIfNotExists();
              model.Database.ExecuteSqlCommand("alter table Results drop column Total; alter table Results add Total AS (Arabic + English + Math + Science)");
      
              var r1 = (from s in model.Students
                        join r in model.Results
                        on s.StudentId equals r.StudentId
                        select new { s.StudentName, r.Arabic, r.English, r.Science, r.Math, r.Total }).ToList();
              dataGridView1.DataSource = r1;
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-01
        • 2023-04-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-03
        相关资源
        最近更新 更多