Подтвердить что ты не робот

Linq to Entity с несколькими левыми внешними соединениями

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

Компания, компанияПродукт, продукт

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

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

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, связанных с ProductID из 14. Таким образом, результаты SQL-запроса представляют собой ожидаемые 3 строки, 2 из которых связаны с CompanyProduct и продуктом и 1, который просто имеет компанию таблицы и нулей в таблицах CompanyProduct и Product.

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

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

Спасибо.

4b9b3361

Ответ 1

Решил!

Конечный результат:

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 - Объект в VS.NET 2008

alt text http://i478.photobucket.com/albums/rr148/KyleLanser/companyproduct.png
Имя контейнера сущностей является "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  

Ответ 2

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

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


    };

Вот как я это сделал.

Ответ 3

Вы хотите использовать 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
            };

Пожалуйста, используйте кнопку "Добавить комментарий", если вы хотите предоставить больше информации, а не создавать другой ответ.

Ответ 5

Обычное объединение групп представляет собой левое внешнее соединение. Попробуйте следующее:

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

Попробуйте что-то вроде этого:

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;

Ура!

Ответ 7

Как насчет этого (у вас есть много-много отношений между компанией и продуктом в вашем дизайнере объектов, не так ли?):

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

Entity Framework должна быть способна определить тип используемого соединения.