Npgsql中的重复连接用于相同的导航属性

时间:2015-10-21 19:36:20

标签: c# sql entity-framework postgresql npgsql

此问题已存在here,但对于TSQ的实体框架

在select上多次使用相同的导航属性时,Npgsql查询会产生多个连接,每次使用一个导航属性。这导致了糟糕的性能损失(测试)

我已经读过这是EF 4的一个问题,但这个问题也发生在EF 6上。

我认为这是Npgsql LINQ to SQL转换器的问题

这是Npgsql为多次使用的相同导航属性生成的代码,显然,只需要一个连接(从其他问题复制,因为情况完全相同)

LEFT OUTER JOIN [dbo].[Versions] AS [Extent4] ON [Extent1].[IDVersionReported] = [Extent4].[ID]
LEFT OUTER JOIN [dbo].[Versions] AS [Extent5] ON [Extent1].[IDVersionReported] = [Extent5].[ID]
LEFT OUTER JOIN [dbo].[Versions] AS [Extent6] ON [Extent1].[IDVersionReported] = [Extent6].[ID]
LEFT OUTER JOIN [dbo].[Versions] AS [Extent7] ON [Extent1].[IDVersionReported] = [Extent7].[ID]

调整PostgreSql以优化重复连接是否可行?

如果没有,哪个选项最适合解决这个问题?

  • 等到Npgsql修复后
  • 下载Npgsql代码并找到修复方法
  • 在到达数据库之前拦截生成的SQL,解析它并删除重复的连接。 (阅读here
  • 不要使用导航属性,而是使用LINQ连接

1 个答案:

答案 0 :(得分:0)

事实上,这是实体框架的问题,但我找到了一种解决方法,希望这有助于某人。

这是LINQ查询的原始.hidden-xs or .visible-xs 部分:

where

注意where的最后一个条件,该条件执行 from cr in Creditos where cr.validado == 1 && cr.fecharegistro >= Desde && cr.fecharegistro <= Hasta && !ProductosExcluidos.Contains(cr.idproducto.Value) && cr.amortizaciones.Sum(am => am.importecapital - am.pagoscap - am.capcancel) > 1 //All references to the navigation property cr.numcliente //results on a separated LEFT OUTTER JOIN between this the 'creditos' and 'clientes' tables select new ArchivoCliente { RFC = cr.numcliente.rfc, Nombres = cr.numcliente.nombres, ApellidoPaterno = cr.numcliente.apellidopaterno, ApellidoMaterno = cr.numcliente.apellidomaterno, } 的所有子实体的总和,如果我们取出最后一个条件,则所有重复的cr都被一个LEFT OUTTER JOIN替换JOIN 1}},由于某种原因,实体框架不喜欢查询where部分的子查询或聚合

如果我们用其他等效查询替换原始查询,则只生成一个LEFT OUTTER JOIN

 (from cr in Creditos
 where cr.validado == 1 &&
 cr.fecharegistro >= Desde &&
 cr.fecharegistro <= Hasta &&
 !ProductosExcluidos.Contains(cr.idproducto.Value) &&
 //Excluded aggregate function condition from the first where
 //the value is now on the select and used for posterior filtering

 select new ArchivoCliente
 {
    RFC = cr.numcliente.rfc,
    Nombres = cr.numcliente.nombres,
    ApellidoPaterno = cr.numcliente.apellidopaterno,
    ApellidoMaterno = cr.numcliente.apellidomaterno,
    SumaAmort = cr.amortizaciones.Sum(am => am.importecapital - am.pagoscap - am.capcancel)
 }).Where (x => x.SumaAmort > 1);

现在,不是直接过滤第一个where语句,而是将聚合结果存储为投影的一部分,然后将第二个应用于生成的查询。

这样可以实现更快的查询,只需要对已翻译的SQL语句进行必要的连接。