C# EF减少嵌套类型的外部联接
我的一个项目的配置有问题,正在生成的SQL EF似乎显示出一些意外(至少对我来说)嵌套。这个问题会有点冗长,但请耐心听我说 那么,假设我有以下设置:C# EF减少嵌套类型的外部联接,c#,entity-framework,C#,Entity Framework,我的一个项目的配置有问题,正在生成的SQL EF似乎显示出一些意外(至少对我来说)嵌套。这个问题会有点冗长,但请耐心听我说 那么,假设我有以下设置: public class Order { public int Id { get; set; } public decimal Amount { get; set; } public Address ShippingAddress { get; set; } } public class Person { publ
public class Order
{
public int Id { get; set; }
public decimal Amount { get; set; }
public Address ShippingAddress { get; set; }
}
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Address Address { get; set; }
}
public class Address
{
public int Id { get; set; }
public string StreetAddress { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
}
将实体配置为:
public class OrderConfiguration : EntityTypeConfiguration<Order>
{
public OrderConfiguration()
{
ToTable("Orders");
HasRequired(order => order.ShippingAddress)
.WithRequiredDependent()
.Map(mapping => mapping.MapKey("ShippingAddressId"));
}
}
public class PersonConfiguration : EntityTypeConfiguration<Person>
{
public PersonConfiguration()
{
ToTable("Persons");
HasRequired(person => person.Address)
.WithRequiredDependent()
.Map(mapping => mapping.MapKey("AddressId"));
}
}
在监视SQL Profiler时,我希望看到生成的SQL从Orders表中进行选择,并在Address表上进行内部联接
SELECT * FROM [dbo].[Orders] AS [Extent1]
INNER JOIN [dbo].[Addresses] AS [Extent2] ON [Extent1].[AddressId] = [Extentd2].[Id]
WHERE [Extent2].[State] == 'FL'
相反,我发现这产生了:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Amount] AS [Amount],
[Join5].[Id1] AS [Id1],
[Join5].[StreetAddress] AS [StreetAddress],
[Join5].[City] AS [City],
[Join5].[State] AS [State],
[Join5].[ZipCode] AS [ZipCode],
[Join8].[Id2] AS [Id2],
[Join11].[Id3] AS [Id3]
FROM [dbo].[Orders] AS [Extent1]
INNER JOIN (SELECT [Extent2].[State] AS [State], [Extent3].[Id] AS [Id4]
FROM [dbo].[Addresses] AS [Extent2]
LEFT OUTER JOIN [dbo].[Orders] AS [Extent3] ON [Extent2].[Id] = [Extent3].[ShippingAddressId]
LEFT OUTER JOIN [dbo].[Persons] AS [Extent4] ON [Extent2].[Id] = [Extent4].[AddressId] ) AS [Join2] ON [Extent1].[Id] = [Join2].[Id4]
LEFT OUTER JOIN (SELECT [Extent5].[Id] AS [Id1], [Extent5].[StreetAddress] AS [StreetAddress], [Extent5].[City] AS [City], [Extent5].[State] AS [State], [Extent5].[ZipCode] AS [ZipCode], [Extent6].[Id] AS [Id5]
FROM [dbo].[Addresses] AS [Extent5]
LEFT OUTER JOIN [dbo].[Orders] AS [Extent6] ON [Extent5].[Id] = [Extent6].[ShippingAddressId]
LEFT OUTER JOIN [dbo].[Persons] AS [Extent7] ON [Extent5].[Id] = [Extent7].[AddressId] ) AS [Join5] ON [Extent1].[Id] = [Join5].[Id5]
LEFT OUTER JOIN (SELECT [Extent9].[Id] AS [Id2]
FROM [dbo].[Addresses] AS [Extent8]
LEFT OUTER JOIN [dbo].[Orders] AS [Extent9] ON [Extent8].[Id] = [Extent9].[ShippingAddressId]
LEFT OUTER JOIN [dbo].[Persons] AS [Extent10] ON [Extent8].[Id] = [Extent10].[AddressId] ) AS [Join8] ON [Extent1].[Id] = [Join8].[Id2]
LEFT OUTER JOIN (SELECT [Extent12].[Id] AS [Id6], [Extent13].[Id] AS [Id3]
FROM [dbo].[Addresses] AS [Extent11]
LEFT OUTER JOIN [dbo].[Orders] AS [Extent12] ON [Extent11].[Id] = [Extent12].[ShippingAddressId]
LEFT OUTER JOIN [dbo].[Persons] AS [Extent13] ON [Extent11].[Id] = [Extent13].[AddressId] ) AS [Join11] ON [Extent1].[Id] = [Join11].[Id6]
WHERE N'FL' = [Join2].[State]
显然,这比需要做的工作多得多。是否有更简单的方法来执行此操作,或者我是否错误地配置了实体?我不明白它为什么要收回所有这些额外的连接,或者我如何将它们限制在我当时需要的表中。任何洞察都将不胜感激
谢谢,
Derek正如您所注意到的
。Include()
有时会生成可怕的SQL
我发现在这种情况下最简单的解决方案是在初始加载之后直接显式加载所需的相关实体。这样做的缺点是额外的数据库调用—它将为每个订单调用一次
var orders = (
from order in context.Orders
where order.ShippingAddress.State == "FL"
select order)
.ToList();
var t1 = (
from order in orders
from address in order.ShippingAddress
select address)
.ToList();
如果您的关系是一对多而不是一对一,SQL可能会变得更好。您是说我应该将其配置为1:N,还是说我需要更改我的域图?如果是前者,为什么会起作用呢?我只是想说,在我的经验中,这种糟糕的SQL尤其适用于一对一关系(手动配置或TPT继承),并且对于一对多关系,它通常会变得更干净。如果可以的话,我会尽量避免一对一。如果您真的需要这里的一对一,您可以做的就不多了(除了可能将
地址
作为复杂类型嵌入到订单
和人员
表中)。实际上,我接受了您的建议,这实际上修复了生成的过于复杂的SQL。我并不特别喜欢它,因为任何查看配置的人可能都不理解它是1:1,但我想这就是域层的用途。谢谢@slauma-感谢您提供的有用信息。感谢您的回复。但这并没有真正的帮助,因为即使我这样做了,第二个查询也会生成时髦的SQL语句。我使用的例子是我试图解决的RL问题的简化版本,其中涉及本地化。我将有2个引用,第二个查询(以及包含的查询)将返回16个引用。
var orders = (
from order in context.Orders
where order.ShippingAddress.State == "FL"
select order)
.ToList();
var t1 = (
from order in orders
from address in order.ShippingAddress
select address)
.ToList();