Как создать некластеризованный индекс для вычисляемого столбца в Entity Framework?

#c# #entity-framework

#c# #entity-framework

Вопрос:

Я вычисляю значение столбца из другого столбца, и мне нужно создать некластеризованный индекс для вычисляемого столбца.

Когда я пытаюсь указать индекс для вычисляемого столбца с помощью Entity Framework, система выдает исключение

В Microsoft произошло исключение типа ‘System.Data.SqlClient.SQLException’.EntityFrameworkCore.Relational.dll, но не был обработан в пользовательском коде

Дополнительная информация: Отфильтрованный индекс ‘UK_ProdBarCode_BarCodeNumber’ не может быть создан в таблице ‘ProdBarCode’, поскольку столбец ‘BarCodeNumber’ в выражении фильтра является вычисляемым столбцом. Перепишите выражение фильтра так, чтобы оно не включало этот столбец.

 prodbarcode.Property<long>(ProdBarCode => 
       ProdBarCode.BarCodeNumber).HasComputedColumnSql("CAST(BarCode AS Bigint)");

prodbarcode.HasIndex(ProdBarCode => 
       new { ProdBarCode.BarCodeNumber })
      .HasName("UK_ProdBarCode_BarCodeNumber")
      .IsUnique(true)
      .ForSqlServerIsClustered(false);
  

Комментарии:

1. «К сожалению, начиная с SQL Server 2014, нет возможности создать отфильтрованный индекс, где фильтр находится в вычисляемом столбце (независимо от того, сохранен он или нет)». Не удается создать отфильтрованный индекс для вычисляемого столбца

2. Да, невозможно создать отфильтрованный индекс для вычисляемого столбца, но, вероятно, уместен вопрос: почему EF пытается создать отфильтрованный индекс? Я не вижу в этом определении ничего, что включало бы фильтр, и создание уникального индекса для вычисляемого столбца в противном случае работает нормально (например, CREATE TABLE #a(BarCode INT, BarCodeNumber AS CAST(BarCode AS BIGINT)); CREATE UNIQUE INDEX IX_#a_ProdBarCode ON #a(BarCodeNumber); ; добавить WHERE BarCodeNumber IS NOT NULL , чтобы получить ошибку).

Ответ №1:

Сегодня я столкнулся с этой проблемой. К сожалению, я не смог найти никакой информации об этом в Entity Framework или Microsoft. Тем не менее, я нашел обходной путь для моей ситуации.

Если вы добавите фильтр самостоятельно и настроите исходный столбец или колонки, он должен достичь того же эффекта, и это допустимый SQL. Смотрите обновленный код ниже…

 prodbarcode.Property<long>(ProdBarCode => 
       ProdBarCode.BarCodeNumber)
       .HasComputedColumnSql("CAST(BarCode AS Bigint)");

prodbarcode.HasIndex(ProdBarCode => 
       new { ProdBarCode.BarCodeNumber })
      .HasName("UK_ProdBarCode_BarCodeNumber")
      .IsUnique(true)
      .HasFilter($"{nameof(ProdBarCode.BarCode)} IS NOT NULL") // <-- filter on source field
      .ForSqlServerIsClustered(false);