Возможно ли использование нескольких индексов с помощью HasColumnAnnotation?

#c# #entity-framework #ef-code-first #ef-fluent-api

#c# #entity-framework #ef-code-first #ef-fluent-api

Вопрос:

Похоже, что в Entity Framework 6.1 они добавили возможность создавать индексы таблиц с помощью нового HasColumnAnnotation метода. Я создал несколько вспомогательных расширений для ускорения процесса:

 public static class MappingExtensions
{
    public static StringPropertyConfiguration HasIndex(this StringPropertyConfiguration config, bool isUnique = false)
    {
        return config.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute() { IsUnique = isUnique }));
    }
    public static StringPropertyConfiguration HasIndex(this StringPropertyConfiguration config, string name, int order = 1, bool isUnique = false)
    {
        return config.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute(name, order) { IsUnique = isUnique }));
    }
    public static PrimitivePropertyConfiguration HasIndex(this PrimitivePropertyConfiguration config, bool isUnique = false)
    {
        return config.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute() { IsUnique = isUnique }));
    }
    public static PrimitivePropertyConfiguration HasIndex(this PrimitivePropertyConfiguration config, string name, int order = 1, bool isUnique = false)
    {
        return config.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute(name, order) { IsUnique = isUnique }));
    }
}
  

Это работает фантастически … пока я не попытаюсь создать второй индекс, содержащий столбец, уже используемый в другом индексе. Все, что я добавляю последним, перезаписывает оригинал. Кто-нибудь знает, возможно ли в настоящее время добавить несколько индексов в один и тот же столбец с помощью нового HasColumnAnnotation , доступного в StringPropertyConfiguration and PrimitivePropertyConfiguration ?

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


После обратной связи Gerts это то, что я в итоге сделал:

 public static class MappingExtensions
{
    public static StringPropertyConfiguration HasIndex(this StringPropertyConfiguration config, params IndexAttribute[] indexes)
    {
        return config.HasColumnAnnotation("Index", new IndexAnnotation(indexes));
    }

    public static PrimitivePropertyConfiguration HasIndex(this PrimitivePropertyConfiguration config, params IndexAttribute[] indexes)
    {
        return config.HasColumnAnnotation("Index", new IndexAnnotation(indexes));
    }
}
  

И вот новое использование:

 Property(x => x.Name).IsRequired().HasMaxLength(65).HasIndex(new IndexAttribute("IX_Countries_Name") { IsUnique = true }, new IndexAttribute("IX_Countries_Published", 2))
  

Ответ №1:

Это связано с тем, что каждый из ваших методов расширения присваивает свойству новую аннотацию и перезаписывает предыдущую. Позвольте мне показать это, используя ваши методы на примере.

Допустим, у нас есть этот (бесполезный) класс

 public class Client
{
    public int ClientId { get; set; }
    public int CompanyId { get; set; }
    public int AddressId { get; set; }
}
  

И примените свои определения индексов (пропуская часть modelBuilder.Entity<Client>() ):

 .Property(c => c.ClientId).HasIndex("ClientCompanyIndex");
.Property(c => c.CompanyId).HasIndex("ClientCompanyIndex", 2);
.Property(c => c.ClientId).HasIndex("ClientAddressIndex");
.Property(c => c.AddressId).HasIndex("ClientAddressIndex", 2);
  

Встраивание методов расширения (слава Богу, для Resharper) приводит к

 .Property(c => c.ClientId).HasColumnAnnotation("Index",
    new IndexAnnotation(new IndexAttribute("ClientCompanyIndex", 1));
.Property(c => c.CompanyId).HasColumnAnnotation("Index",
     new IndexAnnotation(new IndexAttribute("ClientCompanyIndex", 2));
.Property(c => c.ClientId).HasColumnAnnotation("Index",
    new IndexAnnotation(new IndexAttribute("ClientAddressIndex", 1));
.Property(c => c.AddressId).HasColumnAnnotation("Index",
     new IndexAnnotation(new IndexAttribute("ClientAddressIndex", 2));
  

Это то же самое, что и запись

 [Index("ClientCompanyIndex", Order = 1)]
public int ClientId { get; set; }
  

а затем заменить его на

 [Index("ClientAddressIndex", Order = 1)]
public int ClientId { get; set; }
  

Чтобы воспроизвести правильную аннотацию…

 [Index("ClientAddressIndex", IsUnique = true, Order = 1)]
[Index("ClientCompanyIndex", IsUnique = true, Order = 1)]
public int ClientId { get; set; }
[Index("ClientCompanyIndex", IsUnique = true, Order = 2)]
public int CompanyId { get; set; }
[Index("ClientAddressIndex", IsUnique = true, Order = 2)]
public int AddressId { get; set; }
  

… конфигурация ClientId свойства должна выглядеть следующим образом

 .Property(c => c.ClientId).HasColumnAnnotation("Index",
    new IndexAnnotation(new[]
        {
            new IndexAttribute("ClientCompanyIndex", 1),
            new IndexAttribute("ClientAddressIndex", 1)
        }));
  

Теперь внезапно создание методов расширения становится гораздо менее привлекательным. Вряд ли стоит прилагать усилия для создания такой объединенной аннотации. Но для одноразовых столбцов ваши методы являются улучшением.

Конечно, понятно, почему вы пытаетесь это сделать. Текущий беглый синтаксис, мягко говоря, неуклюж. Команда EF прекрасно это знает, и они надеются, что кто-нибудь из участников вскоре решит эту проблему. Может быть, что-нибудь для вас?

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

1. Спасибо, Герт. Я как бы подумал, что это может быть то, что происходит. Ваш последний пример показывает мне, что мне нужно делать дальше. Я, вероятно, настрою свой вспомогательный класс на accept params IndexAttribute[] indexes , чтобы я мог передавать несколько индексов для каждого свойства. В вопрос добавлен новый код.

2. 1. В вашем последнем фрагменте примера кода вы пропустили IsUnique атрибут, он должен был быть new IndexAttribute("ClientCompanyIndex", 1) { IsUnique = true } и new IndexAttribute("ClientAddressIndex", 1) { IsUnique = true } .