C# 如何做表达式树';加入';具有泛型,字符串具有内部和外部表达式

C# 如何做表达式树';加入';具有泛型,字符串具有内部和外部表达式,c#,lambda,expression,expression-trees,generic-lambda,C#,Lambda,Expression,Expression Trees,Generic Lambda,为什么我需要它: 我正在使用的程序有一个通用查询构造函数,它使用expression.trees查询db Dynamicly的所有表。通过简单的选择和几百或几千个数据,它工作得很好。当用户需要一个相关的表数据时,它正在使用懒散加载和映射来实现所需的内容,但如果(以及当)数据将达到数千个,它将不可用。我正在尝试删除懒散加载,并在表达式树中使用join-upfront来完成它,使之成为一次旅行 我之所以需要它,是因为用户能够在数据库中进行动态搜索,并且很难维护每个表的特定查询,因为它有很多表需要手工

为什么我需要它:

我正在使用的程序有一个通用查询构造函数,它使用expression.trees查询db Dynamicly的所有表。通过简单的选择和几百或几千个数据,它工作得很好。当用户需要一个相关的表数据时,它正在使用懒散加载和映射来实现所需的内容,但如果(以及当)数据将达到数千个,它将不可用。我正在尝试删除懒散加载,并在表达式树中使用join-upfront来完成它,使之成为一次旅行

我之所以需要它,是因为用户能够在数据库中进行动态搜索,并且很难维护每个表的特定查询,因为它有很多表需要手工维护,而且客户端需要很多tweeks

问题:

要执行以下查询

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);
在以下执行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(), aKeyFne, bKeyFne, resultFne);
它引起了一个错误

private static Type TypeGenArg(this Expression e, int n) => e.Type.GetGenericArguments()[n];
说它不是通用的

问题是:

  • 如何使用泛型类型T作为db.A,字符串“B”作为db.B,以便在expression.call()中被接受并获取它们的类型
  • 修改联接
  • 发送不同的参数,如
    join
    和字符串
我试图为这个问题实现的相关@NetMage代码(完整的向上链接):

使用:

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, 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);

    public static MethodCallExpression Select(this Expression src, LambdaExpression resultFne) => Expression.Call(TQueryable, "Select", new[] { src.TypeGenArg(0), resultFne.ReturnType }, src, resultFne);

    public static MethodCallExpression Where(this Expression src, LambdaExpression predFne) => Expression.Call(TQueryable, "Where", new[] { src.TypeGenArg(0) }, src, 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, Expression body) => Expression.Lambda(body, 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);
}
public静态类ValueTupleExt{
私有静态T[]makeArray(参数T[]itemArray)=>itemArray;
公共静态T[]ToArray(此(T,T)元组)=>makeArray(tuple.Item1,tuple.Item2);
}
公共静态类ExpressionExt{
私有静态类型TQueryable=typeof(Queryable);
私有静态类型TypeGenArg(此表达式e,int n)=>e.Type.GetGenericArguments()[n];
公共静态方法调用表达式联接(此表达式外部、表达式内部、LambdaExpression外部、LambdaExpression内部、LambdaExpression内部、LambdaExpression resultFne)=>
Expression.Call(TQueryable,“Join”,new[]{outer.TypeGenArg(0),inner.TypeGenArg(0),outerKeyFne.ReturnType,resultFne.ReturnType},outer,innerKeyFne,resultFne);
公共静态方法调用表达式选择(此表达式src,LambdaExpression resultFne)=>Expression.Call(TQueryable,“Select”,new[]{src.TypeGenArg(0),resultFne.ReturnType},src,resultFne);
public static MethodCallExpression Where(此表达式src,LambdaExpression predFne)=>Expression.Call(TQueryable,“Where”,new[]{src.TypeGenArg(0)},src,predFne);
公共静态常量表达式AsConst(此T obj)=>表达式常量(obj,typeof(T));
公共静态MemberExpression点(此表达式obj,字符串propName)=>
(MemberExpression)propNames.Split('.').Aggregate(obj,(ans,propName)=>Expression.PropertyOrField(ans,propName));
公共静态LambdaExpression Lambda(此参数Expression p1,Expression body)=>Expression.Lambda(body,p1);
公共静态LambdaExpression Lambda(this(ParameterExpression,ParameterExpression)parms,Expression body)=>Expression.Lambda(body,parms.ToArray());
公共静态NewExpression New(此类型为t,参数表达式[]vals)=>Expression.New(t.GetConstructors()[0],vals,t.GetProperties());
公共静态二进制表达式opEq(此表达式左,表达式右)=>Expression.Equal(左,右);
公共静态参数Expression Param(此类型为t,字符串pName)=>Expression.Parameter(t,pName);
}
我真的很感激你的帮助

谢谢大家!

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(), aKeyFne, bKeyFne, 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, 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);

    public static MethodCallExpression Select(this Expression src, LambdaExpression resultFne) => Expression.Call(TQueryable, "Select", new[] { src.TypeGenArg(0), resultFne.ReturnType }, src, resultFne);

    public static MethodCallExpression Where(this Expression src, LambdaExpression predFne) => Expression.Call(TQueryable, "Where", new[] { src.TypeGenArg(0) }, src, 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, Expression body) => Expression.Lambda(body, 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);
}