4

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.

I have the following data structure

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

Now what i want to do is return all valid parents and their children so this case i would return everything except Id = 3 (parent 3).

Is there a simple way to do this with LINQ? Im guessing there is but my LinqIQ is very limited, i know the basics but beyond that i need much help.

Is this a case for ToLookup() or Union or neither?

Update:

To be more specific as I've failed to do so, both types of records are in the same table, i want to return all records whether its a parent or child in the 1 query if possible.

Its not as simple as just selecting all records where ValidFlag = 1. The source database is a mess and the only way to get all records is to find the "valid" parents then find all children for the "valid" parents. I know i can just do a simple query to return all valid parent records then do a separate query to find all child of those parents, but combining into 1 LINQ query is where i fail, i was hoping that is possible. In this case it is possible that there are valid child entries of invalid parents, hence need for the question

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

上記のコードは、クライアントで実際にフィルタリングする必要があるより多くのデータを返す原因となる可能性があるdistinctを除いて、SQLでのそれ自体がどのように見えるかと非常によく似たものを生成するはずです. 多くのデータがある場合、主に多くの親がいる場合、それらの複製が返されるため、問題になる可能性があるもの)

これは、明確な呼び出しなしで作り直されたクエリです

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

サンプルデータの場合、これは機能します:

        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

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

これを「間違った」方法で考えると、必要な 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 に答える
0

Entity Framework を使用していて、Navigation プロパティがある場合は、次のことができます。これが事実であるかどうかは、質問からは明らかではありません。

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

次の Linq to Sql エンティティを検討してください。

ここに画像の説明を入力

OneToMany関係の両側に and のようなChildTables名前を付けたと仮定すると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 に答える