具有多个左外连接的Linq to Entity

时间:2008-09-16 23:54:58

标签: join linq-to-entities outer-join

我试图了解LINQ to Entity中的左外连接。例如,我有以下3个表:

公司,公司产品,产品

CompanyProduct链接到其两个父表,公司和产品。

我想要返回所有公司记录和关联的CompanyProduct,无论公司产品是否存在给定产品。在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和Product,1个只有公司CompanyProduct和Product表中的表和空值。

那么如何在LINQ to Entity中编写相同类型的连接来实现类似的结果呢?

我尝试了一些不同的东西,但无法正确理解语法。

感谢。

7 个答案:

答案 0 :(得分: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 - 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  

答案 1 :(得分: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


    };

这就是我做的......

答案 2 :(得分:5)

您需要使用实体框架来设置从公司到产品的多对多映射。这将使用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
            };

如果您想提供更多信息,请使用“添加评论”按钮,而不是创建其他答案。

答案 3 :(得分:2)

LEFT OUTER JOIN通过使用Entity Framework中的GroupJoin完成:

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

答案 4 :(得分: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的所有记录。

答案 5 :(得分: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;

干杯!

答案 6 :(得分:0)

这个怎么样(你的实体设计师确实有公司和产品之间的多对多关系,不是吗?):

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

实体框架应该能够确定要使用的联接类型。