web-dev-qa-db-ja.com

左外部結合が複数あるLinq to Entity

LINQ to Entityの左外部結合を理解しようとしています。たとえば、次の3つのテーブルがあります。

会社、会社製品、製品

CompanyProductは、2つの親テーブルCompanyおよびProductにリンクされています。

特定の製品のCompanyProductが存在するかどうかに関係なく、すべてのCompanyレコードと関連する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つはCompanyテーブルとnullのみを持っています。 CompanyProductテーブルとProductテーブル。

では、同様の結果を達成するために、LINQ to Entityで同じ種類の結合をどのように記述しますか?

いくつかのことを試しましたが、構文を正しく取得できません。

ありがとう。

20
Bob

解決しました!

最終出力:

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のエンティティ

代替テキスト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  
16
KyleLanser

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


    };

これは私がやった方法です...

6
Deepak

Entity Frameworkを使用して、CompanyからProductへの多対多のマッピングを設定します。これは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

LEFT OUTER JOINは、Entity FrameworkのGroupJoinを使用して行われます。

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

2
Mitch

通常のグループ結合は、左外部結合を表します。これを試して:

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のすべてのレコードが取得されます。

1
Martin

次のようなものを試してください:

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
dimarzionist

これについてはどうですか(エンティティデザイナーでは、会社と製品の間に多対多の関係がありますね)。

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

Entity Frameworkは、使用する結合のタイプを把握できる必要があります。

0
liggett78