it-swarm-es.tech

Linq a Entity con múltiples combinaciones externas izquierdas

Estoy tratando de entender las uniones externas izquierdas en LINQ to Entity. Por ejemplo, tengo las siguientes 3 tablas:

Empresa, Empresa Producto, Producto

CompanyProduct está vinculado a sus dos tablas principales, Company y Product.

Deseo devolver todos los registros de la Compañía y el Producto de la Compañía asociado, ya sea que el Producto de la Compañía exista o no para un producto determinado. En Transact SQL, iría de la tabla Company usando combinaciones externas izquierdas de la siguiente manera:

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

Mi base de datos tiene 3 empresas y 2 registros de Producto de empresa asociados con el ID de producto de 14. Por lo tanto, los resultados de la consulta SQL son las 3 filas esperadas, 2 de las cuales están conectadas a un Producto y producto de empresa y 1 que simplemente tiene la tabla Empresa y los valores nulos en las tablas de Producto y Producto de la Compañía.

Entonces, ¿cómo se escribe el mismo tipo de unión en LINQ to Entity para lograr un resultado similar?

He intentado algunas cosas diferentes, pero no puedo obtener la sintaxis correcta.

Gracias.

20
Bob

¡Resuelto!

Salida final:

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

Aquí está el escenario

1 - La base de datos

--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 - Los datos

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 - La entidad en VS.NET 2008

texto alternativo http://i478.photobucket.com/albums/rr148/KyleLanser/companyproduct.png
El nombre del contenedor de la entidad es 'testEntities' (como se ve en la ventana Propiedades del modelo)

4 - El 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 - El resultado final

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

Debería ser algo como esto ...

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


    };

Así es como lo hice ...

6
Deepak

Deberá utilizar Entity Framework para configurar una asignación de muchos a muchos de la empresa al producto. Esto usará la tabla CompanyProduct, pero hará que sea innecesario tener una entidad CompanyProduct establecida en su modelo de entidad. Una vez que haya hecho eso, la consulta será muy simple y dependerá de las preferencias personales y de cómo desee representar los datos. Por ejemplo, si solo desea todas las empresas que tienen un producto determinado, podría decir:

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

o

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

Su consulta SQL devuelve la información del producto junto con las empresas. Si eso es lo que está buscando, puede intentar:

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

Utilice el botón "Agregar comentario" si desea proporcionar más información, en lugar de crear otra respuesta.

5
StriplingWarrior

Las UNIONES EXTERIORES IZQUIERDAS se realizan utilizando GroupJoin en Entity Framework:

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

2
Mitch

La unión de grupo normal representa una unión externa izquierda. Prueba esto:

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() };

Ese ejemplo te da todos los registros de table1 que no tienen una referencia a table2. Si omite la oración where, obtendrá todos los registros de table1.

1
Martin

Por favor intente algo como esto:

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;

¡Salud!

0
dimarzionist

¿Qué pasa con este (tiene una relación de muchos a muchos entre la Compañía y el Producto en su Entity Designer, ¿no es así?):

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

Entity Framework debería poder determinar el tipo de combinación que se utilizará.

0
liggett78