问题描述
为什么需要它:
我正在处理的程序具有一个通用的查询构造函数,该构造函数使用expression.trees动态查询数据库的所有表。通过简单的选择和几百或几千个数据,它就可以正常工作。当用户需要相关的表数据时,它正在使用延迟加载和映射来实现所需的数据,但是如果(何时)数据将达到数十万,则将无法使用。我正在尝试删除延迟加载,并通过在表达式树中预先加入来做到这一点,使之成为一次旅行。
我之所以需要这样做,是因为用户具有在db中动态搜索的能力,并且很难维护每个表的特定查询,因为它需要手动维护很多表,并且客户要求很多周时间
问题:
要执行以下查询,
IQueryable<A> As = db.A
.Join(
db.B,_a => _a.bID,_b => _b.ID,(_a,_b) => new { a = _a,b = _b })
.Where(s => s.b.Name == "xpto")
.Select(s => s.a);
接收到的A具有通用类型,接收到的B具有字符串。
使用@NetMage briiant answer(这只是一部分。完整的答案在链接或下面):
private static Type TypeGenArg(this Expression e,int n) => e.Type.GetGenericArguments()[n];
public static MethodCallExpression Join(this Expression outer,Expression inner,LambdaExpression outerKeyFne,LambdaExpression innerKeyFne,LambdaExpression resultFne)
=>
Expression.Call(
TQueryable,"Join",new[] { outer.TypeGenArg(0),inner.TypeGenArg(0),outerKeyFne.ReturnType,resultFne.ReturnType },outer,inner,outerKeyFne,innerKeyFne,resultFne);
在执行MethodCallExpression'join'的以下调用中:
var join = db.A.AsConst().Join(db.B.AsConst(),aKeyFne,bKeyFne,resultFne);
db.A和db.B似乎是已知的,但事实并非如此,因为客户端决定要浏览的表,而“ B”是选择的结果。
在此类的上下文中; A是通用类型T,B是字符串“ B”。因此,我尝试能够调用以前的语句的每次转换都会在“ join”或更高版本中收到错误时引发不同类型的错误。最好的尝试是当我这样做的:
//GetType of Generic Type A
AType = typeof(A);
//GetType from string 'B'
string BModelstr = "B";
string areaM = "project.Models." + BModelstr;
Assembly currentAssem = Assembly.GetExecutingAssembly();
string assemblStr = currentAssem.ToString();
string complete = areaM + "," + assemblStr;
Type BType = Type.GetType(complete);
//And then calling:
var join1 = (db.Set(AType)).AsConst().Join((db.Set(BType)).AsConst(),resultFne);
private static Type TypeGenArg(this Expression e,int n) => e.Type.GetGenericArguments()[n];
说这不是通用的。
问题:
var aParm = typeof(A).Param("_a");
var aKeyFne = aParm.Lambda(aParm.Dot("bID"));
var bParm = typeof(B).Param("_b");
var bKeyFne = bParm.Lambda(bParm.Dot("ID"));
var anonType = (new { a = default(A),b = default(B) }).GetType();
var resultFne = (aParm,bParm).Lambda(anonType.New(aParm,bParm));
var join = db.A.AsConst().Join(db.B.AsConst(),resultFne);
.....
使用:
public static class ValueTupleExt {
private static T[] makeArray<T>(params T[] itemArray) => itemArray;
public static T[] ToArray<T>(this (T,T) tuple) => makeArray(tuple.Item1,tuple.Item2);
}
public static class ExpressionExt {
private static Type TQueryable = typeof(Queryable);
private static Type TypeGenArg(this Expression e,int n) => e.Type.GetGenericArguments()[n];
public static MethodCallExpression Join(this Expression outer,LambdaExpression resultFne) =>
Expression.Call(TQueryable,resultFne);
public static MethodCallExpression Select(this Expression src,LambdaExpression resultFne) => Expression.Call(TQueryable,"Select",new[] { src.TypeGenArg(0),src,resultFne);
public static MethodCallExpression Where(this Expression src,LambdaExpression predFne) => Expression.Call(TQueryable,"Where",new[] { src.TypeGenArg(0) },predFne);
public static ConstantExpression AsConst<T>(this T obj) => Expression.Constant(obj,typeof(T));
public static MemberExpression Dot(this Expression obj,string propNames) =>
(MemberExpression)propNames.Split('.').Aggregate(obj,(ans,propName) => Expression.PropertyOrField(ans,propName));
public static LambdaExpression Lambda(this ParameterExpression p1,Expression body) => Expression.Lambda(body,p1);
public static LambdaExpression Lambda(this (ParameterExpression,ParameterExpression) parms,parms.ToArray());
public static NewExpression New(this Type t,params Expression[] vals) => Expression.New(t.GetConstructors()[0],vals,t.GetProperties());
public static BinaryExpression opEq(this Expression left,Expression right) => Expression.Equal(left,right);
public static ParameterExpression Param(this Type t,string pName) => Expression.Parameter(t,pName);
}
非常感谢帮助。
谢谢!
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)