【问题标题】:Adding a LINQ where clause to a custom class将 LINQ where 子句添加到自定义类
【发布时间】:2015-03-24 23:52:16
【问题描述】:

我拥有此查询所需的大部分内容,但似乎无法获得最后一点。基本上,我需要将Where 子句应用于Book 部分。例如,我需要知道哪个Parent 有一个Child 读过书1234。所以在这种情况下,我的 LINQ 查询将返回一个 Parent 类,其中包含 JohnSallys 信息(但显然有更多的记录不会返回)。当我添加Books = grp1.Select(q=>q.Books) 时,我设置的所有内容都返回错误消息Error 199 Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<System.Collections.Generic.List<int>>' to 'System.Collections.Generic.List<int>'. An explicit conversion exists (are you missing a cast?)。有什么想法吗?

public class Parent
{
    public Parent() { }

    public int ParentID { get { return _parentID; } set { _parentID = value; } }
    public List<Child> Children { get { return _child; } set { _child = value; } }
}
public class Child
{
    public Child() { }

    public int ChildID { get { return _childID; } set { _childID = value; } }
    public List<int> BookID { get { return _books; } set { _books = value; } }
}

表格

 Parent ID |     Parent      | Child ID |     Child     |     Books 
1          | John            | 4        | Suzy          | 1234
1          | John            | 4        | Suzy          | 4567
1          | John            | 5        | James         | 6789
2          | Sally           | 4        | Suzy          | 1234
2          | Sally           | 4        | Suzy          | 4567
2          | Sally           | 5        | James         | 6789

查询制作父母名单##

List<Parent> Parents = dt.AsEnumerable().GroupBy(x => x.Field<int>("parent_id"))
    .Select(x => new Parent
    {
        ParentID = x.Key,
        Children = x.GroupBy(y => y.Field<int>("children")).Select(z => new Child
        {
            ChildID = z.Key,
            Books = z.Select(b => b.Field<int>("books")).ToList()
        }).ToList()
    }).ToList();

期望的结果

List&lt;Parent&gt;

父类索引 0: 家长编号:1 儿童指数 0: 儿童编号:4 BookID 索引 0: 1234,图书索引 1: 4567 儿童索引 1: 儿童编号:5 BookID 索引 0: 6789

...等等。

【问题讨论】:

  • x, y, z 不是特别有用的名称。如果您使用 lambda 变量做任何远程复杂的事情,那么值得给它一个更好的名称。
  • @ObliviousSage 适当地指出,这只是为了让它工作。我很难理解这个查询。在我 100% 理解每个变量所代表的含义之前,我觉得命名变量是没有意义的……如果这有意义的话。
  • 签出了“SelectMany”?
  • @Sasse 我不确定字符数组将如何帮助我?至少如果我正确理解SelectMany
  • 那你就倒退了。从您理解的简单部分构建查询。每当一个 lambda 变量被多次引用时,这意味着是时候给它一个更具描述性的名称,以便在添加更多片段时记住它是什么。

标签: c# linq class generics


【解决方案1】:

您需要使用 SelectMany 而不是 Select。

Books = grp1.Select(q =&gt; q.Books); 会将每个组成员转换为相应的List 书籍,因此您最终会得到一个IEnumerable&lt;List&lt;int&gt;&gt;

SelectManySelect 执行相同的操作,但将生成的 IEnumerables 合并到父 IEnumerable 中。在这种情况下,Books = grp1.SelectMany(q =&gt; q.Books); 会给你一个IEnumerable&lt;int&gt;

【讨论】:

  • 这似乎不起作用。我试了一下,但Child = z.Key 的行出现了另一个问题。它包含Child 的列表,并且似乎无法正确评估。我不确定SelectMany 是否有帮助,因为另一部分现在出错了。
  • 这根本不是他需要的。一开始我以为是这样,直到我阅读了整个问题。
  • @Volearix 由于您的示例将标识符属性列为child.ChildID 而不是child.Key,因此该错误对我来说很有意义。
【解决方案2】:

我相信下面的 linq 查询会返回你需要的结果:

var parents = (from p in dt.AsEnumerable()
                    group p by p.Field<int>("parent_id")
                    into g
                    select new Parent
                    {
                        ParentId = g.Key,
                        Children =
                            (from c in g
                                group c by c.Field<int>("child_id")
                                into childGroup
                                select new Child
                                {
                                    ChildId = childGroup.Key,
                                    Books = childGroup.Select(c => c.Field<string>("books")).ToList()
                                }).ToList()
                    }).ToList();

【讨论】:

    【解决方案3】:

    我确实整理了一些代码只是为了尝试您的查询,因为我认为它看起来还不错(除了您正在阅读我在 cmets 中告诉您的字符串之类的书。

    所以这不是一个答案,但应该能够进一步帮助你。

    public class Parent
    {
        public int ParentID { get; set; }
        public List<Child> Children { get; set; }
    }
    public class Child
    {
        public int ChildID { get; set; }
        public List<string> Books { get; set; }
    }
    
    public class SS
    {
        public int pid { get; set; }
        public int cid { get; set; }
        public string book { get; set; }
    }
    
    [TestMethod]
    public void AAPlaying()
    {
        var dt = new List<SS>() { };
        dt.Add(new SS() { pid = 1, cid = 4, book = "Grapes of ..."});
        dt.Add(new SS() { pid = 1, cid = 4, book = "Huck......." });
        dt.Add(new SS() { pid = 1, cid = 5, book = "The adven..." });
        dt.Add(new SS() { pid = 2, cid = 4, book = "Grapes of ..." });
        dt.Add(new SS() { pid = 2, cid = 4, book = "Huck......." });
        dt.Add(new SS() { pid = 2, cid = 5, book  = "The adven..." });
    
    
        List<Parent> Parents = dt.AsEnumerable().GroupBy(x => x.pid)
            .Select(x => new Parent
            {
                ParentID = x.Key,
                Children = x.GroupBy(y => y.cid).Select(z => new Child
                {
                    ChildID = z.Key,
                    Books = z.Select(b => b.book).ToList()
                }).ToList()
            }).ToList();
    }
    

    【讨论】:

    • 好的,所以您的查询将返回所有内容,正确,但现在我只需要带有特定标题的 Books
    • @Volearix 好的,你需要它们吗?您是否需要选择所有父母和所有孩子,但只选择正确的书籍,还是要排除不读这本书的人。只需添加一个“.Where(book => book.Title == "Grapes of ...") 像这样的“z.Where(...).Select(...)”。否则你可以从开头,例如 "dt.AsEnumerable().Where(row => row.Books == "Grapes of ...").GroupBy(...
    • 首先我要说的是“SS”类不存在。为了让事情变得更明智,而无需接触SS 类,我将更新我的示例。请参阅更新的问题。我还将在答案中准确概述我需要什么。一秒。
    • 更新了问题。希望我在寻找什么是有意义的。查看所需的结果区域
    • @Volearix 当然,SS 对你来说不存在,它是我示例代码的一部分,用于说明为什么我的 GroupBy 看起来不像你的。 SS 类说明了数据表中没有 ParentName 和 ChildName 的一行。
    猜你喜欢
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    • 1970-01-01
    • 2010-09-15
    • 2021-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多