首页 > 解决方案 > 在 EntityFramework Core + npgsql 中填充新添加的计算列

问题描述

我在数据库表中添加了一列,该列是根据其他列的值计算得出的。它永远不会直接设置,而是在更新这些列时更新。

我在没有任何原始 SQL 的模型类中实现了这一点,并且它在一个问题上运行良好:我希望迁移在应用时为所有行填充此列,而不必等待每个字段在更改后手动更新.

该模型的简化示例如下:

public class MyModel 
{
  private string _title;
  private string _description;
  private string _data;

  public string Title
  {
    get 
    {
      return _title;
    }
    set
    {
      _title = value;
      UpdateCombinedField(value, _description, _data);
    }
  }

  public string Description
  {
    get 
    {
      return _description;
    }
    set
    {
      _description = value;
      UpdateCombinedField(_title, value, _data);
    }
  }

  [Column(TypeName = "jsonb")]
  public string Data
  {
    get
    {
      return _data;
    }
    set
    {
      _data = value;
      UpdateCombinedField(_title, _description, _value);
    }
  }

  public string CombinedField { get; set; }

  public void UpdateCombinedField(title, description)
  {
    // some logic here extracts string values from json e.g. { k1: 'v1', k2: 'v2' } -> 'v1 v2'
    CombinedField = title + " " + description + " " + extractedJsonValues;
  }
}

这个想法是创建一个可以搜索的单个文本字段 - 不幸的是,由于 jsonb 的二进制性质, npgsql SearchVector 选项不起作用。因此,改为UpdateCombinedField创建该字段的字符串,该字符串可以与其他字符串字段连接到CombinedField.

正如我所说,这工作正常,问题是在CombinedField应用迁移时填充。

我尝试在 Migration 的方法中使用以下内容,该Up方法改编自上面的 SearchVector 指南,用于更新表:

migrationBuilder.Sql("UPDATE \"MyModels\" SET \"Title\" = \"Title\";");

但是我不确定如何设置触发上述代码工作的触发器,而不必将计算组合列的代码从类中取出并放入 SQL - 因此再次遇到 jsonb 二进制问题。

我们正在使用 postgresql 10。

总结一下需求,需要将文本列和 jsonb 列中的值组合到一个文本列中,当首次应用迁移时,该列也适用于现有行。此列是 Tsvector 是一个奖励,但不是必需的。

标签: c#postgresqlentity-framework-corenpgsql

解决方案


很难准确地理解你在做什么。

PostgreSQL 10 不支持计算列,尽管 PostgreSQL 12 附带了此功能 - 请参阅此问题以及. 此功能可能对您想要的非常有用。

在任何情况下,您都可以有一个文本列,其中包含 jsonb 列的文本副本(通过触发器更新),然后可以在 tsvector 列中使用。但是,JSON 数据确实不是文本,对其进行全文搜索可能无法如您所愿。

migrationBuilder.Sql("UPDATE \"MyModels\" SET \"Title\" = \"Title\";");

您是否按照文档页面中的说明设置了触发器?此代码仅用于使触发器在创建后第一次运行。


推荐阅读