Entity Framework core 3.1.1 Многоуровневое наследование - PullRequest
2 голосов
/ 03 февраля 2020

Исключение выдается при выполнении надстройки (ядро EF 3.1.1):

Свойство CLR «DiscriminatorLevel2Id» нельзя добавить к типу сущности «CustomerBase», поскольку оно объявлено в CLR type 'InternalCustomer'

На следующем рисунке показана необходимая иерархия (кратко):

Class Diagram

Отображение выглядит следующим образом:

// Discriminator (Level 1)
modelBuilder.Entity<CustomerBase>()              
            .HasDiscriminator(b => b.CustomerTypeId)
            .HasValue<InternalCustomer>((int)CustomerType.Internal)
            .HasValue<ExternalCustomer>((int)CustomerType.External);

// Discriminator (Level 2)
modelBuilder.Entity<InternalCustomer>()
         .HasDiscriminator(b => b.DiscriminatorLevel2Id)
         .HasValue<VIPCustomer>((int)DiscriminatorLevel2.VIP)
         .HasValue<RegularCustomer>((int)DiscriminatorLevel2.Regular);

Поддерживается ли "Многоуровневое наследование TPH" в Entity Framework Core 3.1.1?

1 Ответ

3 голосов
/ 04 февраля 2020

Это возможно, но с одним общим дискриминатором на абстрактном уровне root, содержащим значения для всех возможных создаваемых (не абстрактных) прямых или косвенных производных сущностей.

Применение к вашему образцу требует удаления DiscriminatorLevel2 свойство (столбец), удаление Internal из CustomerType перечисления (при условии, что InternalCustomer является абстрактным) и объединение Regular и VIP в него, например, что-то вроде этого:

Модель:

public abstract class CustomerBase
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int CustomerTypeId { get; set; }
}

public abstract class InternalCustomer : CustomerBase
{
    public decimal Points { get; set; }
}

public class RegularCustomer : InternalCustomer
{
    public int PartnerId { get; set; }
}

public class VIPCustomer : InternalCustomer
{
    public string CardNo { get; set; }
}

public class ExternalCustomer : CustomerBase
{
}

public enum CustomerType { External, Regular, VIP }

Конфигурация:

modelBuilder.Entity<CustomerBase>()
    .HasDiscriminator(b => b.CustomerTypeId)
    .HasValue<ExternalCustomer>((int)CustomerType.External)
    .HasValue<VIPCustomer>((int)CustomerType.VIP)
    .HasValue<RegularCustomer>((int)CustomerType.Regular);

modelBuilder.Entity<InternalCustomer>();

Если вы хотите запросить InternalCustomer производные объекты, вы можете использовать db.Set<InternalCustomer>() или db.Set<CustomerBase>().OfType<InternalCustomer>() и EF Core применяет фильтр, аналогичный t.CustomerTypeId IN (1,2), т.е. предложение IN будет содержать список значений дискриминатора для всех конечных объектов, полученных из InternalCustomer.

...