2016-12-15 6 views
3

私はLinq/LinqKitを使用してネストされたクエリを構築しようとしています。理論的にはこれは簡単だと思われる。しかし、私は実用的な部分に立ち往生しています。入れ子になったデータのLinq(キット)を使用してStackOverflowException

私のデータベースには、親に対する自己参照を持つテーブルがあります。私のlinq-queryでは、特定の要素(およびこの要素の親など)のすべての親を選択する必要があります。

public static Expression<Func<MyTable, IEnumerable<MyTable>>> Parents => (entity) => entity.ParentId != null ? new[]{entity.ParentEntity}.Union(Parents.Invoke(entity.ParentEntity) : new MyEntity[]{}; 

ParentIdが設定されている場合に特定のエンティティの親とそれらの親を選択する必要があります。私のコードで

私はMyTableの部分クラスに次の式を持っています。

クエリ自体(簡体字):停止条件がヒットせず、スタックが満杯になるまで従ってParents -callが無限にネストされているように、このコードを実行

dbContext 
    .MyTable 
    .AsExpandable() 
    .Where(x => x.Id == myId) 
    .Select(x => new 
    { 
     Parents = MyTable.Parents.Invoke(x, dbContext) 
    }); 

StackOverflowExceptionで終わります。

どのようにこれを行うことができますかこれは不可能ですか?または、1つのクエリ内でLinq/LinqKitを使用してネストされたデータを取得するための他の方法がありますか?

私はすでにサブクエリ(も動作していない)を作成するために、式にコンテキストを渡してみました:

public static Expression<Func<MyTable, MyContext, IEnumerable<MyTable>>> Parents => (entity, dbContext) => entity.ParentId != null ? new[]{entity.ParentEntity}.Union(Parents.Invoke(dbContext.MyTable.FirstOrDefault(x => x.Id == entity.ParentId), dbContext) : new MyEntity[]{}; 
+0

こんにちは、面白い試み!しかし、いや、それはSQL CTEのない相当するものがないため、ネストの未知の最高レベルの拡張性(EF互換)の再帰式を作成することはできません。 –

+0

@IvanStoevは、私は、ネストの最大レベルを知っていたでしょうか?すでに各再帰呼び出しによってデクリメントされ、深さのparamを渡してみました。しかし、ここでも同じ例外 – KingKerosin

答えて

0

コメントで述べたように、現在、それは再帰的な拡張(つまりを作成することはできません非呼び出し可能)式。

あなたは最大の深さを制限することができますしかし、もし、一つの可能​​な解決策は次のように式を作成することです(EFナビゲーションプロパティを利用):動的

Parents = new MyTable [] { x.Parent, x.Parent.Parent, x.Parent.Parent.Parent, ...} 
    .Where(e => e != null) 

static Expression<Func<MyTable, IEnumerable<MyTable>>> ParentsSelector(int maxLevels) 
{ 
    var parameter = Expression.Parameter(typeof(MyTable), "x"); 
    var parents = new Expression[maxLevels]; 
    for (int i = 0; i < parents.Length; i++) 
     parents[i] = Expression.Property(i > 0 ? parents[i - 1] : parameter, "Parent"); 
    Expression<Func<MyTable, bool>> predicate = x => x != null; 
    var result = Expression.Call(
     typeof(Enumerable), "Where", new[] { parameter.Type }, 
     Expression.NewArrayInit(parameter.Type, parents), predicate); 
    return Expression.Lambda<Func<MyTable, IEnumerable<MyTable>>>(result, parameter); 
} 

と使用それは次のように:

var parents = ParentsSelector(10); 
var query = dbContext.MyTable 
    .AsExpandable() 
    .Where(x => x.Id == myId) 
    .Select(x => new 
    { 
     Parents = parents.Invoke(x) 
    }); 
関連する問題