web-dev-qa-db-fra.com

Comment effectuer une jointure entre plusieurs tables dans LINQ lambda

J'essaye d'effectuer un jointure entre plusieurs tables dans LINQ. J'ai les cours suivants:

Product {Id, ProdName, ProdQty}

Category {Id, CatName}

ProductCategory{ProdId, CatId} //association table

Et j'utilise le code suivant (où product, category et productcategory sont des instances des classes ci-dessus):

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

Avec ce code, j'obtiens un objet de la classe suivante:

QueryClass { productproductcategory, category}

Où la catégorie de produits est de type:

ProductProductCategoryClass {product, productcategory}

Je ne comprends pas où se trouve la "table" jointe, je m'attendais à une classe unique qui contient toutes les propriétés des classes impliquées.

Mon objectif est de renseigner un autre objet avec certaines propriétés résultant de la requête:

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

comment puis-je atteindre cet objectif?

81
CiccioMiami

Pour les jointures, je préfère fortement la syntaxe de requête pour tous les détails qui sont heureusement cachés (les identificateurs transparents impliqués dans les projections intermédiaires le long du chemin n'étant pas les moindres, comme en apparence dans l'équivalent de la syntaxe à points). Cependant, vous avez demandé à propos de Lambdas que je pense que vous avez tout ce dont vous avez besoin - il vous suffit de tout mettre en ordre.

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

Si vous en avez besoin, vous pouvez enregistrer la jointure dans une variable locale et la réutiliser ultérieurement, mais sans autre précision, je ne vois aucune raison d'introduire la variable locale.

De plus, vous pouvez jeter la Select dans le dernier lambda du second Join (encore une fois, à condition qu'aucune autre opération ne dépende du résultat de la jointure), ce qui donnerait:

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

... et faisant une dernière tentative pour vous vendre sur la syntaxe de requête, ceci ressemblerait à ceci:

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

Vos mains peuvent être liées si la syntaxe de requête est disponible. Je sais que certains magasins ont de tels mandats - souvent basés sur l’idée que la syntaxe de requête est un peu plus limitée que la syntaxe à points. Il y a d'autres raisons, comme "pourquoi devrais-je apprendre une seconde syntaxe si je peux tout faire et plus en syntaxe à points?" Comme le montre cette dernière partie, la syntaxe de la requête cache certains détails qui peuvent le rendre digne d'intérêt pour l'amélioration de la lisibilité: toutes les projections et les identifiants intermédiaires que vous devez préparer sont heureusement pas parfaitement centrés. étape dans la version de requête-syntaxe - ils sont fluff d'arrière-plan. Hors de ma boîte à savon maintenant - de toute façon, merci pour la question. :)

161
devgeezer

Ce que vous avez vu est ce que vous obtenez - et c'est exactement ce que vous avez demandé, ici:

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

C'est une expression lambda renvoyant un type anonyme avec ces deux propriétés.

Dans vos produits catégorisés, il vous suffit de passer par ces propriétés:

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

regardez cet exemple de code de mon projet

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

dans ce code, j'ai rejoint 3 tables et j'ai craché la condition de jointure de la clause où

remarque: les classes de services viennent juste de déformer (encapsuler) les opérations de base de données

4
Basheer AL-MOMANI
 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
saktiprasad swain

cela fait longtemps, mais ma réponse pourrait aider quelqu'un:

si vous avez déjà défini la relation correctement, vous pouvez utiliser ceci:

        var res = query.Products.Select(m => new
        {
            productID = product.Id,
            categoryID = m.ProductCategory.Select(s => s.Category.ID).ToList(),
        }).ToList();
0
iDeveloper
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