2012-03-15 37 views
62

我试图执行一个LINQ中的多个表之间的连接。我有以下类:如何执行LINQ lambda中的多个表之间的连接

Product {Id, ProdName, ProdQty} 

Category {Id, CatName} 

ProductCategory{ProdId, CatId} //association table 

我使用下面的代码(其中productcategoryproductcategory是上述类的实例):

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

我怎样才能实现这一目标?

+0

我不明白...为什么** m.ProdId = ** **而不是** prodId = m.ProdId **? – 2012-03-15 13:03:12

+0

因为我不知道如何导航和获得产品 – CiccioMiami 2012-03-15 13:16:27

回答

124

对于加入,我强烈希望查询的语法对于那些愉快地隐藏所有细节(而不是其中的是透明标识符与中间投影相关,这在点语法等价中是明显的)。不过,你问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 
    }); 

如果需要,你可以保存加入到一个局部变量和以后重新使用它,但缺乏其他细节,相反,我认为没有理由引进的局部变量。

此外,您可以扔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 
    }; 

你的手可能是绑定在查询语法是否可用。我知道一些商店有这样的任务 - 通常基于这样的概念,即查询语法比点语法更有限。还有其他一些原因,比如“为什么我应该学习第二种语法,如果我可以在点语法中做更多的事情?“正如最后一部分所显示的那样 - 有些查询语法隐藏的细节可以让它值得接受,因为它带来了可读性的提高:所有那些你必须做的中间预测和标识符都非常适合不在前端和中心-stage在查询语法版本 - 他们是背景绒毛关我的香皂盒,现在 - 。无论如何,感谢您的问题:)

+3

谢谢你的解决方案更完整。我同意在某些情况下查询语法更清晰,但你猜对了,我被要求使用lambda。此外,我必须使这个连接超过6桌,并在这种情况下,点符号更整齐 – CiccioMiami 2012-03-15 15:27:36

+0

+1完美... !!! – 2014-08-21 10:31:45

+0

@devgeezer如果我们需要'JOIN'语句中的附加条件呢?我们如何做到这一点?例如,在'pc.productcategory中加入pc到p.Id等于pc.ProdId'行,我们需要添加'和p.Id == 1'。 – 2016-09-27 02:30:33

9

你看到的就是你得到了什么 - 这是你问什么,可以在这里:

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

这是一个lambda表达式返回一个匿名类型与这两个属性。

在你CategorizedProducts,你只需要通过这些属性去:

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

谢谢。我理解关于匿名类的讨论,但其属性仅包含满足查询的类对象?我执行2连接后会发生什么? productproductcategory.product没有加入category right? – CiccioMiami 2012-03-15 13:15:47

+0

@CiccioMiami:嗯,属性是*对象的引用,是的。 “未加入”的含义并不十分清楚 - 您希望从查询中获得哪些信息? – 2012-03-15 13:17:54

+0

第一次加入时,我获得了产品和产品类别之间的连接。随着第二我得到产品类别(加入产品)和类别之间的联接。这意味着关于多重连接的信息只包含在productproductcategory中。这意味着产品(和类别)只与产品类别连接。 – CiccioMiami 2012-03-15 13:30:47

3

看一看这一示例代码从我的项目

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个表格,并且从第

号 号 号

号开始连接条件注意:服务类只是被扭曲(encapsu后期)数据库操作

1
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

虽然此代码段可能会解决问题,但[包括解释](http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers)确实有助于提高帖子的质量。请记住,您将来会为读者回答问题,而这些人可能不知道您的代码建议的原因。 – 2017-03-29 12:38:02

相关问题