it-swarm-pt.tech

Linq to Entity com várias junções externas esquerdas

Estou tentando entender as associações externas à esquerda no LINQ to Entity. Por exemplo, eu tenho as seguintes 3 tabelas:

Empresa, EmpresaProduto, Produto

O CompanyProduct está vinculado às suas duas tabelas pai, Company e Product.

Desejo retornar todos os registros da empresa e o CompanyProduct associado, independentemente de o CompanyProduct existir ou não para um determinado produto. No Transact SQL, eu iria da tabela Company usando junções externas à esquerda da seguinte maneira:

SELECT * FROM Company AS C
LEFT OUTER JOIN  CompanyProduct AS CP ON C.CompanyID=CP.CompanyID
LEFT OUTER JOIN  Product AS P ON CP.ProductID=P.ProductID 
WHERE      P.ProductID = 14 OR P.ProductID IS NULL

Meu banco de dados possui 3 empresas e 2 registros CompanyProduct associados ao ProductID de 14. Portanto, os resultados da consulta SQL são as 3 linhas esperadas, 2 das quais estão conectadas a um CompanyProduct and Product e 1 que simplesmente possui a tabela Company e nulos nas tabelas CompanyProduct e Product.

Então, como você escreve o mesmo tipo de associação no LINQ to Entity para obter um resultado semelhante?

Eu tentei algumas coisas diferentes, mas não consigo obter a sintaxe correta.

Obrigado.

20
Bob

Resolvi-o!

Resultado final:

theCompany.id: 1  
theProduct.id: 14  
theCompany.id: 2  
theProduct.id: 14  
theCompany.id: 3  

Aqui está o cenário

1 - O banco de dados

--Company Table
CREATE TABLE [theCompany](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [value] [nvarchar](50) NULL,
 CONSTRAINT [PK_theCompany] PRIMARY KEY CLUSTERED 
( [id] ASC ) WITH (
    PAD_INDEX  = OFF, 
    STATISTICS_NORECOMPUTE  = OFF, 
    IGNORE_DUP_KEY = OFF, 
    ALLOW_ROW_LOCKS  = ON, 
    ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY];
GO


--Products Table
CREATE TABLE [theProduct](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [value] [nvarchar](50) NULL,
 CONSTRAINT [PK_theProduct] PRIMARY KEY CLUSTERED 
( [id] ASC
) WITH (    
    PAD_INDEX  = OFF, 
    STATISTICS_NORECOMPUTE  = OFF, 
    IGNORE_DUP_KEY = OFF, 
    ALLOW_ROW_LOCKS  = ON, 
    ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY];
GO


--CompanyProduct Table
CREATE TABLE [dbo].[CompanyProduct](
    [fk_company] [int] NOT NULL,
    [fk_product] [int] NOT NULL
) ON [PRIMARY];    
GO

ALTER TABLE [CompanyProduct]  WITH CHECK ADD CONSTRAINT
    [FK_CompanyProduct_theCompany] FOREIGN KEY([fk_company]) 
    REFERENCES [theCompany] ([id]);
GO

ALTER TABLE [dbo].[CompanyProduct] CHECK CONSTRAINT 
    [FK_CompanyProduct_theCompany];
GO

ALTER TABLE [CompanyProduct]  WITH CHECK ADD CONSTRAINT 
    [FK_CompanyProduct_theProduct] FOREIGN KEY([fk_product]) 
 REFERENCES [dbo].[theProduct] ([id]);
GO

ALTER TABLE [dbo].[CompanyProduct] CHECK CONSTRAINT 
    [FK_CompanyProduct_theProduct];

2 - Os dados

SELECT [id] ,[value] FROM theCompany
id          value
----------- --------------------------------------------------
1           company1
2           company2
3           company3

SELECT [id] ,[value]  FROM theProduct
id          value
----------- --------------------------------------------------
14          Product 1


SELECT [fk_company],[fk_product] FROM CompanyProduct;
fk_company  fk_product
----------- -----------
1           14
2           14

3 - A entidade no VS.NET 2008

texto alternativo http://i478.photobucket.com/albums/rr148/KyleLanser/companyproduct.png
O nome do contêiner da entidade é 'testEntities' (como visto na janela Propriedades do modelo)

4 - O Código (FINALMENTE!)

testEntities entity = new testEntities();

var theResultSet = from c in entity.theCompany
select new { company_id = c.id, product_id = c.theProduct.Select(e=>e) };

foreach(var oneCompany in theResultSet)
{
   Debug.WriteLine("theCompany.id: " + oneCompany.company_id);
    foreach(var allProducts in oneCompany.product_id)
    {
        Debug.WriteLine("theProduct.id: " + allProducts.id);
    }
}

5 - O resultado final

theCompany.id: 1  
theProduct.id: 14  
theCompany.id: 2  
theProduct.id: 14  
theCompany.id: 3  
16
KyleLanser

Deve ser algo assim ....

var query = from t1 in db.table1
    join t2 in db.table2
    on t1.Field1 equals t2.field1 into T1andT2
    from t2Join in T1andT2.DefaultIfEmpty()


    join t3 in db.table3
    on t2Join.Field2 equals t3.Field3 into T2andT3
    from t3Join in T2andT3.DefaultIfEmpty()
    where t1.someField = "Some value" 
    select 
    {
        t2Join.FieldXXX
        t3Join.FieldYYY


    };

Foi assim que eu fiz ....

6
Deepak

Você deseja usar o Entity Framework para configurar um mapeamento muitos para muitos da empresa para o produto. Isso usará a tabela CompanyProduct, mas tornará desnecessário ter uma entidade CompanyProduct definida em seu modelo de entidade. Depois de fazer isso, a consulta será muito simples e dependerá da preferência pessoal e de como você deseja representar os dados. Por exemplo, se você deseja apenas todas as empresas que possuem um determinado produto, pode dizer:

var query = from p in Database.ProductSet
            where p.ProductId == 14
            from c in p.Companies
            select c;

ou

var query = Database.CompanySet
            .Where(c => c.Products.Any(p => p.ProductId == 14));

Sua consulta SQL retorna as informações do produto junto com as empresas. Se é isso que você procura, tente:

var query = from p in Database.ProductSet
            where p.ProductId == 14
            select new
            {
                Product = p,
                Companies = p.Companies
            };

Por favor, use o botão "Adicionar comentário" se desejar fornecer mais informações, em vez de criar outra resposta.

5
StriplingWarrior

As junções externas esquerdas são feitas usando o GroupJoin no Entity Framework:

http://msdn.Microsoft.com/en-us/library/bb896266.aspx

2
Mitch

A junção normal do grupo representa uma junção externa esquerda. Tente o seguinte:

var list = from a in _datasource.table1
           join b in _datasource.table2
           on a.id equals b.table1.id
           into ab
           where ab.Count()==0
           select new { table1 = a, 
                        table2Count = ab.Count() };

Esse exemplo fornece todos os registros de table1 que não têm uma referência a table2. Se você omitir a frase where, obterá todos os registros de table1.

1
Martin

Por favor, tente algo como isto:

from s in db.Employees
join e in db.Employees on s.ReportsTo equals e.EmployeeId
join er in EmployeeRoles on s.EmployeeId equals er.EmployeeId
join r in Roles on er.RoleId equals r.RoleId
where e.EmployeeId == employeeId &&
er.Status == (int)DocumentStatus.Draft
select s;

Felicidades!

0
dimarzionist

E esse (você tem um relacionamento muitos para muitos entre Empresa e Produto em seu Entity Designer, não tem?):

from s in db.Employees
where s.Product == null || s.Product.ProductID == 14
select s;

O Entity Framework deve ser capaz de descobrir o tipo de associação a ser usada.

0
liggett78