EF Linq to Entities在实体集上调用ToList()会生成包含多个左外连接的SQL命令

Ghi*_*nio 5 .net c# linq ado.net entity-framework

我的实体"Progetto"映射名为VW_AMY_PRG_WCS_Lookup的视图

在此输入图像描述

Progetto拥有五个导航属性:ClienteDiFatturazione,ClienteDiLavorazione,PercentualeSuccesso,Agente具有多重性0..1和DocumentiWcs具有mupltiplicity*

当我在LINQPad中运行这个简单的语句时

var prj = Progetti.AsQueryable(); 
prj.ToList();
Run Code Online (Sandbox Code Playgroud)

生成的sql是

SELECT 
    [Extent1].[IdProgetto] AS [IdProgetto], 
    [Extent1].[IdSerie_Progetto] AS [IdSerie_Progetto], 
    [Extent1].[Importo] AS [Importo], 
    [Extent1].[Data_Prevista_Chiusura] AS [Data_Prevista_Chiusura], 
    [Extent1].[IdStato] AS [IdStato], 
    [Extent1].[Oggetto] AS [Oggetto], 
    [Extent1].[IdMezzo_Pervenuto] AS [IdMezzo_Pervenuto], 
    [Extent1].[IdAgente] AS [IdAgente], 
    [Extent1].[Fido_Residuo] AS [Fido_Residuo], 
    [Extent2].[IdAnagrafica_Fatturazione] AS [IdAnagrafica_Fatturazione], 
    [Extent3].[IdAnagrafica_Lavorazione] AS [IdAnagrafica_Lavorazione], 
    [Extent4].[IdPercentuale_Successo] AS [IdPercentuale_Successo]
    FROM    (SELECT 
    [VW_AMY_PRG_WCS_Lookup].[IdProgetto] AS [IdProgetto], 
    [VW_AMY_PRG_WCS_Lookup].[IdSerie_Progetto] AS [IdSerie_Progetto], 
    [VW_AMY_PRG_WCS_Lookup].[Importo] AS [Importo], 
    [VW_AMY_PRG_WCS_Lookup].[IdPercentuale_Successo] AS [IdPercentuale_Successo], 
    [VW_AMY_PRG_WCS_Lookup].[Data_Prevista_Chiusura] AS [Data_Prevista_Chiusura], 
    [VW_AMY_PRG_WCS_Lookup].[IdAnagrafica_Lavorazione] AS [IdAnagrafica_Lavorazione], 
    [VW_AMY_PRG_WCS_Lookup].[IdAnagrafica_Fatturazione] AS [IdAnagrafica_Fatturazione], 
    [VW_AMY_PRG_WCS_Lookup].[IdMezzo_Pervenuto] AS [IdMezzo_Pervenuto], 
    [VW_AMY_PRG_WCS_Lookup].[IdStato] AS [IdStato], 
    [VW_AMY_PRG_WCS_Lookup].[Oggetto] AS [Oggetto], 
    [VW_AMY_PRG_WCS_Lookup].[IdAgente] AS [IdAgente], 
    [VW_AMY_PRG_WCS_Lookup].[Fido_Residuo] AS [Fido_Residuo]
    FROM [dbo].[VW_AMY_PRG_WCS_Lookup] AS [VW_AMY_PRG_WCS_Lookup]) AS [Extent1]
    LEFT OUTER JOIN (SELECT 
    [VW_AMY_PRG_WCS_Lookup].[IdProgetto] AS [IdProgetto], 
    [VW_AMY_PRG_WCS_Lookup].[IdSerie_Progetto] AS [IdSerie_Progetto], 
    [VW_AMY_PRG_WCS_Lookup].[Importo] AS [Importo], 
    [VW_AMY_PRG_WCS_Lookup].[IdPercentuale_Successo] AS [IdPercentuale_Successo], 
    [VW_AMY_PRG_WCS_Lookup].[Data_Prevista_Chiusura] AS [Data_Prevista_Chiusura], 
    [VW_AMY_PRG_WCS_Lookup].[IdAnagrafica_Lavorazione] AS [IdAnagrafica_Lavorazione], 
    [VW_AMY_PRG_WCS_Lookup].[IdAnagrafica_Fatturazione] AS [IdAnagrafica_Fatturazione], 
    [VW_AMY_PRG_WCS_Lookup].[IdMezzo_Pervenuto] AS [IdMezzo_Pervenuto], 
    [VW_AMY_PRG_WCS_Lookup].[IdStato] AS [IdStato], 
    [VW_AMY_PRG_WCS_Lookup].[Oggetto] AS [Oggetto], 
    [VW_AMY_PRG_WCS_Lookup].[IdAgente] AS [IdAgente], 
    [VW_AMY_PRG_WCS_Lookup].[Fido_Residuo] AS [Fido_Residuo]
    FROM [dbo].[VW_AMY_PRG_WCS_Lookup] AS [VW_AMY_PRG_WCS_Lookup]) AS [Extent2] ON ([Extent2].[IdAnagrafica_Fatturazione] IS NOT NULL) AND ([Extent1].[IdProgetto] = [Extent2].[IdProgetto]) AND ([Extent1].[IdSerie_Progetto] = [Extent2].[IdSerie_Progetto])
    LEFT OUTER JOIN (SELECT 
    [VW_AMY_PRG_WCS_Lookup].[IdProgetto] AS [IdProgetto], 
    [VW_AMY_PRG_WCS_Lookup].[IdSerie_Progetto] AS [IdSerie_Progetto], 
    [VW_AMY_PRG_WCS_Lookup].[Importo] AS [Importo], 
    [VW_AMY_PRG_WCS_Lookup].[IdPercentuale_Successo] AS [IdPercentuale_Successo], 
    [VW_AMY_PRG_WCS_Lookup].[Data_Prevista_Chiusura] AS [Data_Prevista_Chiusura], 
    [VW_AMY_PRG_WCS_Lookup].[IdAnagrafica_Lavorazione] AS [IdAnagrafica_Lavorazione], 
    [VW_AMY_PRG_WCS_Lookup].[IdAnagrafica_Fatturazione] AS [IdAnagrafica_Fatturazione], 
    [VW_AMY_PRG_WCS_Lookup].[IdMezzo_Pervenuto] AS [IdMezzo_Pervenuto], 
    [VW_AMY_PRG_WCS_Lookup].[IdStato] AS [IdStato], 
    [VW_AMY_PRG_WCS_Lookup].[Oggetto] AS [Oggetto], 
    [VW_AMY_PRG_WCS_Lookup].[IdAgente] AS [IdAgente], 
    [VW_AMY_PRG_WCS_Lookup].[Fido_Residuo] AS [Fido_Residuo]
    FROM [dbo].[VW_AMY_PRG_WCS_Lookup] AS [VW_AMY_PRG_WCS_Lookup]) AS [Extent3] ON ([Extent3].[IdAnagrafica_Lavorazione] IS NOT NULL) AND ([Extent1].[IdProgetto] = [Extent3].[IdProgetto]) AND ([Extent1].[IdSerie_Progetto] = [Extent3].[IdSerie_Progetto])
    LEFT OUTER JOIN (SELECT 
    [VW_AMY_PRG_WCS_Lookup].[IdProgetto] AS [IdProgetto], 
    [VW_AMY_PRG_WCS_Lookup].[IdSerie_Progetto] AS [IdSerie_Progetto], 
    [VW_AMY_PRG_WCS_Lookup].[Importo] AS [Importo], 
    [VW_AMY_PRG_WCS_Lookup].[IdPercentuale_Successo] AS [IdPercentuale_Successo], 
    [VW_AMY_PRG_WCS_Lookup].[Data_Prevista_Chiusura] AS [Data_Prevista_Chiusura], 
    [VW_AMY_PRG_WCS_Lookup].[IdAnagrafica_Lavorazione] AS [IdAnagrafica_Lavorazione], 
    [VW_AMY_PRG_WCS_Lookup].[IdAnagrafica_Fatturazione] AS [IdAnagrafica_Fatturazione], 
    [VW_AMY_PRG_WCS_Lookup].[IdMezzo_Pervenuto] AS [IdMezzo_Pervenuto], 
    [VW_AMY_PRG_WCS_Lookup].[IdStato] AS [IdStato], 
    [VW_AMY_PRG_WCS_Lookup].[Oggetto] AS [Oggetto], 
    [VW_AMY_PRG_WCS_Lookup].[IdAgente] AS [IdAgente], 
    [VW_AMY_PRG_WCS_Lookup].[Fido_Residuo] AS [Fido_Residuo]
    FROM [dbo].[VW_AMY_PRG_WCS_Lookup] AS [VW_AMY_PRG_WCS_Lookup]) AS [Extent4] ON ([Extent4].[IdPercentuale_Successo] IS NOT NULL) AND ([Extent1].[IdProgetto] = [Extent4].[IdProgetto]) AND ([Extent1].[IdSerie_Progetto] = [Extent4].[IdSerie_Progetto])
Run Code Online (Sandbox Code Playgroud)

我想知道为什么生成的SQL查询涉及这么多左外连接; 我希望在VW_AMY_PRG_WCS_Lookup上进行简单的选择.这种行为的目的是什么?作为映射到View多个联接的实体会对查询性能产生重大影响.任何解决方法?

更新 作为VW_AMY_PRG_WCS_Lookup视图我必须手动添加所有关联和导航属性(在数据库级别没有定义fk,因此在从数据库创建模型时没有生成关联)

IdAnagrafica_Fatturazione指的是ClienteDIfatturazione,IdAnagrafica_Lavorazione指的是ClienteDiLavorazione,IdPercentuale_Successo指的是PercentualeSuccesso和IdAgente指的是Agente,我只是重命名模型中的字段,所以他们的名字与视图中的字段有点不同.

这是Progetto类的代码

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated from a template.
//
//     Manual changes to this file may cause unexpected behavior in your application.
//     Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace EntityModel
{
    using System;
    using System.Collections.Generic;

    public partial class Progetto
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public Progetto()
        {
            this.DocumentiWcs = new HashSet<DocumentoWcsProgetto>();
        }

        public int Codice { get; set; }
        public int Serie { get; set; }
        public Nullable<decimal> Importo { get; set; }
        public Nullable<System.DateTime> DataPrevistaChiusura { get; set; }
        public Nullable<int> IdStato { get; set; }
        public string Oggetto { get; set; }
        public Nullable<int> IdMezzoPervenuto { get; set; }
        public Nullable<int> IdAgente { get; set; }
        public Nullable<decimal> FidoResiduo { get; set; }

        public virtual Cliente ClienteDiFatturazione { get; set; }
        public virtual Cliente ClienteDiLavorazione { get; set; }
        public virtual PercentualeSuccesso PercentualeSuccesso { get; set; }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<DocumentoWcsProgetto> DocumentiWcs { get; set; }
        public virtual Agente Agente { get; set; }
    }
}
Run Code Online (Sandbox Code Playgroud)

这里是视图VW_AMY_PRG_WCS_Lookup的DefiningQuery

      <EntitySet Name="VW_AMY_PRG_WCS_Lookup" EntityType="Self.VW_AMY_PRG_WCS_Lookup" store:Type="Views" store:Schema="dbo">
        <DefiningQuery>SELECT 
[VW_AMY_PRG_WCS_Lookup].[IdProgetto] AS [IdProgetto], 
[VW_AMY_PRG_WCS_Lookup].[IdSerie_Progetto] AS [IdSerie_Progetto], 
[VW_AMY_PRG_WCS_Lookup].[Importo] AS [Importo], 
[VW_AMY_PRG_WCS_Lookup].[IdPercentuale_Successo] AS [IdPercentuale_Successo], 
[VW_AMY_PRG_WCS_Lookup].[Data_Prevista_Chiusura] AS [Data_Prevista_Chiusura], 
[VW_AMY_PRG_WCS_Lookup].[IdAnagrafica_Lavorazione] AS [IdAnagrafica_Lavorazione], 
[VW_AMY_PRG_WCS_Lookup].[IdAnagrafica_Fatturazione] AS [IdAnagrafica_Fatturazione], 
[VW_AMY_PRG_WCS_Lookup].[IdMezzo_Pervenuto] AS [IdMezzo_Pervenuto], 
[VW_AMY_PRG_WCS_Lookup].[IdStato] AS [IdStato], 
[VW_AMY_PRG_WCS_Lookup].[Oggetto] AS [Oggetto], 
[VW_AMY_PRG_WCS_Lookup].[IdAgente] AS [IdAgente], 
[VW_AMY_PRG_WCS_Lookup].[Fido_Residuo] AS [Fido_Residuo]
FROM [dbo].[VW_AMY_PRG_WCS_Lookup] AS [VW_AMY_PRG_WCS_Lookup]</DefiningQuery>
      </EntitySet>
Run Code Online (Sandbox Code Playgroud)

Har*_*lse 0

原因是您没有Select在查询中使用。因此选择原来的类。

您应该只选择您真正计划使用的属性。

下面是经过测试的解决方案,它只会连接您的请求中使用的表。唉,我的意大利语(?)有点生疏,所以如果我没有使用正确的标识符,请原谅我。

var result = myDbContext.Progretti           
    .Select(progret => new                 // from every Progret make one new object
    {                                      // containing only the properties you plan to use
        Id = progret.Id,
        Name = progret.Name

        ProgrettiDiFacturazione = new      // you can even use properties from other tables
        {                                  // again: only properties you plan to use
             Name = progret.ProgrettiDiFacturazione.Name
             Date = progret.ProgrettiDiFacturazione.Date,
             ...
        },
        ...
    })
    .ToList();
Run Code Online (Sandbox Code Playgroud)

DbSet 实现了 IQueryable,所以你不需要AsQueryable

如果您正确设计了一对多(多对多?)类,实体框架足够智能,可以理解需要哪些表连接。如果该表没有请求任何属性,它不会连接表。