为什么实体框架在查询TPT继承中的基类时包含具有外连接的派生类

时间:2015-07-29 05:29:28

标签: c# entity-framework entity-framework-6

我使用实体框架6和TPT(Table-per-type)继承。

我有这个课程

public class Person
{
    public Guid Id { get; set; }
    public string Name { get; set; }
}

public class Customer : Person
{
    public string BillingAddress { get; set; }
}    

public class IndividualCustomer : Customer
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime Birthday { get; set; }
}

public class CorporateCustomer : Customer
{
    public string ContactPerson { get; set; }
    public string CorporateTaxNo { get; set; }
}

public class SalesInvoice
{
    public Guid Id { get; set; }
    public Guid CustomerId { get; set; }
    public Customer Customer { get; set; }
}

当我执行此查询时

var people = ctx.People.ToList();

实体框架生成此查询

SELECT 
    CASE WHEN (( NOT (([Project4].[C1] = 1) AND ([Project4].[C1] IS NOT NULL))) AND ( NOT (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL)))) THEN '0X' WHEN (([Project4].[C3] = 1) AND ([Project4].[C3] IS NOT NULL)) THEN '0X0X0X' WHEN (([Project4].[C1] = 1) AND ([Project4].[C1] IS NOT NULL) AND ( NOT (([Project4].[C2] = 1) AND ([Project4].[C2] IS NOT NULL))) AND ( NOT (([Project4].[C3] = 1) AND ([Project4].[C3] IS NOT NULL)))) THEN '0X0X' WHEN (([Project4].[C2] = 1) AND ([Project4].[C2] IS NOT NULL)) THEN '0X0X1X' ELSE '0X1X' END AS [C1], 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Name] AS [Name], 
    CASE WHEN (( NOT (([Project4].[C1] = 1) AND ([Project4].[C1] IS NOT NULL))) AND ( NOT (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL)))) THEN CAST(NULL AS varchar(1)) WHEN (([Project4].[C3] = 1) AND ([Project4].[C3] IS NOT NULL)) THEN [Project4].[BillingAddress] WHEN (([Project4].[C1] = 1) AND ([Project4].[C1] IS NOT NULL) AND ( NOT (([Project4].[C2] = 1) AND ([Project4].[C2] IS NOT NULL))) AND ( NOT (([Project4].[C3] = 1) AND ([Project4].[C3] IS NOT NULL)))) THEN [Project4].[BillingAddress] WHEN (([Project4].[C2] = 1) AND ([Project4].[C2] IS NOT NULL)) THEN [Project4].[BillingAddress] END AS [C2], 
    CASE WHEN (( NOT (([Project4].[C1] = 1) AND ([Project4].[C1] IS NOT NULL))) AND ( NOT (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL)))) THEN CAST(NULL AS varchar(1)) WHEN (([Project4].[C3] = 1) AND ([Project4].[C3] IS NOT NULL)) THEN [Project4].[ContactPerson] WHEN (([Project4].[C1] = 1) AND ([Project4].[C1] IS NOT NULL) AND ( NOT (([Project4].[C2] = 1) AND ([Project4].[C2] IS NOT NULL))) AND ( NOT (([Project4].[C3] = 1) AND ([Project4].[C3] IS NOT NULL)))) THEN CAST(NULL AS varchar(1)) WHEN (([Project4].[C2] = 1) AND ([Project4].[C2] IS NOT NULL)) THEN CAST(NULL AS varchar(1)) END AS [C3], 
    CASE WHEN (( NOT (([Project4].[C1] = 1) AND ([Project4].[C1] IS NOT NULL))) AND ( NOT (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL)))) THEN CAST(NULL AS varchar(1)) WHEN (([Project4].[C3] = 1) AND ([Project4].[C3] IS NOT NULL)) THEN [Project4].[CorporateTaxNo] WHEN (([Project4].[C1] = 1) AND ([Project4].[C1] IS NOT NULL) AND ( NOT (([Project4].[C2] = 1) AND ([Project4].[C2] IS NOT NULL))) AND ( NOT (([Project4].[C3] = 1) AND ([Project4].[C3] IS NOT NULL)))) THEN CAST(NULL AS varchar(1)) WHEN (([Project4].[C2] = 1) AND ([Project4].[C2] IS NOT NULL)) THEN CAST(NULL AS varchar(1)) END AS [C4], 
    CASE WHEN (( NOT (([Project4].[C1] = 1) AND ([Project4].[C1] IS NOT NULL))) AND ( NOT (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL)))) THEN CAST(NULL AS varchar(1)) WHEN (([Project4].[C3] = 1) AND ([Project4].[C3] IS NOT NULL)) THEN CAST(NULL AS varchar(1)) WHEN (([Project4].[C1] = 1) AND ([Project4].[C1] IS NOT NULL) AND ( NOT (([Project4].[C2] = 1) AND ([Project4].[C2] IS NOT NULL))) AND ( NOT (([Project4].[C3] = 1) AND ([Project4].[C3] IS NOT NULL)))) THEN CAST(NULL AS varchar(1)) WHEN (([Project4].[C2] = 1) AND ([Project4].[C2] IS NOT NULL)) THEN [Project4].[FirstName] END AS [C5], 
    CASE WHEN (( NOT (([Project4].[C1] = 1) AND ([Project4].[C1] IS NOT NULL))) AND ( NOT (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL)))) THEN CAST(NULL AS varchar(1)) WHEN (([Project4].[C3] = 1) AND ([Project4].[C3] IS NOT NULL)) THEN CAST(NULL AS varchar(1)) WHEN (([Project4].[C1] = 1) AND ([Project4].[C1] IS NOT NULL) AND ( NOT (([Project4].[C2] = 1) AND ([Project4].[C2] IS NOT NULL))) AND ( NOT (([Project4].[C3] = 1) AND ([Project4].[C3] IS NOT NULL)))) THEN CAST(NULL AS varchar(1)) WHEN (([Project4].[C2] = 1) AND ([Project4].[C2] IS NOT NULL)) THEN [Project4].[LastName] END AS [C6], 
    CASE WHEN (( NOT (([Project4].[C1] = 1) AND ([Project4].[C1] IS NOT NULL))) AND ( NOT (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL)))) THEN CAST(NULL AS datetime2) WHEN (([Project4].[C3] = 1) AND ([Project4].[C3] IS NOT NULL)) THEN CAST(NULL AS datetime2) WHEN (([Project4].[C1] = 1) AND ([Project4].[C1] IS NOT NULL) AND ( NOT (([Project4].[C2] = 1) AND ([Project4].[C2] IS NOT NULL))) AND ( NOT (([Project4].[C3] = 1) AND ([Project4].[C3] IS NOT NULL)))) THEN CAST(NULL AS datetime2) WHEN (([Project4].[C2] = 1) AND ([Project4].[C2] IS NOT NULL)) THEN [Project4].[Birthday] END AS [C7], 
    CASE WHEN (( NOT (([Project4].[C1] = 1) AND ([Project4].[C1] IS NOT NULL))) AND ( NOT (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL)))) THEN CAST(NULL AS varchar(1)) WHEN (([Project4].[C3] = 1) AND ([Project4].[C3] IS NOT NULL)) THEN CAST(NULL AS varchar(1)) WHEN (([Project4].[C1] = 1) AND ([Project4].[C1] IS NOT NULL) AND ( NOT (([Project4].[C2] = 1) AND ([Project4].[C2] IS NOT NULL))) AND ( NOT (([Project4].[C3] = 1) AND ([Project4].[C3] IS NOT NULL)))) THEN CAST(NULL AS varchar(1)) WHEN (([Project4].[C2] = 1) AND ([Project4].[C2] IS NOT NULL)) THEN CAST(NULL AS varchar(1)) ELSE [Project1].[Address] END AS [C8]
    FROM   [dbo].[Person] AS [Extent1]
    LEFT OUTER JOIN  (SELECT 
        [Extent2].[Id] AS [Id], 
        [Extent2].[Address] AS [Address], 
        cast(1 as bit) AS [C1]
        FROM [dbo].[Vendor] AS [Extent2] ) AS [Project1] ON [Extent1].[Id] = [Project1].[Id]
    LEFT OUTER JOIN  (SELECT 
        [Extent3].[Id] AS [Id], 
        [Extent3].[BillingAddress] AS [BillingAddress], 
        cast(1 as bit) AS [C1], 
        [Project2].[ContactPerson] AS [ContactPerson], 
        [Project2].[CorporateTaxNo] AS [CorporateTaxNo], 
        [Project3].[FirstName] AS [FirstName], 
        [Project3].[LastName] AS [LastName], 
        [Project3].[Birthday] AS [Birthday], 
        CASE WHEN (([Project3].[C1] = 1) AND ([Project3].[C1] IS NOT NULL)) THEN cast(1 as bit) WHEN ( NOT (([Project3].[C1] = 1) AND ([Project3].[C1] IS NOT NULL))) THEN cast(0 as bit) END AS [C2], 
        CASE WHEN (([Project2].[C1] = 1) AND ([Project2].[C1] IS NOT NULL)) THEN cast(1 as bit) WHEN ( NOT (([Project2].[C1] = 1) AND ([Project2].[C1] IS NOT NULL))) THEN cast(0 as bit) END AS [C3]
        FROM   [dbo].[Customer] AS [Extent3]
        LEFT OUTER JOIN  (SELECT 
            [Extent4].[Id] AS [Id], 
            [Extent4].[ContactPerson] AS [ContactPerson], 
            [Extent4].[CorporateTaxNo] AS [CorporateTaxNo], 
            cast(1 as bit) AS [C1]
            FROM [dbo].[CorporateCustomer] AS [Extent4] ) AS [Project2] ON [Extent3].[Id] = [Project2].[Id]
        LEFT OUTER JOIN  (SELECT 
            [Extent5].[Id] AS [Id], 
            [Extent5].[FirstName] AS [FirstName], 
            [Extent5].[LastName] AS [LastName], 
            [Extent5].[Birthday] AS [Birthday], 
            cast(1 as bit) AS [C1]
            FROM [dbo].[IndividualCustomer] AS [Extent5] ) AS [Project3] ON [Extent3].[Id] = [Project3].[Id] ) AS [Project4] ON [Extent1].[Id] = [Project4].[Id]
go

当我想要的是实体框架时,实体框架添加所有外部联接的原因是什么。

但是,如果我指定要返回的字段,实体框架会返回更好的查询

var people = ctx.People.Select(x => new {x.Id, x.Name}).ToList();

返回

SELECT 
    1 AS [C1], 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Name] AS [Name]
    FROM [dbo].[Person] AS [Extent1]
go

使用include

时,查询更难以改变
var invoices = ctx.SalesInvoices.Include("Customer").ToList();

返回

SELECT 
    1 AS [C1], 
    [Extent1].[Id] AS [Id], 
    [Extent1].[CustomerId] AS [CustomerId], 
    [Extent1].[CustomerId2] AS [CustomerId2], 
    CASE WHEN ([Join3].[Id1] IS NULL) THEN CAST(NULL AS varchar(1)) WHEN (((CASE WHEN (([Join3].[C11] = 1) AND ([Join3].[C11] IS NOT NULL)) THEN cast(1 as bit) WHEN ( NOT (([Join3].[C11] = 1) AND ([Join3].[C11] IS NOT NULL))) THEN cast(0 as bit) END) <> 1) AND ((CASE WHEN (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL)) THEN cast(1 as bit) WHEN ( NOT (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL))) THEN cast(0 as bit) END) <> 1)) THEN '2X0X' WHEN ((CASE WHEN (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL)) THEN cast(1 as bit) WHEN ( NOT (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL))) THEN cast(0 as bit) END) = 1) THEN '2X0X0X' ELSE '2X0X1X' END AS [C2], 
    [Join3].[Id1] AS [Id1], 
    [Join3].[Name] AS [Name], 
    [Join3].[BillingAddress] AS [BillingAddress], 
    CASE WHEN ([Join3].[Id1] IS NULL) THEN CAST(NULL AS varchar(1)) WHEN (((CASE WHEN (([Join3].[C11] = 1) AND ([Join3].[C11] IS NOT NULL)) THEN cast(1 as bit) WHEN ( NOT (([Join3].[C11] = 1) AND ([Join3].[C11] IS NOT NULL))) THEN cast(0 as bit) END) <> 1) AND ((CASE WHEN (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL)) THEN cast(1 as bit) WHEN ( NOT (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL))) THEN cast(0 as bit) END) <> 1)) THEN CAST(NULL AS varchar(1)) WHEN ((CASE WHEN (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL)) THEN cast(1 as bit) WHEN ( NOT (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL))) THEN cast(0 as bit) END) = 1) THEN [Join3].[ContactPerson] END AS [C3], 
    CASE WHEN ([Join3].[Id1] IS NULL) THEN CAST(NULL AS varchar(1)) WHEN (((CASE WHEN (([Join3].[C11] = 1) AND ([Join3].[C11] IS NOT NULL)) THEN cast(1 as bit) WHEN ( NOT (([Join3].[C11] = 1) AND ([Join3].[C11] IS NOT NULL))) THEN cast(0 as bit) END) <> 1) AND ((CASE WHEN (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL)) THEN cast(1 as bit) WHEN ( NOT (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL))) THEN cast(0 as bit) END) <> 1)) THEN CAST(NULL AS varchar(1)) WHEN ((CASE WHEN (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL)) THEN cast(1 as bit) WHEN ( NOT (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL))) THEN cast(0 as bit) END) = 1) THEN [Join3].[CorporateTaxNo] END AS [C4], 
    CASE WHEN ([Join3].[Id1] IS NULL) THEN CAST(NULL AS varchar(1)) WHEN (((CASE WHEN (([Join3].[C11] = 1) AND ([Join3].[C11] IS NOT NULL)) THEN cast(1 as bit) WHEN ( NOT (([Join3].[C11] = 1) AND ([Join3].[C11] IS NOT NULL))) THEN cast(0 as bit) END) <> 1) AND ((CASE WHEN (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL)) THEN cast(1 as bit) WHEN ( NOT (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL))) THEN cast(0 as bit) END) <> 1)) THEN CAST(NULL AS varchar(1)) WHEN ((CASE WHEN (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL)) THEN cast(1 as bit) WHEN ( NOT (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL))) THEN cast(0 as bit) END) = 1) THEN CAST(NULL AS varchar(1)) ELSE [Join3].[FirstName] END AS [C5], 
    CASE WHEN ([Join3].[Id1] IS NULL) THEN CAST(NULL AS varchar(1)) WHEN (((CASE WHEN (([Join3].[C11] = 1) AND ([Join3].[C11] IS NOT NULL)) THEN cast(1 as bit) WHEN ( NOT (([Join3].[C11] = 1) AND ([Join3].[C11] IS NOT NULL))) THEN cast(0 as bit) END) <> 1) AND ((CASE WHEN (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL)) THEN cast(1 as bit) WHEN ( NOT (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL))) THEN cast(0 as bit) END) <> 1)) THEN CAST(NULL AS varchar(1)) WHEN ((CASE WHEN (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL)) THEN cast(1 as bit) WHEN ( NOT (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL))) THEN cast(0 as bit) END) = 1) THEN CAST(NULL AS varchar(1)) ELSE [Join3].[LastName] END AS [C6], 
    CASE WHEN ([Join3].[Id1] IS NULL) THEN CAST(NULL AS datetime2) WHEN (((CASE WHEN (([Join3].[C11] = 1) AND ([Join3].[C11] IS NOT NULL)) THEN cast(1 as bit) WHEN ( NOT (([Join3].[C11] = 1) AND ([Join3].[C11] IS NOT NULL))) THEN cast(0 as bit) END) <> 1) AND ((CASE WHEN (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL)) THEN cast(1 as bit) WHEN ( NOT (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL))) THEN cast(0 as bit) END) <> 1)) THEN CAST(NULL AS datetime2) WHEN ((CASE WHEN (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL)) THEN cast(1 as bit) WHEN ( NOT (([Join3].[C12] = 1) AND ([Join3].[C12] IS NOT NULL))) THEN cast(0 as bit) END) = 1) THEN CAST(NULL AS datetime2) ELSE [Join3].[Birthday] END AS [C7]
    FROM  [dbo].[SalesInvoice] AS [Extent1]
    LEFT OUTER JOIN  (SELECT [Extent2].[Id] AS [Id1], [Extent2].[BillingAddress] AS [BillingAddress], [Project1].[ContactPerson] AS [ContactPerson], [Project1].[CorporateTaxNo] AS [CorporateTaxNo], [Project1].[C1] AS [C12], [Project2].[FirstName] AS [FirstName], [Project2].[LastName] AS [LastName], [Project2].[Birthday] AS [Birthday], [Project2].[C1] AS [C11], [Extent5].[Name] AS [Name]
        FROM    [dbo].[Customer] AS [Extent2]
        LEFT OUTER JOIN  (SELECT 
            [Extent3].[Id] AS [Id], 
            [Extent3].[ContactPerson] AS [ContactPerson], 
            [Extent3].[CorporateTaxNo] AS [CorporateTaxNo], 
            cast(1 as bit) AS [C1]
            FROM [dbo].[CorporateCustomer] AS [Extent3] ) AS [Project1] ON [Extent2].[Id] = [Project1].[Id]
        LEFT OUTER JOIN  (SELECT 
            [Extent4].[Id] AS [Id], 
            [Extent4].[FirstName] AS [FirstName], 
            [Extent4].[LastName] AS [LastName], 
            [Extent4].[Birthday] AS [Birthday], 
            cast(1 as bit) AS [C1]
            FROM [dbo].[IndividualCustomer] AS [Extent4] ) AS [Project2] ON [Extent2].[Id] = [Project2].[Id]
        INNER JOIN [dbo].[Person] AS [Extent5] ON [Extent2].[Id] = [Extent5].[Id] ) AS [Join3] ON [Extent1].[CustomerId] = [Join3].[Id1]
go

有解决方法吗?

1 个答案:

答案 0 :(得分:0)

  

当我想要的是实体框架时,实体框架添加所有外部联接的原因是什么。

EF希望知道实体的确切类型(PersonCustomerIndividualCustomer等),以便能够创建正确的实例。因此,它只能从加入层次结构的所有表中获取类型信息(参见case语句)。

  

有解决方法吗?

可能的替代方法之一是应用 - 只查询基类中所需的属性,就像您一样。另一种可能的选择 - 使用带有鉴别器列的每个层次表。