给定一个IDbSet,其中Person包含“Id”属性,如何执行以下命令:
var p = PersonDbSet.FirstOrDefault(i=>i.Id = 3);
我可以构建谓词,并获得对FirstOrDefault扩展方法的引用,但我似乎无法将它们全部放在一起:
首先是谓词
ParameterExpression parameter = Expression.Parameter(entityType, "Id");
MemberExpression property = Expression.Property(parameter, 3);
ConstantExpression rightSide = Expression.Constant(refId);
BinaryExpression operation = Expression.Equal(property, rightSide);
Type delegateType = typeof (Func<,>).MakeGenericType(entityType, typeof (bool));
LambdaExpression predicate = Expression.Lambda(delegateType, operation, parameter);
现在引用扩展方法:
var method = typeof (System.Linq.Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public)
.FirstOrDefault(m => m.Name == "FirstOrDefault" && m.GetParameters().Count() == 2);
MethodInfo genericMethod = method.MakeGenericMethod(new[] { entityType });
最后尝试执行方法:
object retVal = genericMethod.Invoke(null, new object[] {dbSet, predicate});
使用以下消息抛出ArgumentException:
“System.Reflection.RuntimePropertyInfo”类型的对象无法转换为类型'System.Linq.IQuerable`1 [Person]'。“
有什么想法吗?
答案 0 :(得分:2)
您必须制作该方法的通用版本:
MethodInfo genericMethod = method.MakeGenericMethod(entityType);
object retVal = genericMethod.Invoke(dbSet, new object[] {expr});
顺便说一句。你不应该尝试从System.Linq.Queryable
获取方法吗? System.Linq.Enumerable
完全是关于对象的linq,看起来你正在试图调用你的数据库。
答案 1 :(得分:0)
我想出了问题..我正在反映我的数据上下文以获取dbset,并返回属性信息而不是属性的值。
以上代码现在效果很好..感谢所有人的帮助!
答案 2 :(得分:0)
我有同样的问题。这段代码也对我有用。希望这对您有帮助...
public async Task<Unit> Handle(UpdateCustomCommand<TType> request, CancellationToken cancellationToken)
{
//TODO: set access based on user credentials
var contextCollectionProp = _context.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.FirstOrDefault(e => e.PropertyType == typeof(DbSet<TType>));
if (contextCollectionProp == null)
{
throw new UnSupportedCustomEntityTypeException(typeof(TType), "DB Contexts doesn't contains collection for this type.");
}
var firstOrDefaultMethod = typeof(System.Linq.Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public)
.FirstOrDefault(m => m.Name == "FirstOrDefault" && m.GetParameters().Count() == 2);
if (firstOrDefaultMethod == null)
{
throw new UnSupportedCustomEntityTypeException(typeof(TType), "Cannot find \"Syste.Linq.FirstOrDefault\" method.");
}
Expression<Func<TType, bool>> expr = e => request.Id.Equals(e.ID);
firstOrDefaultMethod = firstOrDefaultMethod.MakeGenericMethod(typeof(TType));
TType item = firstOrDefaultMethod.Invoke(null, new[] { contextCollectionProp.GetValue(_context), expr }) as TType;
if (item == null)
{
throw new NotFoundException(nameof(TType), request.Id);
}
//TODO: use any mapper instead of following code
item.Code = request.Code;
item.Description = request.Description;
await _context.SaveChangesAsync(cancellationToken);
return Unit.Value;
}