Ну, у меня есть проблемы с созданием дерева выражения для 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» не совместим с аргументами, передаваемыми типа и аргументов. Никакие аргументы типа не должны быть обеспечены, если метод не является родовым)
, так что я думаю, что главный вопрос здесь:.
- Как построить дерево выражения для такого SelectMany запроса
- Как сделать Я построить запрос выражение, которое имеет resultSelector & collectionSelector и несколько параметров ..
- и почему код ниже работает, но 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
Извините за грязный и длинный пост, .. мой английский плохо .. :(
, что наряду вопрос ... –
Было бы очень полезно, если вы могли бы конденсироваться это вплоть до полного блока функционирования коды ... –