[英]Why does entity framework include derived classes with outer join when querying against the base class in TPT inheritance
我正在使用具有TPT(每个类型的表)继承的实体框架6。
我有这节课
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
使用包含时查询更难更改
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
是否有解决此问题的解决方法?
当我想要的只是人员类时,实体框架添加所有这些外部联接的原因是什么?
EF希望了解实体的确切类型( Person
, Customer
, IndividualCustomer
等),以便能够创建正确的实例。 因此,它只能从连接层次结构的所有表中获取类型信息(请参阅case语句)。
是否有解决此问题的解决方法?
一种可能的替代方法是应用-与您一样仅从基类中查询所需的属性。 另一种可能的选择-使用带有区分符列的按层次结构表。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.