【问题标题】:linq lambda multiple group joinslinq lambda 多组连接
【发布时间】:2017-12-08 16:33:16
【问题描述】:

我正在尝试获取产品列表及其评级、cmets 和视图。 PID是没有外键关系的产品ID列。

产品-

Id  Name
1   P1
2   P2

评分 -

Id  PID Rating
1   1   5
2   1   4
3   2   3

评论-

Id  PID Comment
1   1   Good
2   1   Average
3   2   Bad

观看次数 -

Id  PID View
1   1   500
2   1   200
3   2   10

我的班级应该是这样的——

Public Class Product{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Rating> Ratings{ get; set; }
    public List<Comments> Comments{ get; set; }
    public List<Views> Views{ get; set; }
}

我正在尝试使用 Linq 组加入来获取此信息,以便获得子集合。

IEnumerable<Product> _products = _context.Product.GroupJoin(_context.Rating, p=>p.id, r=>r.PID, (Product, Rating) => new Product(){
    //fill fields here
});

但是如何将其他表也分组到单个数据库查询中。

谢谢

【问题讨论】:

  • linq-to-sql 在您提交更改时自动处理对查询的分组。你在问什么?
  • 试试这样的代码:IEnumerable _products = (from p in _context.Product join r in _context.Rating on p.id equals r.id Join s in _context.Sales on p.id等于 s.id select new { p = p, r = r, s = s}).Select(x => new Product() { ..... }
  • 我想变成课堂上提到的父子格式。那是我组加入的地区。我想简单的连接将所有记录都变成了平面格式。如果我错了,请纠正我。

标签: c# linq lambda linq-to-sql entity


【解决方案1】:

您可以直接查找匹配项来构造Product 对象,而不是GroupJoin

IEnumerable<Product> _products = _context.Product.Select(product => new Product() {
    Id = product.id,
    Name = product.name,
    Ratings = _context.Rating.Where(r => r.PID == product.id).ToList(),
    // ... other lists similar
});

正如 cmets 中所指出的,上述查询可以为每个产品生成三个子查询。

如果你创建匿名对象来保存中间结果,你可以使用GroupJoin

var _products = _context.Product.GroupJoin(_context.Rating, p => p.id, r => r.PID, (p, rs) => new { p, rs })
                                .GroupJoin(_context.Comment, prs => prs.p.id, c => c.PID, (prs, cs) => new { prs.p, prs.rs, cs })
                                .GroupJoin(_context.View, prs => prs.p.id, v => v.PID, (prscs, vs) => new Product() {
                                    Id = prscs.p.id,
                                    Name = prscs.p.name,
                                    Ratings = prscs.rs.ToList(),
                                    Comments = prscs.cs.ToList(),
                                    Views = vs.ToList()
                                });

【讨论】:

  • 这可能是昂贵的操作。对于每个产品,它都会触发一个评分、视图和评论查询。
  • 好点,虽然我很失望 LINQ to SQL 不够聪明,无法转换为单个查询?
  • 此组加入有效。但是在 LINQPad 中生成的 SQL 是巨大的。事实上,组连接和内部查询都生成相似的 SQL。它会触发每个产品记录的评分、查看和评论查询。
  • GroupJoin 没有生成 SQL JOIN ?
【解决方案2】:

你可以这样试试;

        var records = _context.Product
            .GroupJoin(_context.Ratings, p => p.Id, r => r.PID, (p, r) => new { Product = p, Ratings = r})
            .GroupJoin(_context.Comments, p => p.Product.Id, c => c.PID, (p, c) => new { p.Product, p.Ratings, Comments = c})
            .GroupJoin(_context.Views, p => p.Product.Id, v => v.PID, (p, v) => new { p.Product, p.Ratings, p.Comments, Views = v })
            .Select(p => new
            {
                Id = p.Product.Id,
                Name = p.Product.Name,
                Comments = p.Comments,
                Ratings = p.Ratings,
                Views = p.Views
            })
            .ToList().Select(x => new Product
            {
                Id = x.Id,
                Name = x.Name,
                Comments = x.Comments.ToList(),
                Ratings = x.Ratings.ToList(),
                Views = x.Views.ToList()
            }).ToList();

【讨论】:

  • 我相信第一个 ToList 生成的每条记录都会触发一条额外的 SQL 语句,具体取决于生成和执行数百到数千条 SQL 语句的返回集。
猜你喜欢
  • 1970-01-01
  • 2011-09-09
  • 2012-05-06
  • 1970-01-01
  • 2021-02-25
  • 1970-01-01
  • 2010-11-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多