c# - EF 减少嵌套类型的外部连接

标签 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
{
    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"));
    }
}

我的目标是获取包含地址的订单,因此我运行了一个简单的查询,例如:

var orders = context.Orders
    .Include(order => order.ShippingAddress)
    .Where(order => order.ShippingAddress.State == "FL")
    .ToList();

当我监视 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]

显然,这比需要完成的工作要多得多。是否有更简单的方法来执行此操作,或者我是否将实体配置不正确?我不明白为什么它要撤回所有这些额外的连接,或者我如何才能将它们限制在我当时需要的表中。任何见解将不胜感激!

谢谢, 德里克

最佳答案

正如您所注意到的,.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();

关于c# - EF 减少嵌套类型的外部连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15330897/

相关文章:

c# - RegisterForEventValidation .net 3.5 gridview 行,如何?

entity-framework - 数据库首先使用system.data.sqlite 1.0.93创建 Entity Framework 6.1.1模型

c# - EF 的 ObjectContext.ApplyCurrentValues 等效项是什么

c# - Entity Framework 代码优先通过关系表导航属性

c# - 处理属性(property)变更事件

c# - 如何将 PDF 保存为只读/扁平化?

c# - 从另一个项目修改 Windows 窗体控件

c# - EntityFrameworkCore 中的 IDbAsyncQueryProvider

entity-framework - Entity Framework 代码首先使用 Guid 作为身份与另一个身份列

mysql - 使用 Entity Framework 填充表