2008-09-16 5 views
20

Я пытаюсь понять левые внешние соединения в LINQ to Entity. Например, у меня есть следующие 3 таблицы:Linq to Entity с несколькими левыми внешними соединениями

Company, CompanyProduct, продукт

CompanyProduct связан с его двумя родительскими таблицами, компании и продукта.

Я хочу вернуть все записи Компании и связанный с ними CompanyProduct независимо от того, существует ли КомпанияProduct или нет для данного продукта. В Transact SQL я бы из таблицы компании, используя левый внешнее соединение следующим образом:

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 

Моя база данных имеет 3 компаний и 2 CompanyProduct записи assocaited с ProductID из 14. Таким образом, результаты запроса SQL являются ожидаемые 3 строки, 2 из которых связаны с CompanyProduct и продуктом и 1, который просто имеет таблицу компании и нули в таблицах CompanyProduct и Product.

Итак, как вы пишете одно и то же соединение в LINQ to Entity, чтобы получить аналогичный результат?

Я пробовал несколько разных вещей, но не могу получить синтаксис правильно.

Спасибо.

ответ

0

Пожалуйста, попробуйте что-то вроде этого:

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; 

Ура!

0

насчет этого (у вас есть много-ко-многим между Компанией и накопленную в Entity Designer, не так ли?):

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

Entity Framework должны быть в состоянии выяснить, тип соединения для использования.

16

Решено!

Окончательный выход:

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

Вот сценарий

1 - База данных

--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 - Данные

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 - The Entity в VS.NET 2008

alt text http://i478.photobucket.com/albums/rr148/KyleLanser/companyproduct.png
Платформа Entity Container имя 'testEntities' (как показано в модели окне Свойства)

4 - Код (НАКОНЕЦ!)

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 - Окончательный выход

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

`. Выбрать (e => e)` is no-op и может быть удален. Конечно, если вы используете только идентификатор, почему бы не сказать `.Select (e => e.id)`? – StriplingWarrior 2010-11-04 15:32:17

5

Вы хотите использовать Entity Framework, чтобы создать много-ко-многим отображение от Компании к продукту. Это будет использовать таблицу CompanyProduct, но не потребует, чтобы в модели сущности был установлен объект CompanyProduct. Как только вы это сделаете, запрос будет очень простым, и это будет зависеть от личных предпочтений и того, как вы хотите представлять данные. Например, если вы просто хотите, чтобы все компании, которые имеют данный продукт, вы могли бы сказать:

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

или

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

Ваш SQL-запрос возвращает информацию о продукте вместе с компаниями. Если это то, что вы собираетесь, вы можете попробовать:

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

Пожалуйста, используйте кнопку «Добавить комментарий», если вы хотите, чтобы предоставить более подробную информацию, а не создавать еще один ответ.

+0

Я не думаю, что вы это решили, вы нашли обходное решение. – theKing 2010-11-04 06:34:41

1

Нормальное объединение групп представляет собой левое внешнее соединение. Попробуйте это:

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

Этот пример дает вам все записи из table1, которые не имеют ссылки на table2. Если вы опустите предложение where, вы получите все записи table1.

6

IT должно быть что-то вроде этого ....

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 


    }; 

Это, как я сделал .. ..