IQueryable.Provider.CreateQuery <t>将提供什么?

时间:2019-01-03 13:43:41

标签: c# serialization lambda entity-framework-core iqueryable

我想创建带有EF core 2的远程Linq表达式执行器之类的东西。

首先,用户向服务器发送请求

2)服务器将生成一个可以根据用户需求执行的表达式

类似{value(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable1[X.API.NewsPaper]).Where(model => (model.Id.ToString() == "630b7340-068e-47be-ba0e-2e03bdd72e1e")).AsNoTracking().FirstOrDefault().Posts}

然后服务器将通过Aq.ExpressionJsonSerializer对其进行序列化,并将其放入响应中(注意:由于客户端请求和数据库方案,生成的表达式可能有所不同,因此我对数据库一无所知,所以我无法使用预定义的表达式)

3)客户端将请求将生成的表达式发送到服务器来执行

4)服务器将尝试通过我的Aq.ExpressionJsonSerializer库的自定义功能对其进行反序列化

问题将出现在这里:

反序列化表达式后,我无法对其执行任何功能。

这是我自定义的Aq.ExpressionJsonSerializer函数

namespace Aq.ExpressionJsonSerializer {
    partial class Deserializer {
        private ConstantExpression ConstantExpression (
            ExpressionType nodeType, System.Type type, JObject obj) {
            object value;

            var valueTok = this.Prop (obj, "value");
            if (valueTok == null || valueTok.Type == JTokenType.Null) {
                value = null;
            } else {
                var valueObj = (JObject) valueTok;
                var valueType = this.Prop (valueObj, "type", this.Type);

                if (typeof(IQueryable).IsAssignableFrom(valueType)) {
                    value = this.queryableProvider.GetIQueryableByType(valueType.GetGenericArguments().FirstOrDefault());
                } else {
                    value = this.Deserialize (this.Prop (valueObj, "value"), valueType);
                }
            }

            switch (nodeType) {
                case ExpressionType.Constant:
                    return Expr.Constant (value, type);
                default:
                    throw new NotSupportedException ();
            }
        }
    }
}

这是接口实现:

public IQueryable GetIQueryableByType (Type type) {
    ExpressionQueryableType = type;
    return this.GetType ()
        .GetMethod (nameof (GetIQueryable))
        .MakeGenericMethod (type)
        .Invoke (this, null) as IQueryable;
}

public IQueryable<T> GetIQueryable<T> () where T : class =>
    dbContext.Set<T> ().Select (x => x);

这是我的控制器代码:

public async Task<IActionResult> PagedListExp (Cursor cursor) {
    var defaultSettings = new JsonSerializerSettings {
        MaxDepth = 15,
        TypeNameHandling = TypeNameHandling.Objects
    };
    defaultSettings.Converters.Add (new ExpressionJsonConverter (Assembly.GetAssembly (typeof (MyController)), this));
    var path = JsonConvert.DeserializeObject<Expression> (cursor.ExpressionPath, defaultSettings);

    var queryable =
        this.GetType ()
        .GetMethod (nameof (GetIQueryableFromExpression))
        .MakeGenericMethod (ExpressionQueryableType, modelParser.GetResourceType(cursor.IssuedFor))
        .Invoke (this, new object[] { path }) 
       // as IQueryable<dynamic>;
        as IQueryable<Post>

    var size = queryable.Count();

    ...

}

public IQueryable<TTarget> GetIQueryableFromExpression<TSource, TTarget> (Expression exp) where TSource : class {
    return dbContext.Set<TSource> ().AsQueryable<TSource> ().Provider.CreateQuery<TTarget> (exp);
}

这是错误消息:

An unhandled exception occurred while processing the request.
ArgumentException: Expression of type 'System.Collections.Generic.ICollection`1[X.API.Post]' cannot be used for parameter of type 'System.Linq.IQueryable`1[X.API.Post]' of method 'Int32 Count[Post](System.Linq.IQueryable`1[X.API.Post])'
Parameter name: arg0

System.Dynamic.Utils.ExpressionUtils.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arguments, ParameterInfo pi, string methodParamName, string argumentParamName, int index)

谢谢

0 个答案:

没有答案