Многоуровневое наследование с TPT дает неправильный класс - PullRequest
0 голосов
/ 31 августа 2018

У меня проблема с запросом, сгенерированным Entity Framework 6

Мы используем модель TPT (таблица на тип), у нас есть вложенное наследование 3-го уровня, и похоже, что EF6 теряется при запросе 3-го уровня. Еще одной важной деталью является то, что мы реализовали «мягкое удаление», и у дочерних объектов есть столбец, сообщающий IS_ACTIVE, какая запись активна или нет.

У нас есть что-то вроде this в базе данных

Наши классы:

public abstract class Developer
{
    public int Id { get; set; }
    public string Name { get; set;}
    public bool IsActive { get;set; }
    ...
}    

public class FrontEnd : Developer
{
    ... 
}

public class BackEnd : Developer
{
    ...
}

public abstract class FullStack : Developer
{
    public int Level { get; set; }
}

public class Desktop : FullStack
{
    ...
}

public class Web : FullStack
{
    ...
}

Класс нашей карты в Entity Framework:

DeveloperMap.cs

public class DeveloperMap : EntityTypeConfiguration<Developer>
{
    public DeveloperMap()
    {
        HasKey(x => x.Id);
        Property(x => x.Id).HasColumnName("ID").HasColumnType("int")
            .HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None);
        Property(x => x.Name).HasColumnName("Name");
        // Other Properties Here...

        // This is the domain property used to indicate if a record is "deleted" or not
        Ignore(x => x.IsActive); 

        ToTable("DEVELOPER");
    }
}

FrontEndMap.cs

public class FrontEndMap : EntityTypeConfiguration<FrontEnd>
{
    public FrontEndMap()
    {
        Map(x => x.Requires("IS_ACTIVE").HasValue(true);

        // Other Properties Here...

        ToTable("FRONTEND");
    }
}

BackEndMap.cs

public class BackEndMap : EntityTypeConfiguration<BackEnd>
{
    public BackEndMap()
    {
        Map(x => x.Requires("IS_ACTIVE").HasValue(true);

        // Other Properties Here...

        ToTable("BACKEND");
    }
}

FullStackMap.cs

public class FullStackMap : EntityTypeConfiguration<FullStack>
{
    public FullStackMap()
    {
        Property(x => x.Level).HasColumnName("LEVEL");

        // Other Properties Here...

        ToTable("FULLSTACK");
    }
}

DesktopMap.cs

public class DesktopMap : EntityTypeConfiguration<Desktop>
{
    public DesktopMap()
    {
        Map(x => x.Requires("IS_ACTIVE").HasValue(true);

        // Other Properties Here...

        ToTable("DESKTOP");
    }
}

WebMap.cs

public class WebMap : EntityTypeConfiguration<Web>
{
    public WebMap()
    {
        Map(x => x.Requires("IS_ACTIVE").HasValue(true);

        // Other Properties Here...

        ToTable("WEB");
    }
}

Наш DbContext

DevContext.cs

public class DevContext : DbContext, IDisposable
{
    public DevContext(DbConnection existingConnection, bool contextOwnsConnection) : base(existingConnection, contextOwnsConnection)
    {
        Configuration.ValidateOnSaveEnabled = false;
        Database.SetInitializer<DevContext>(null);
    }

    // AccessControl
    public DbSet<Developer> Developers { get; set; }
}

Когда мы пытаемся загрузить данные из БД для заполнения сетки, используя

_context.Developers

У меня две проблемы:

  1. Если один элемент DESKTOP или WEB имеет значение IS_ACTIVE = 0 в база данных, EF6 не сбрасывает его.

  2. EF6 создает запрос, который получает неверный тип таблицы. Мы есть запись, которая должна быть загружена как DESKTOP, и когда я проверяю ее мой код, я получаю сущность BACKEND!

Запрос, сгенерированный EF6, похож на

SELECT 
"UnionAll2"."C1" AS "C1", 
CASE WHEN (("Project6"."C1" = 1) AND ("Project6"."C1" IS NOT NULL)) THEN '0X0X0X' WHEN (("Project5"."C1" = 1) AND ("Project5"."C1" IS NOT NULL)) THEN '0X0X1X' WHEN ("UnionAll2"."C3" = 1) THEN '0X1X' ELSE '0X2X' END AS "C2", 

-- get properties here like "Extent4"."PROPERTY" AS "PROPERTY"

CASE WHEN (("Project6"."C1" = 1) AND ("Project6"."C1" IS NOT NULL)) THEN "UnionAll2"."C2" WHEN (("Project5"."C1" = 1) AND ("Project5"."C1" IS NOT NULL)) THEN "UnionAll2"."C2" WHEN ("UnionAll2"."C3" = 1) THEN NULL END AS "C3", 

-- get another properties here

CASE WHEN (("Project6"."C1" = 1) AND ("Project6"."C1" IS NOT NULL)) THEN NULL WHEN (("Project5"."C1" = 1) AND ("Project5"."C1" IS NOT NULL)) THEN NULL WHEN ("UnionAll2"."C3" = 1) THEN NULL ELSE "UnionAll2"."C4" END AS "C7"
FROM     (SELECT 
    "UnionAll1"."ID" AS "C1", 
    "UnionAll1"."LEVEL" AS "C2", 
    "UnionAll1"."C1" AS "C3", 
    "UnionAll1"."C2" AS "C4"
    FROM  (SELECT 
        "Extent1"."ID" AS "ID",
        "Extent1"."LEVEL" AS "LEVEL", 
        0 AS "C1", 
        NULL AS "C2"
        FROM "SCHEMA"."FULLSTACK" "Extent1"
    UNION ALL
        SELECT 
        "Extent2"."ID" AS "ID", 
        NULL AS "C1", 
        0 AS "C2",
        FROM "SCHEMA"."BACKEND" "Extent2"
        WHERE ("Extent2"."MORE_IN_ATIVO" = 1)) "UnionAll1"
UNION ALL
    SELECT 
    "Extent3"."ID" AS "ID", 
    NULL AS "C1", 
    1 AS "C2", 
    NULL AS "C3"
    FROM "SCHEMA"."FRONTEND" "Extent3"
    WHERE ("Extent3"."MOR2_IN_ATIVO" = 1)) "UnionAll2"
INNER JOIN "SCHEMA"."DEVELOPER" "Extent4" ON "UnionAll2"."C1" = "Extent4"."ID"
LEFT OUTER JOIN  (SELECT 
    "Extent5"."ID" AS "ID", 

    -- get properties from DESKTOP here

    1 AS "C1"
    FROM "SCHEMA"."DESKTOP" "Extent5"
    WHERE ("Extent5"."IS_ACTIVE" = 1) ) "Project5" ON "UnionAll2"."C1" = "Project5"."ID"
LEFT OUTER JOIN  (SELECT 

    -- get properties from WEB here

    "Extent6"."ID" AS "ID", 
    1 AS "C1"
    FROM "SCHEMA"."WEB" "Extent6"
    WHERE ("Extent6"."IS_ACTIVE" = 1) ) "Project6" ON "UnionAll2"."C1" = "Project6"."ID"

Раньше отлично работал на EF5. Что может быть не так?

...