How to return both parent and child using LINQ against 1 table

前端 未结 7 722
隐瞒了意图╮
隐瞒了意图╮ 2021-01-19 17:10

Been looking for a solution for this but haven\'t been able to find one so far.

I\'m fairly sure its possible with one linq call but having trouble working it out.

相关标签:
7条回答
  • 2021-01-19 17:48

    If you're using Entity Framework and have Navigation Properties, you could do the following. It's not clear from the question whether this is the case though.

    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();
    
    0 讨论(0)
  • 2021-01-19 18:04

    for your sample data, this will work :

            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;
    

    but it won't work if there are multi-level hierarchies in your data, and you want to select the sub-children too.

    another thing, i'm not sure if the above will work on linq-to-sql or another linq provider, but it does work for in-memory data.

    0 讨论(0)
  • 2021-01-19 18:05

    I was going to use a GroupJoin, but this should satisfy your requirement.

     var query = dataContext.YourTable.Where(x => x.ValidFlag == 1 &&
     (x.ParentId == null ||
        dataContext.YourTable.Where( y => y.ParentId == x.Id)
        .First().ValidFlag == 1))
     .ToList();
                          .
    
    0 讨论(0)
  • 2021-01-19 18:06

    This should do it. Create a generic list of the type of your object that contains that data structure. Then use the .Where extension which returns an IEnumerable of the same type.

        List<YourObject> list = new List<YourObject>();
        IEnumerable<YourbObject> validItems = list.Where(x=>x.ValidFlag=1);
    
    0 讨论(0)
  • 2021-01-19 18:07

    This should do the trick, (edit: see below for version that doesn't use 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();
    

    The above code should hopefully generate something quite similar to what it itself looks like in SQL, maybe with the exception of the distinct which might cause it to return more data that is actually needed to be filtered on the client. Something that might become an issue if there's a lot data, chiefly if there's a lot of parents because it will return duplicates of those)

    Here is the query reworked without the distinct call

    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
    
    0 讨论(0)
  • 2021-01-19 18:07

    Thinking about this the "wrong" way around, the SQL you want is:

    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
    

    so the LINQ you want is:

    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;
    

    (Not quite the same SQL, but effectively so.)

    0 讨论(0)
提交回复
热议问题