4

一直在寻找解决方案,但到目前为止还没有找到。

我相当确定它可以通过一个 linq 调用但无法解决。

我有以下数据结构

Id      ParentId     Name       ValidFlag

1       NULL         parent 1   1
2       NULL         parent 2   1
3       NULL         parent 3   0
4       1            child 1    1
5       1            child 2    1
6       2            child 3    1
7       2            child 4    1
8       3            child 5    1
9       3            child 6    1

现在我想做的是返回所有有效的父母和他们的孩子,所以在这种情况下,我会返回除 ID = 3(父母 3)之外的所有内容。

有没有一种简单的方法可以用 LINQ 做到这一点?我猜有,但我的 LinqIQ 非常有限,我知道基础知识,但除此之外我需要很多帮助。

这是 ToLookup() 或 Union 的情况,还是两者都不是?

更新:

更具体地说,因为我没有这样做,两种类型的记录都在同一个表中,如果可能的话,我想返回所有记录,无论它是 1 查询中的父还是子。

它不像只选择 ValidFlag = 1 的所有记录那么简单。源数据库是一团糟,获取所有记录的唯一方法是找到“有效”父母,然后找到“有效”父母的所有孩子。我知道我可以只做一个简单的查询来返回所有有效的父记录,然后做一个单独的查询来找到这些父母的所有孩子,但是组合成 1 个 LINQ 查询是我失败的地方,我希望这是可能的。在这种情况下,可能存在无效父母的有效子条目,因此需要该问题

4

7 回答 7

3

这应该可以解决问题,(编辑:有关不使用 Distinct 的版本,请参见下文。)

(from parents in collection
from all in collection
where
    parents.ValidFlag == 1 &&
    parents.ParentId == null &&
    all.ValidFlag == 1 &&
    (all.ParentId == null || all.ParentId == parents.Id)
select all).Distinct();

上面的代码应该希望生成与它在 SQL 中看起来非常相似的东西,也许除了 distinct 可能导致它返回更多实际需要在客户端过滤的数据。如果有很多数据,可能会成为一个问题,主要是如果有很多父母,因为它会返回那些重复的)

这是在没有不同调用的情况下重新编写的查询

from parents in collection // parents is only used to decide which children to get
from all in collection // this is where we will actually grab our data from
where
    parents.ValidFlag == 1 &&  // only include parents that are valid
    parents.ParentId == null && // and that are parents
    all.ValidFlag == 1 &&  // only include entries that are valid
    (
        (all.ParentId == null && all.Id == parents.Id) ||  // If entry is a parent, match with itself to limit returns to 1
        all.ParentId == parents.Id // otherwise, parentid should match one of the valid parents.
    )
select all
于 2013-02-21T05:21:48.367 回答
1

这应该这样做。创建包含该数据结构的对象类型的通用列表。然后使用返回相同类型的 IEnumerable 的 .Where 扩展名。

    List<YourObject> list = new List<YourObject>();
    IEnumerable<YourbObject> validItems = list.Where(x=>x.ValidFlag=1);
于 2013-02-21T04:13:28.870 回答
0

考虑以下 Linq to Sql 实体:

在此处输入图像描述

假设我们已经将OneToMany关系的边命名为ChildTablesand ParentTables,那么下面的代码应该可以完成这项工作

//create data context
MyTableDataContext dc = new MyTableDataContext("Your connection string"); 
//find all children, i.e. the entities with ParentId set
var allChildEntities = dc.MyTable.Where(t=>t.ParentId.HasValue);
//find all valid parents, which have no parent and no children
var allParentsWithChild = dc.MyTable.Where(c => !c.ParentId.HasValue && 
                                                !c.ChildTables.Any());
//union the results
var result = allChildEntities.Union(allParentsWithChild);

Id如果和之间有外键关系ParentId,那就足够了。如果没有,您还应该搜索不存在父母的子实体。但这可能会更容易用纯 sql 完成

于 2013-02-21T04:28:43.803 回答
0

我打算使用 GroupJoin,但这应该可以满足您的要求。

 var query = dataContext.YourTable.Where(x => x.ValidFlag == 1 &&
 (x.ParentId == null ||
    dataContext.YourTable.Where( y => y.ParentId == x.Id)
    .First().ValidFlag == 1))
 .ToList();
                      .
于 2013-02-21T04:39:58.863 回答
0

对于您的示例数据,这将起作用:

        var validData = from d in data
                        where (!d.ParentID.HasValue && d.IsValid) //select all valid parents
                        || (d.ParentID.HasValue && data.Where(p => !p.ParentID.HasValue && p.IsValid).Select(p => p.ID).Contains(d.ParentID.Value)) //select children
                        select d;

但如果您的数据中存在多级层次结构,并且您也想选择子子级,则它将不起作用。

另一件事,我不确定上述是否适用于 linq-to-sql 或其他 linq 提供程序,但它确实适用于内存数据。

于 2013-02-21T04:50:20.507 回答
0

如果您使用的是实体框架并具有导航属性,则可以执行以下操作。不过,从这个问题中还不清楚是否是这种情况。

var query = db.YourTable
    .Where(x => x.Parent != null && x.Parent.ValidFlag == 1)
    .GroupBy(x => x.ParentId)
    .Select(g => new { ParentId = g.Key, Children = g.ToList() })
    .ToList();
于 2013-02-21T05:33:25.733 回答
0

考虑一下这种“错误”的方式,您想要的 SQL 是:

SELECT * FROM MyTable
WHERE IsValid = 1 AND
 (ParentID IS NULL -- Parents
 OR ParentID IN (SELECT ID FROM MyTable WHERE IsValid = 1 AND ParentID IS NULL))
     -- Children

所以你想要的 LINQ 是:

var result = from d in MyTable
             where d.ValidFlag == 1
              && (d.ParentId == null
               || (from p in MyTable where p.ValidFlag == 1 && p.ParentId == null
                   && p.Id == d.ParentId select p.Id).Any())
             select d;

(不完全相同的 SQL,但实际上如此。)

于 2013-02-21T07:30:11.437 回答