LINQ with Left Outer Join in Manytomany

Asked

Viewed 90 times

2

I searched a lot about LINQ and Extension Methods, but I did not find a solution for this query that I need to do. The fact is that I have the model below (I left only the entities used) and I need to bring the Notafiscal, its Status (from the Notafiscal table), and bring if this status has registration in the Permission table (here enters the LEFT OUTER JOIN): Models

I’m trying to find a solution to a query in LINQ or Extension Methods resulting in the SQL query below:

SELECT TOP 1000
[Extent1].[IdNotaFiscal] AS [IdNotaFiscal], 
[Extent1].[Numero] AS [Numero], 
[Extent1].[IdFornecedor] AS [IdFornecedor], 
[Extent1].[DataEmissao] AS [DataEmissao], 
[Extent1].[IdNotaFiscalStatus] AS [IdNotaFiscalStatus], 
[Extent1].[Valor] AS [Valor], 
[Extent2].[Status] AS [Status], 
CASE WHEN ([Extent3].[IdPermissao] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
FROM   [dbo].[NotaFiscal] AS [Extent1]
INNER JOIN [dbo].[NotaFiscalStatus] AS [Extent2] ON [Extent1].[IdNotaFiscalStatus] = [Extent2].[IdNotaFiscalStatus]
LEFT OUTER JOIN [dbo].[Permissao] AS [Extent3] ON [Extent3].[IdNotaFiscalStatus] = [Extent2].[IdNotaFiscalStatus]
--Até aqui já consegui usando o Extension Methods, conforme próximo trecho de código
--A linha abaixo que preciso adicionar, a variável já está com valor atribuído
AND [Extent3].[IdAcessoTipo] = @IdAcessoTipo 

With the code below I came as close as expected, but still need to filter by idAcessoTipo:

            var notasfiscais = (from s in db.NotaFiscal select s)
                                   .Include(n => n.NotaFiscalStatus) 
                                   .Include(p => p.NotaFiscalStatus.Permissao);

Which resulted in query below, which makes a duplicate query (it would be better if it did not):

SELECT 
[Project1].[Sequencia] AS [Sequencia], 
[Project1].[IdNotaFiscal] AS [IdNotaFiscal], 
[Project1].[Numero] AS [Numero], 
[Project1].[IdFornecedor] AS [IdFornecedor], 
[Project1].[DataEmissao] AS [DataEmissao], 
[Project1].[Parcelas] AS [Parcelas], 
[Project1].[IdNotaFiscalStatus] AS [IdNotaFiscalStatus], 
[Project1].[Valor] AS [Valor], 
[Project1].[DataHoraCadastro] AS [DataHoraCadastro], 
[Project1].[DataHoraAlteracao] AS [DataHoraAlteracao], 
[Project1].[IdUsuarioAlteracao] AS [IdUsuarioAlteracao], 
[Project1].[IdNotaFiscalStatus1] AS [IdNotaFiscalStatus1], 
[Project1].[Status] AS [Status], 
[Project1].[BotaoIncremento] AS [BotaoIncremento], 
[Project1].[FluxoAprovacao] AS [FluxoAprovacao], 
[Project1].[C1] AS [C1], 
[Project1].[IdPermissao] AS [IdPermissao], 
[Project1].[IdAcessoTipo] AS [IdAcessoTipo], 
[Project1].[IdNotaFiscalStatus2] AS [IdNotaFiscalStatus2]
FROM ( SELECT 
    [Extent1].[IdNotaFiscal] AS [IdNotaFiscal], 
    [Extent1].[Numero] AS [Numero], 
    [Extent1].[IdFornecedor] AS [IdFornecedor], 
    [Extent1].[DataEmissao] AS [DataEmissao], 
    [Extent1].[Parcelas] AS [Parcelas], 
    [Extent1].[IdNotaFiscalStatus] AS [IdNotaFiscalStatus], 
    [Extent1].[Valor] AS [Valor], 
    [Extent1].[DataHoraCadastro] AS [DataHoraCadastro], 
    [Extent1].[DataHoraAlteracao] AS [DataHoraAlteracao], 
    [Extent1].[IdUsuarioAlteracao] AS [IdUsuarioAlteracao], 
    [Extent2].[IdNotaFiscalStatus] AS [IdNotaFiscalStatus1], 
    [Extent2].[Status] AS [Status], 
    [Extent2].[Sequencia] AS [Sequencia], 
    [Extent2].[BotaoIncremento] AS [BotaoIncremento], 
    [Extent2].[FluxoAprovacao] AS [FluxoAprovacao], 
    [Extent3].[IdPermissao] AS [IdPermissao], 
    [Extent3].[IdAcessoTipo] AS [IdAcessoTipo], 
    [Extent3].[IdNotaFiscalStatus] AS [IdNotaFiscalStatus2], 
    CASE WHEN ([Extent3].[IdPermissao] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
    FROM   [dbo].[NotaFiscal] AS [Extent1]
    INNER JOIN [dbo].[NotaFiscalStatus] AS [Extent2] ON [Extent1].[IdNotaFiscalStatus] = [Extent2].[IdNotaFiscalStatus]
    LEFT OUTER JOIN [dbo].[Permissao] AS [Extent3] ON [Extent3].[IdNotaFiscalStatus] = [Extent1].[IdNotaFiscalStatus]
)  AS [Project1]
ORDER BY [Project1].[IdNotaFiscal] ASC, [Project1].[IdNotaFiscalStatus1] ASC, [Project1].[C1] ASC

I tried to use Groupjoin and Where and various combinations with the same, but without success. Follow the classes involved:

Notafiscal.Cs:

public partial class NotaFiscal
{
    public NotaFiscal()
    {
        this.Parcela = new HashSet<Parcela>();
    }

    public long IdNotaFiscal { get; set; }
    public string Numero { get; set; }
    public long IdFornecedor { get; set; }
    public System.DateTime DataEmissao { get; set; }
    public Nullable<int> Parcelas { get; set; }
    public long IdNotaFiscalStatus { get; set; }
    public decimal Valor { get; set; }
    public System.DateTime DataHoraCadastro { get; set; }
    public Nullable<System.DateTime> DataHoraAlteracao { get; set; }
    public Nullable<long> IdUsuarioAlteracao { get; set; }

    public virtual ACESSO ACESSO { get; set; }
    public virtual Fornecedor Fornecedor { get; set; }
    public virtual ICollection<Parcela> Parcela { get; set; }
    public virtual NotaFiscalStatus NotaFiscalStatus { get; set; }
}

Notafiscalstatus.Cs:

public partial class NotaFiscalStatus
{
    public NotaFiscalStatus()
    {
        this.Permissao = new HashSet<Permissao>();
    }

    public long IdNotaFiscalStatus { get; set; }
    public string Status { get; set; }
    public int Sequencia { get; set; }
    public string BotaoIncremento { get; set; }
    public Nullable<bool> FluxoAprovacao { get; set; }
    public virtual ICollection<Permissao> Permissao { get; set; }
}

Permissao.Cs:

public partial class Permissao
{
    public long IdPermissao { get; set; }
    public long IdAcessoTipo { get; set; }
    public long IdNotaFiscalStatus { get; set; }
    public virtual AcessoTipo AcessoTipo { get; set; }
    public virtual NotaFiscalStatus NotaFiscalStatus { get; set; }
}

Acessotipo.Cs:

public partial class AcessoTipo
{
    public AcessoTipo()
    {
        this.ACESSO = new HashSet<ACESSO>();
        this.Permissao = new HashSet<Permissao>();
    }

    public long IdAcessoTipo { get; set; }
    public string Tipo { get; set; }
    public virtual ICollection<ACESSO> ACESSO { get; set; }
    public virtual ICollection<Permissao> Permissao { get; set; }
}

I found some similar cases, but their implementation did not cause the expected result.

Edit:

The closest I came was with LINQ, with the code below, but the clause Where needs to be inside the last Join to bring the null tuples from the permission table:

var notasfiscais3 = from s in db.NotaFiscal
                            join n in db.NotaFiscalStatus on s.IdNotaFiscalStatus equals n.IdNotaFiscalStatus
                            join p in db.Permissao on n.IdNotaFiscalStatus equals p.IdNotaFiscalStatus
                            where p.IdAcessoTipo == idAcessoTipo
                            let y = new { n, s, Permissao = p == null ? 0 : 1 }
                            select y;

And trying to make the comparison with the code below is presented the error "The type of one of the expressions in the Join clause is incorrect. Type inference failed in "Join".":

var notasfiscais4 = from s in db.NotaFiscal
                            join n in db.NotaFiscalStatus on s.IdNotaFiscalStatus equals n.IdNotaFiscalStatus
                            join p in db.Permissao on new {n.IdNotaFiscalStatus, idAcessoTipo}
                            equals new {p.IdNotaFiscalStatus, p.IdAcessoTipo}
                            let y = new { n, s, Permissao = p == null ? 0 : 1 }
                            select y;

Even trying to do cast for the guy long in various ways in idAcessoTipo.

Edit2: I managed to create the query, but returns a IQuerable of an anonymous type, causing conflict with the Notafiscal type. Is there any other way to return of the same type with extra fields? Follows the code:

var notasfiscais = (from s in db.NotaFiscal select s);
notasfiscais = notasfiscais.Include(n => n.NotaFiscalStatus);
///
// Aqui existe alguns filtros com método Where
///
var notasfiscaisresultado = notasfiscais.Include(p => p.NotaFiscalStatus.Permissao)
            .GroupJoin(db.Permissao, n => n.IdNotaFiscalStatus, p => p.IdNotaFiscalStatus,
            (n, p) => new { NotaF = n, Permissao = p });
// Acima tive que criar outra variável para aceitar o novo tipo anônimo
  • if you have to do it with join to work

  • I did it with two joins and it "erases" the first (from n in db.Notafiscal Join s in db.Notafiscalstatus on n.Idnotafiscalstatus equals.Idnotafiscalstatus Join m in db. Permissao on s.Idnotafiscalstatus equals m.Idnotafiscalstatus Where m.Idacessotype == idAccessType select n)

No answers

Browser other questions tagged

You are not signed in. Login or sign up in order to post.