2008-09-16 21 views
20

Estoy tratando de comprender las uniones externas a la izquierda en LINQ to Entity. Por ejemplo, tengo las siguientes tablas: 3Linq a Entidad con múltiples combinaciones externas a la izquierda

Company, CompanyProduct, Producto

El CompanyProduct está vinculado a sus dos mesas de padres, de empresas y productos.

Quiero devolver todos los registros de la Compañía y el CompanyProduct asociado, independientemente de que exista o no el producto de la compañía para un producto determinado. En Transact SQL que iría desde la mesa de la empresa utilizando externa izquierda se une como sigue:

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 cuenta con 3 empresas, y 2 registros CompanyProduct assocaited con el ProductID 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 la Compañía y 1 que simplemente tiene la tabla de la Compañía y los nulos en las tablas Producto y Producto de la Compañía.

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

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

Gracias.

Respuesta

0

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

¿Qué hay de este (que tienen una relación muchos-a-muchos relación entre la empresa y el producto en su Entity Designer, ¿verdad?):

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

Entidad marco debe ser capaz de averiguar el tipo de unión para usar.

16

¡Solucionado!

Salida final:

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

Aquí está el panorama

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

alt text http://i478.photobucket.com/albums/rr148/KyleLanser/companyproduct.png
La Entidad Nombre de contenedor es testEntities '' (como se ve en el modelo de ventana Propiedades)

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 - La salida final

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

'.Select (e => e)' no funciona, y puede eliminarse. Por supuesto, si solo está usando la ID, ¿por qué no decir '.Select (e => e.id)'? – StriplingWarrior

5

Usted querrá utilizar el marco de la entidad para establecer un mapeo muchos-a-muchos de ellos de la empresa de productos. Esto utilizará la tabla CompanyProduct, pero hará que no sea necesario 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 quiera representar los datos. Por ejemplo, si solo desea que todas las empresas que tienen un producto determinado, se 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 de producto junto con las empresas. Si eso es lo que vamos a dar, puede intentar:

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

favor utilice el botón "Añadir comentario" si desea proporcionar más información, en lugar de crear otra respuesta.

+0

No creo que lo haya resuelto, encontró una solución. – theKing

+0

@theKing: me permito diferir. El OP preguntó: "Entonces, ¿cómo se escribe el mismo tipo de unión en LINQ to Entity para obtener un resultado similar?" La forma correcta de hacer esto en LINQ to Entities * es * para establecer una relación many-to-many y acceder a las entidades relacionadas a través de la propiedad de relación. Ves que la solución final de OP usó la misma estrategia. ¿Qué aspecto de la pregunta no pude resolver? – StriplingWarrior

+0

También encontró un trabajo alrededor también. La solución está en este enlace http://msdn.microsoft.com/en-us/library/bb896266.aspx que es proporcionado por Mitch debajo de – theKing

1

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 se da todos los registros de table1 que no tienen una referencia a table2. Si omite la oración where, obtiene todos los registros de table1.

6

TI debe 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 


    }; 

Esta es la forma en que lo hice .. ..

Cuestiones relacionadas