如何使用泛型和字符串表达树“加入”具有内部和外部表达

问题描述

为什么需要它:

我正在处理的程序具有一个通用的查询构造函数,该构造函数使用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];

说这不是通用的。

问题:

  • 如何将通用类型T用作db.A,将字符串'B'用作db.B,以便在expression.call()'join'中被接受并获取其类型?
  • 修改联接吗?
  • 要发送不同的参数,例如join<A>和字符串吗?

我要为此问题实施的相关@NetMage代码(完整链接):

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 (将#修改为@)