web-dev-qa-db-ja.com

LINQ lambdaで複数のテーブル間で結合を実行する方法

LINQで複数のテーブル間の結合を実行しようとしています。次のクラスがあります。

Product {Id, ProdName, ProdQty}

Category {Id, CatName}

ProductCategory{ProdId, CatId} //association table

そして、次のコードを使用します(productcategory、およびproductcategoryは上記のクラスのインスタンスです)。

var query = product.Join(productcategory, p => p.Id, pc => pc.ProdID, (p, pc) => new {product = p, productcategory = pc})
                   .Join(category, ppc => ppc.productcategory.CatId, c => c.Id, (ppc, c) => new { productproductcategory = ppc, category = c});

このコードを使用して、次のクラスからオブジェクトを取得します。

QueryClass { productproductcategory, category}

Producproductcategoryのタイプは次のとおりです。

ProductProductCategoryClass {product, productcategory}

結合された「テーブル」がどこにあるのかわかりませんが、関連するクラスのすべてのプロパティを含む単一クラスを期待していました。

私の目的は、クエリから得られるいくつかのプロパティを別のオブジェクトに設定することです。

CategorizedProducts catProducts = query.Select(m => new { m.ProdId = ???, m.CatId = ???, //other assignments });

どうすればこの目標を達成できますか?

80
CiccioMiami

結合については、幸福に隠されているすべての詳細について、クエリ構文を強くお勧めします(ドット構文に相当する方法に沿って、中間投影に関係する透明な識別子は少なくとも重要ではありません)。ただし、必要なものはすべて揃っていると思うLambdasについて質問しました。すべてをまとめる必要があります。

var categorizedProducts = product
    .Join(productcategory, p => p.Id, pc => pc.ProdId, (p, pc) => new { p, pc })
    .Join(category, ppc => ppc.pc.CatId, c => c.Id, (ppc, c) => new { ppc, c })
    .Select(m => new { 
        ProdId = m.ppc.p.Id, // or m.ppc.pc.ProdId
        CatId = m.c.CatId
        // other assignments
    });

必要に応じて、ローカル変数に結合を保存して後で再利用できますが、他の詳細が欠けているため、ローカル変数を導入する理由はありません。

また、2番目のSelectの最後のラムダにJoinをスローできます(これも、結合結果に依存する他の操作がない場合)。

var categorizedProducts = product
    .Join(productcategory, p => p.Id, pc => pc.ProdId, (p, pc) => new { p, pc })
    .Join(category, ppc => ppc.pc.CatId, c => c.Id, (ppc, c) => new {
        ProdId = ppc.p.Id, // or ppc.pc.ProdId
        CatId = c.CatId
        // other assignments
    });

...そしてクエリ構文で最後の販売を試みると、これは次のようになります。

var categorizedProducts =
    from p in product
    join pc in productcategory on p.Id equals pc.ProdId
    join c in category on pc.CatId equals c.Id
    select new {
        ProdId = p.Id, // or pc.ProdId
        CatId = c.CatId
        // other assignments
    };

Query-syntaxが利用可能かどうかは、あなたの手に縛られているかもしれません。クエリ構文はドット構文よりもいくぶん制限されているという考えに基づいていることがよくあります。 「ドット構文ですべてを実行できるのに、なぜ2番目の構文を学ぶ必要があるのか​​」など、他の理由もあります。この最後の部分が示すように、クエリ構文が非表示にする詳細があり、それがもたらす読みやすさの改善を受け入れる価値があります。クエリ構文バージョンのステージ-バックグラウンドフラフです。今私の石鹸箱から-とにかく、質問をありがとう。 :)

159
devgeezer

あなたが見たものはあなたが得るものです-そしてそれはまさにあなたが求めたものです、ここに:

(ppc, c) => new { productproductcategory = ppc, category = c}

それは、これらの2つのプロパティを持つ匿名型を返すラムダ式です。

CategorizedProductsでは、これらのプロパティを経由するだけです。

CategorizedProducts catProducts = query.Select(
      m => new { 
             ProdId = m.productproductcategory.product.Id, 
             CatId = m.category.CatId, 
             // other assignments 
           });
10
Jon Skeet

私のプロジェクトからこのサンプルコードを見てください

public static IList<Letter> GetDepartmentLettersLinq(int departmentId)
{
    IEnumerable<Letter> allDepartmentLetters =
        from allLetter in LetterService.GetAllLetters()
        join allUser in UserService.GetAllUsers() on allLetter.EmployeeID equals allUser.ID into usersGroup
        from user in usersGroup.DefaultIfEmpty()// here is the tricky part
        join allDepartment in DepartmentService.GetAllDepartments() on user.DepartmentID equals allDepartment.ID
        where allDepartment.ID == departmentId
        select allLetter;

    return allDepartmentLetters.ToArray();
}

このコードでは、3つのテーブルを結合し、where句から結合条件を調べました

注:サービスクラスは、データベース操作をワープ(カプセル化)するだけです

4
 public ActionResult Index()
    {
        List<CustomerOrder_Result> obj = new List<CustomerOrder_Result>();

       var  orderlist = (from a in db.OrderMasters
                         join b in db.Customers on a.CustomerId equals b.Id
                         join c in db.CustomerAddresses on b.Id equals c.CustomerId
                         where a.Status == "Pending"
                         select new
                         {
                             Customername = b.Customername,
                             Phone = b.Phone,
                             OrderId = a.OrderId,
                             OrderDate = a.OrderDate,
                             NoOfItems = a.NoOfItems,
                             Order_amt = a.Order_amt,
                             dis_amt = a.Dis_amt,
                             net_amt = a.Net_amt,
                             status=a.Status,  
                             address = c.address,
                             City = c.City,
                             State = c.State,
                             Pin = c.Pin

                         }) ;
       foreach (var item in orderlist)
       {

           CustomerOrder_Result clr = new CustomerOrder_Result();
           clr.Customername=item.Customername;
           clr.Phone = item.Phone;
           clr.OrderId = item.OrderId;
           clr.OrderDate = item.OrderDate;
           clr.NoOfItems = item.NoOfItems;
           clr.Order_amt = item.Order_amt;
           clr.net_amt = item.net_amt;
           clr.address = item.address;
           clr.City = item.City;
           clr.State = item.State;
           clr.Pin = item.Pin;
           clr.status = item.status;

           obj.Add(clr);



       }
1

それはしばらくされていますが、私の答えは誰かを助けるかもしれません:

リレーションをすでに適切に定義している場合、これを使用できます:

        var res = query.Products.Select(m => new
        {
            productID = product.Id,
            categoryID = m.ProductCategory.Select(s => s.Category.ID).ToList(),
        }).ToList();
1
tahaGhSa
var query = from a in d.tbl_Usuarios
                    from b in d.tblComidaPreferidas
                    from c in d.tblLugarNacimientoes
                    select new
                    {
                        _nombre = a.Nombre,
                        _comida = b.ComidaPreferida,
                        _lNacimiento = c.Ciudad
                    };
        foreach (var i in query)
        {
            Console.WriteLine($"{i._nombre } le gusta {i._comida} y nació en {i._lNacimiento}");
        }
0
Alex Martinez