2013-08-14 2 views
2

Ну, у меня есть проблемы с созданием дерева выражения для SelectMany .. особенно в TypeArguments части ..SelectMany Expression Tree Expression.Call TypeArguments

Итак, у меня есть база данных с таблицами, как показано ниже:

[Группа] (один ко многим) [GroupDetail] (многие к одному) [Элемент] (один ко многим) [ItemDetail]

  • GroupDetail.group является группа
  • GroupDetail.item является элементом
  • ItemDetail.item является Item
  • Item.itemDetail представляет собой сборник ItemDetail
  • Group.groupDetail представляет собой сборник GroupDetail

так что вы можете видеть, что группа подробно просто многие ко многим ссылку для группы и п и (один ко многим) является один ко многим отношение ..

Например, данные, как показано ниже:

Group, GroupDetail, Item, ItemDetail 
------------------------------------ 
gr1, grDt1, ItemA, PartsAA 
gr1, grDt1, ItemA, PartsAB 
gr1, grDt2, ItemB, PartsBA 
gr1, grDt2, ItemB, PartsBB 

gr2, grDt3, ItemC, PartsCA 
gr2, grDt4, ItemA, PartsAA 
gr2, grDt4, ItemA, PartsAB 

gr3, grDt4, ItemD, PartsDA 
gr3, grDt5, ItemE, PartsEA 

Я хочу, чтобы выбрать элементы и каждый из его деталей с помощью группового поиска и вернуть его в качестве коллекции какой-то вид класса ..

Похожие, как эта функция ниже:

public IQueryable<ItemGroupDetailView> getViewQ(IQueryable<GroupDetail> myQ) 
{ 
    return myQ.SelectMany(
    m => m.item.itemDetail, 
     (m, n) => new ItemGroupDetailView 
     { 
      groupName = m.group.name, 
      groupDetailCount = m.group.groupDetail.Count, 
      item = new ItemView 
      { 
       itemName = n.item.name, 
       itemDetailCount = n.item.itemDetail.Count 
      }, 
      itemDetail = new ItemDetailView 
      { 
       itemDetailName = n.name 
      }   
     } 
    ); 
} 

просто как что выше нО Я хочу, чтобы это было динамическое ехр дерево вместо этого, так что, возможно, я могу просто использовать его как:

Filter filter = new Filter("gr1","ItemA"); // just a filter 

var myQ = getSearchQ(filters); // it gets all the where etc, everything is fine here.. 
var viewQ = getViewQ(myQ); // simply to convert the data to the view,.. where all the errors are 
var finalQ = ApplyLimit(ApplyGrouping(ApplySorting(ApplySelect(myQ))); // paging, sorting, grouping, etc.. 

// run the select.. get the count etc.. 

теперь я хочу, чтобы сделать его динамичным, но я, кажется, это неправильно на SelectMany часть

Это примерно, как я делаю SelectMany вещи:

шаг 1: Я связываю назначение свойства/поля ..он пришел из какого-то список-строковым конфигурационных любопытных вещей, которые отображают уступку

PropertyInfo pInfo; 
MemberExpression mExp; 
// parse getproperty reflect etc... 
List<MemberAssignment> memberAssginments = new List<MemberAssignment>(); 
memberAssginments.Add(Expression.Bind(pInfo, mExp); 

шаг 2: то обычный INIT члена

MemberInitExpression mie = 
    Expression.MemberInit(Expression.New 
     (typeof(ItemGroupDetailView)), memberAssginments); 

так что я получаю это:

new ItemGroupDetailView 
    { 
     groupName = m.group.name, 
     groupDetailCount = m.group.groupDetail.Count, 
     item = new ItemView 
     { 
      itemName = n.item.name, 
      itemDetailCount = n.item.itemDetail.Count 
     }, 
     itemDetail = new ItemDetailView 
     { 
      itemDetailName = n.name 
     }   
    } 

шаг 3: затем получить выражение collectionSelector & resultSelector

ParamterExpression m = Expression.Parameter(typeof(GroupDetail),"m"); 
ParamterExpression n = Expression.Parameter(typeof(ItemDetail),"n");  

Expression<Func<GroupDetail, ItemDetail, ItemGroupDetailView>> exp2 =  
    Expression.Lambda<Func<GroupDetail, ItemDetail, ItemGroupDetailView>> 
     (mie, new ParameterExpression[] { m, n }); 

Я думаю, что я получаю то, что мне нужно, exp2 (resultSelector):

(m, n) => new ItemGroupDetailView 
    { 
     groupName = m.group.name, 
     groupDetailCount = m.group.groupDetail.Count, 
     item = new ItemView 
     { 
      itemName = n.item.name, 
      itemDetailCount = n.item.itemDetail.Count 
     }, 
     itemDetail = new ItemDetailView 
     { 
      itemDetailName = n.name 
     }   
    } 

и подобным образом я получаю другой пункт, exp1 (collectionSelector)

MemberExpression mEx = .... reflect get property/field etc.. 

Expression<Func<GroupDetail, IEnumerable<ItemDetail>>> exp1 = 
    Expression.Lambda<Func<GroupDetail, IEnumerable<ItemDetail>>>(mEx, m); 

, так что я получаю это:

m => m.item.itemDetail 

шаг 4: затем получить SelectMany MethodCallExpression сам

MethodCallExpression selectManyExp = 
    Expression.Call(
     typeof(Queryable), 
     "SelectMany", 
     new Type[] { 
      typeof(GroupDetail), 
      typeof(Expression<Func<GroupDetail, IEnumerable<ItemDetail>>>), 
      typeof(Expression<Func<GroupDetail, ItemDetail, ItemGroupDetailView>>) 
     }, 
     new Expression[] { Expression.Quote(exp1), Expression.Quote(exp2) } 
    ); 

Это не работает на всех ..

(Нет общий метод «SelectMany» от типа «System.Linq.Queryable» не совместим с аргументами, передаваемыми типа и аргументов. Никакие аргументы типа не должны быть обеспечены, если метод не является родовым)

, так что я думаю, что главный вопрос здесь:.

  1. Как построить дерево выражения для такого SelectMany запроса
  2. Как сделать Я построить запрос выражение, которое имеет resultSelector & collectionSelector и несколько параметров ..
  3. и почему код ниже работает, но Expression.Call всегда ошибка ..
myQ.SelectMany(exp1, exp2); 

Я предполагаю, что я не понимаю, как работает SelectMany или Expression Tree .. :(

но, мне это нужно, чтобы быть динамическим, поскольку связывание присвоение собственности/поля и источника, селектор и результат является динамическим

public IQueryable<TView> getViewQ(IQueryable<T> myQ) 
{  
    // some code.. 
} 

EDIT 1:

Переключение exp1 и exp2 .. Теперь exp1 является collectionSelector и exp2 является resultSelector ..

EDIT 2:

Кроме того, я попробовал несколько вещей: первых, изменить аргумент типа, как то, что ниже, сказал Майк, но ошибка все та же

MethodCallExpression selectManyExp = 
    Expression.Call(
     typeof(Queryable), 
     "SelectMany", 
     new Type[] { 
      typeof(GroupDetail), 
      typeof(ItemDetail), 
      typeof(ItemGroupDetailView) 
     }, 
     new Expression[] { Expression.Quote(exp1), Expression.Quote(exp2) } 
    ); 

тогда я попробовать отражение этого и проверить

System.Reflection.MethodInfo sminfo = null; 
System.Reflection.MethodInfo sminfo2 = null; 

IEnumerable<System.Reflection.MethodInfo> sminfos = typeof(Queryable) 
    .GetMethods(System.Reflection.BindingFlags.Static 
     | System.Reflection.BindingFlags.Public) 
    .Where(xxx => xxx.Name.Equals("SelectMany")); 

foreach (System.Reflection.MethodInfo mi in sminfos) 
{ 
    if (mi.GetParameters().Count() == 3) 
    { 
     sminfo = mi; 
    } 
} 

/* 
I ran this step by step to make sure that the method I get in sminfo is: 
public static IQueryable<TResult> SelectMany<TSource, TCollection, TResult>(
    this IQueryable<TSource> source, 
    Expression<Func<TSource, IEnumerable<TCollection>>> collectionSelector, 
    Expression<Func<TSource, TCollection, TResult>> resultSelector 
); 
*/ 

sminfo2 = sminfo.MakeGenericMethod(
    new Type[] { 
     typeof(GroupDetail), typeof(ItemDetail), typeof(ItemGroupDetailView) 
    }); 

MethodCallExpression selectManyExp = 
    Expression.Call(sminfo2, new Expression[] { exp1, exp2 }); 

и я получаю другую ошибку: (Неверное количество аргументов, для вызова метода ..)

и он говорит мне, что метод требуется 3 параметра, а не 2, а один я пропустить это IQueryable<GroupDetail> источник

поэтому я вернусь Expression.Call и добавить параметр источника

MethodCallExpression selectManyExp = 
    Expression.Call(
     typeof(Queryable), 
     "SelectMany", 
     new Type[] { 
      typeof(GroupDetail), 
      typeof(ItemDetail), 
      typeof(ItemGroupDetailView) 
     }, 
     new Expression[] { myQ.Expression, exp1, exp2 } 
    ); 

return (IQueryable<ItemGroupDetailView>)myQ.Provider.CreateQuery(selectManyExp); 

и он работает ..: D

Извините за грязный и длинный пост, .. мой английский плохо .. :(

+1

, что наряду вопрос ... –

+0

Было бы очень полезно, если вы могли бы конденсироваться это вплоть до полного блока функционирования коды ... –

ответ

0

Похоже, что вы сконфигурировали параметры типа с формальными параметрами. Я считаю, что ваши аргументы типа должны выглядеть следующим образом:

MethodCallExpression selectManyExp = 
    Expression.Call(
     typeof(Queryable), 
     "SelectMany", 
     new Type[] { 
      typeof(GroupDetail), 
      typeof(ItemDetail), 
      typeof(ItemGroupDetailView) 
     }, 
     new Expression[] { Expression.Quote(exp1), Expression.Quote(exp2) } 
); 
+0

да что должно быть правильным , сэр .. но я все равно получаю ту же ошибку .. факт, что 'myQ.SelectMany (exp1, exp2);' на самом деле работает, все еще путают меня, почему Expression.Call всегда ошибка .. – sickdoctor

+0

После теста на отражение, я обнаружил, что не только пропустил аргумент типа, но и пропустил исходное выражение для аргументов 'new Expression [] {myQ.Expression, exp1, exp2}' – sickdoctor

Смежные вопросы