我想创建带有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)
谢谢