Linq - 由具有多个返回的多个表分组

时间:2011-08-03 18:48:41

标签: c# .net linq linq-to-sql group-by

使用Linq to Sql如何对下表(entidadeProdutosFornecedores)进行分组并从N个表中返回字段?

SQL中的原始查询

SELECT  @NM_VALOR1      = MAX(ProdutosFornecedores.NM_PRECO_REPOSICAO),
                @NM_VALOR2      = MAX(ProdutosFornecedores.ID_MOEDAS_REPOSICAO),
                @ID_IMPOSTOSDESTINOS    = MAX(Fornecedores.ID_IMPOSTOSDESTINOS),
                @ID_IMPOSTOSCONFIG  = MAX(ProdutosFornecedores.ID_IMPOSTOSCONFIG),
                @ID_TABELANCMS      = MAX(ProdutosFornecedores.ID_TABELANCMS),
                @ID_FORNECEDORES    = MAX(Fornecedores.ID_FORNECEDORES),
                @CD_UF_BASE     = MAX(UnidadesFederacao.CD_UNIDADEFEDERACAO)
              FROM  ProdutosFornecedores
                INNER JOIN Fornecedores     ON Fornecedores.ID_FORNECEDORES       = ProdutosFornecedores.ID_FORNECEDORES
                INNER JOIN Municipios       ON Municipios.ID_MUNICIPIOS       = Fornecedores.ID_MUNICIPIOS
                INNER JOIN UnidadesFederacao    ON UnidadesFederacao.ID_UNIDADESFEDERACAO = Municipios.ID_UNIDADESFEDERACAO
             WHERE  ProdutosFornecedores.ID_PRODUTOS        = CAST(@CD_OBJETO1 AS INT)  AND
                ProdutosFornecedores.ID_PRODUTOSCONFIGPRECOS    = CAST(@CD_OBJETO2 AS INT)  AND
                ProdutosFornecedores.FG_STATUS          = 1
            GROUP BY
                ProdutosFornecedores.ID_PRODUTOS,
                ProdutosFornecedores.ID_PRODUTOSCONFIGPRECOS

查询转换为Linq

var prodForn2 = from entidadeProdutosFornecedores in ERPDAOManager.GetTable<ProdutosFornecedores>()
                                                    //Inner Join with Fornecedores
                                                    join entidadeFornecedores in ERPDAOManager.GetTable<Fornecedores>()
                                                         on entidadeProdutosFornecedores.ID_FORNECEDORES equals entidadeFornecedores.ID into tempFornecedores
                                                    from fornecedores in tempFornecedores
                                                    //Inner Join with Municipios
                                                    join entidadeMuncipios in ERPDAOManager.GetTable<Municipios>()
                                                        on fornecedores.ID_MUNICIPIOS equals entidadeMuncipios.ID into tempMunicipios
                                                    from municipios in tempMunicipios
                                                    //Inner Join with UnidadesFederacao
                                                    join entidadeUnidadesFederacao in ERPDAOManager.GetTable<UnidadesFederacao>()
                                                        on municipios.ID_UNIDADESFEDERACAO equals entidadeUnidadesFederacao.ID into tempUnidadesFederacao
                                                    from unidadesFederacao in tempUnidadesFederacao
                                                    //Filters
                                                    where entidadeProdutosFornecedores.ID_PRODUTOS == Convert.ToInt32(objEsquemasCalculoRegras.CD_OBJETO1) &&
                                                          entidadeProdutosFornecedores.ID_PRODUTOSCONFIGPRECOS == Convert.ToInt32(objEsquemasCalculoRegras.CD_OBJETO2) &&
                                                          entidadeProdutosFornecedores.FG_STATUS == true
                                                    group entidadeProdutosFornecedores by new { entidadeProdutosFornecedores.ID_PRODUTOS, entidadeProdutosFornecedores.ID_PRODUTOSCONFIGPRECOS } into produtosFornecedores
                                                    select new
                                                    {
                                                        NM_PRECO_REPOSICAO = (decimal)produtosFornecedores.Max(item => item.NM_PRECO_REPOSICAO),
                                                        ID_MOEDAS_REPOSICAO = (int)produtosFornecedores.Max(item => item.ID_MOEDAS_REPOSICAO),
                                                        ID_IMPOSTOSDESTINOS = (int)fornecedores.ID_IMPOSTOSDESTINOS, //Error: The name fornecedores does not exist in the current context
                                                        ID_IMPOSTOSCONFIG = (int)produtosFornecedores.Max(item => item.ID_IMPOSTOSCONFIG),
                                                        ID_TABELANCMS = (int)produtosFornecedores.Max(item => item.ID_TABELANCMS),
                                                        ID_FORNECEDORES = (int)fornecedores.ID, //Error: The name fornecedores does not exist in the current context
                                                        CD_UF_BASE = (string)unidadesFederacao.CD_UNIDADEFEDERACAO //Error: The name unidadesFederacao does not exist in the current context
                                                    };

2 个答案:

答案 0 :(得分:3)

您在查询中遇到的问题是,您尝试在“分组依据”之后访问“来自”变量,而您无法执行此操作。为了获得这些变量,它们必须(1)保持在分组之外或(2)成为分组本身的一部分。

(1)

var prodForn2 =
    from produtosFornecedores in ERPDAOManager.GetTable<ProdutosFornecedores>()
    join fornecedores in ERPDAOManager.GetTable<Fornecedores>()
        on produtosFornecedores.ID_FORNECEDORES equals fornecedores.ID
    join municipios in ERPDAOManager.GetTable<Municipios>()
        on fornecedores.ID_MUNICIPIOS equals municipios.ID
    join unidadesFederacao in ERPDAOManager.GetTable<UnidadesFederacao>()
        on municipios.ID_UNIDADESFEDERACAO equals unidadesFederacao.ID
    where produtosFornecedores.ID_PRODUTOS ==
        Convert.ToInt32(objEsquemasCalculoRegras.CD_OBJETO1)
    where produtosFornecedores.ID_PRODUTOSCONFIGPRECOS ==
        Convert.ToInt32(objEsquemasCalculoRegras.CD_OBJETO2)
    where produtosFornecedores.FG_STATUS == true
    let ID_IMPOSTOSDESTINOS = (int)fornecedores.ID_IMPOSTOSDESTINOS
    let ID_FORNECEDORES = (int)fornecedores.ID
    let CD_UF_BASE = (string)unidadesFederacao.CD_UNIDADEFEDERACAO
    group produtosFornecedores by new
    {
        ID_IMPOSTOSDESTINOS,
        ID_FORNECEDORES,
        CD_UF_BASE,
    } into gpfs1
    select new
    {
        gpfs1.Key.ID_IMPOSTOSDESTINOS,
        gpfs1.Key.ID_FORNECEDORES,
        gpfs1.Key.CD_UF_BASE,
        PRODUTOSFORNECEDORES =
            from pfs1 in gpfs1
            group pfs1 by new
            {
                pfs1.ID_PRODUTOS,
                pfs1.ID_PRODUTOSCONFIGPRECOS
            } into gpfs2
            select new
            {
                NM_PRECO_REPOSICAO = (decimal)gpfs2
                    .Max(item => item.NM_PRECO_REPOSICAO),
                ID_MOEDAS_REPOSICAO = (int)gpfs2
                    .Max(item => item.ID_MOEDAS_REPOSICAO),
                ID_IMPOSTOSCONFIG = (int)gpfs2
                    .Max(item => item.ID_IMPOSTOSCONFIG),
                ID_TABELANCMS = (int)gpfs2
                    .Max(item => item.ID_TABELANCMS),
            },
    };

(2)

var prodForn2 =
    from produtosFornecedores in ERPDAOManager.GetTable<ProdutosFornecedores>()
    join fornecedores in ERPDAOManager.GetTable<Fornecedores>()
        on produtosFornecedores.ID_FORNECEDORES equals fornecedores.ID
    join municipios in ERPDAOManager.GetTable<Municipios>()
        on fornecedores.ID_MUNICIPIOS equals municipios.ID
    join unidadesFederacao in ERPDAOManager.GetTable<UnidadesFederacao>()
        on municipios.ID_UNIDADESFEDERACAO equals unidadesFederacao.ID
    where produtosFornecedores.ID_PRODUTOS ==
        Convert.ToInt32(objEsquemasCalculoRegras.CD_OBJETO1)
    where produtosFornecedores.ID_PRODUTOSCONFIGPRECOS ==
        Convert.ToInt32(objEsquemasCalculoRegras.CD_OBJETO2)
    where produtosFornecedores.FG_STATUS == true
    let ID_IMPOSTOSDESTINOS = (int)fornecedores.ID_IMPOSTOSDESTINOS
    let ID_FORNECEDORES = (int)fornecedores.ID
    let CD_UF_BASE = (string)unidadesFederacao.CD_UNIDADEFEDERACAO
    group produtosFornecedores by new
    {
        ID_IMPOSTOSDESTINOS,
        ID_FORNECEDORES,
        CD_UF_BASE,
        produtosFornecedores.ID_PRODUTOS,
        produtosFornecedores.ID_PRODUTOSCONFIGPRECOS,
    } into gpfs
    select new
    {
        gpfs.Key.ID_IMPOSTOSDESTINOS,
        gpfs.Key.ID_FORNECEDORES,
        gpfs.Key.CD_UF_BASE,
        NM_PRECO_REPOSICAO = (decimal)gpfs.Max(item => item.NM_PRECO_REPOSICAO),
        ID_MOEDAS_REPOSICAO = (int)gpfs.Max(item => item.ID_MOEDAS_REPOSICAO),
        ID_IMPOSTOSCONFIG = (int)gpfs.Max(item => item.ID_IMPOSTOSCONFIG),
        ID_TABELANCMS = (int)gpfs.Max(item => item.ID_TABELANCMS),
    };

让每一个都更好,看看哪个更适合您的需求。

您可能还会发现性能是分组和多个最大查询的问题,因此在将结果分组之前将记录放入内存可能是值得的。

var prodForn2_1 =
    from produtosFornecedores in ERPDAOManager.GetTable<ProdutosFornecedores>()
    join fornecedores in ERPDAOManager.GetTable<Fornecedores>()
        on produtosFornecedores.ID_FORNECEDORES equals fornecedores.ID
    join municipios in ERPDAOManager.GetTable<Municipios>()
        on fornecedores.ID_MUNICIPIOS equals municipios.ID
    join unidadesFederacao in ERPDAOManager.GetTable<UnidadesFederacao>()
        on municipios.ID_UNIDADESFEDERACAO equals unidadesFederacao.ID
    where produtosFornecedores.ID_PRODUTOS ==
        Convert.ToInt32(objEsquemasCalculoRegras.CD_OBJETO1)
    where produtosFornecedores.ID_PRODUTOSCONFIGPRECOS ==
        Convert.ToInt32(objEsquemasCalculoRegras.CD_OBJETO2)
    where produtosFornecedores.FG_STATUS == true
    let ID_IMPOSTOSDESTINOS = (int)fornecedores.ID_IMPOSTOSDESTINOS
    let ID_FORNECEDORES = (int)fornecedores.ID
    let CD_UF_BASE = (string)unidadesFederacao.CD_UNIDADEFEDERACAO
    select new
    {
        ID_IMPOSTOSDESTINOS = (int)fornecedores.ID_IMPOSTOSDESTINOS,
        ID_FORNECEDORES = (int)fornecedores.ID,
        CD_UF_BASE = (string)unidadesFederacao.CD_UNIDADEFEDERACAO,
        ID_PRODUTOS = produtosFornecedores.ID_PRODUTOS,
        ID_PRODUTOSCONFIGPRECOS = produtosFornecedores.ID_PRODUTOSCONFIGPRECOS,
        NM_PRECO_REPOSICAO = (decimal)produtosFornecedores.NM_PRECO_REPOSICAO,
        ID_MOEDAS_REPOSICAO = (int)produtosFornecedores.ID_MOEDAS_REPOSICAO,
        ID_IMPOSTOSCONFIG = (int)produtosFornecedores.ID_IMPOSTOSCONFIG,
        ID_TABELANCMS = (int)produtosFornecedores.ID_TABELANCMS,
    };

var prodForn2_2 =
    from pf in prodForn2_1.ToArray()
    group ...

现在您只需要使用上面的选项(1)或(2)完成prodForn2_2。请注意,ToArray调用将强制prodForn2_1查询执行并将记录作为数组存入内存 - 然后分组和子查询会非常快。您只需要注意内存使用而不是查询执行时间。

我希望这会有所帮助。

答案 1 :(得分:0)

我通过这种方式决定使用:

var prodForn = from produtosFornecedores in ERPDAOManager.GetTable<ProdutosFornecedores>()
                                                   //Inner Join com Fornecedores
                                                   join fornecedores in ERPDAOManager.GetTable<Fornecedores>()
                                                        on produtosFornecedores.ID_FORNECEDORES equals fornecedores.ID
                                                   //Inner Join com Municipios
                                                   join municipios in ERPDAOManager.GetTable<Municipios>()
                                                       on fornecedores.ID_MUNICIPIOS equals municipios.ID
                                                   //Inner Join com UnidadesFederacao
                                                   join unidadesFederacao in ERPDAOManager.GetTable<UnidadesFederacao>()
                                                       on municipios.ID_UNIDADESFEDERACAO equals unidadesFederacao.ID
                                                   //Filtros
                                                   where produtosFornecedores.ID_PRODUTOS == Convert.ToInt32(objEsquemasCalculoRegras.CD_OBJETO1) &&
                                                         produtosFornecedores.ID_PRODUTOSCONFIGPRECOS == Convert.ToInt32(objEsquemasCalculoRegras.CD_OBJETO2) &&
                                                         produtosFornecedores.FG_STATUS == true
                                                   group produtosFornecedores by new
                                                   {
                                                       ID_IMPOSTOSDESTINOS = fornecedores.ID_IMPOSTOSDESTINOS,
                                                       ID_FORNECEDORES = fornecedores.ID,
                                                       CD_UF_BASE = unidadesFederacao.CD_UNIDADEFEDERACAO,
                                                       produtosFornecedores.ID_PRODUTOS,
                                                       produtosFornecedores.ID_PRODUTOSCONFIGPRECOS
                                                   } into grpProdutosFornecedores
                                                   select new
                                                   {
                                                       grpProdutosFornecedores.Key.ID_IMPOSTOSDESTINOS,
                                                       grpProdutosFornecedores.Key.ID_FORNECEDORES,
                                                       grpProdutosFornecedores.Key.CD_UF_BASE,
                                                       NM_PRECO_REPOSICAO = (decimal)grpProdutosFornecedores.Max(item => item.NM_PRECO_REPOSICAO),
                                                       ID_MOEDAS_REPOSICAO = (int)grpProdutosFornecedores.Max(item => item.ID_MOEDAS_REPOSICAO),
                                                       ID_IMPOSTOSCONFIG = (int)grpProdutosFornecedores.Max(item => item.ID_IMPOSTOSCONFIG),
                                                       ID_TABELANCMS = (int)grpProdutosFornecedores.Max(item => item.ID_TABELANCMS)
                                                   };

                                    if (prodForn.Count() > 0)
                                    {
                                        NM_VALOR1 = prodForn.First().NM_PRECO_REPOSICAO;
                                        NM_VALOR2 = prodForn.First().ID_MOEDAS_REPOSICAO;
                                        ID_IMPOSTOSDESTINOS = prodForn.First().ID_IMPOSTOSDESTINOS;
                                        ID_IMPOSTOSCONFIG = prodForn.First().ID_IMPOSTOSCONFIG;
                                        ID_TABELANCMS = prodForn.First().ID_TABELANCMS;
                                        ID_FORNECEDORES = prodForn.First().ID_FORNECEDORES;
                                        CD_UF_BASE = prodForn.First().CD_UF_BASE;
                                    }