基于任何导航方法的通用表达式 属性
Generic Expression Based Any Method on Navigation Property
我正在尝试编写一种基于表达式的通用方法,用于在 DbSet 的导航 属性 上添加“任何”查询。我正在使用 dotnet 核心 5 和 entity framework 核心。目前我得到以下信息:
'DbSet().Where(u => u.UserRoles.Any())' could not be translated
这对我来说似乎是一个合理的查询,但我不确定是否所有类型都正确,或者这是否可能。我目前必须构建的方法如下:
private IQueryable<TEntity> GenericAny(IQueryable<TEntity> queryable)
{
// attempting to replicate
// users.Where(u => u.UserRoles.Any());
var linkedEntityName = "UserRoles";
// once working look at passing these in as parameters
Type listType = typeof(TEntity).GetProperty(linkedEntityName).PropertyType.GetGenericArguments()[0];
var param = Expression.Parameter(typeof(TEntity), "u");
MemberExpression body = Expression.Property(param, linkedEntityName);
// find AsQueryable method to be called on navigation prop
var toQueryable = typeof(Queryable).GetMethods()
.Where(m => m.Name == "AsQueryable")
.Single(m => m.IsGenericMethod)
.MakeGenericMethod(listType);
var anyLambda = Expression.Lambda<Func<TEntity, bool>>(
Expression.Call(
typeof(Enumerable),
"Any",
new Type[] { listType },
Expression.Call(null, toQueryable, body)),
Expression.Parameter(typeof(TEntity), "u"));
var whereMethod = typeof(Queryable)
.GetMethods()
.Where(m => m.Name == "Where" && m.GetParameters().Length == 2)
.First()
.MakeGenericMethod(typeof(TEntity));
var whereCallExpression = Expression.Call(
whereMethod,
queryable.Expression,
anyLambda);
return queryable = queryable.Provider.CreateQuery<TEntity>(whereCallExpression);
}
UserRoles 属性 在用户对象上定义为:
[InverseProperty(nameof(UserRole.User))]
public virtual ICollection<UserRole> UserRoles { get; set; }
我可以直接调用数据库集:
var query = _context.Users
.Include(u => u.UserRoles)
.AsQueryable();
return query.Where(u => u.UserRoles.Any());
我是不是漏掉了什么?非常感谢任何帮助。
这是正确的实现,没有不需要的操作。
public static IQueryable<TEntity> GenericAny<TEntity>(this IQueryable<TEntity> queryable, string linkedEntityName)
{
var param = Expression.Parameter(typeof(TEntity), "e");
var propExpression = Expression.Property(param, linkedEntityName);
var listType = propExpression.Type.GetGenericArguments()[0];
var anyCall =
Expression.Call(
typeof(Enumerable),
nameof(Enumerable.Any),
new[] { listType },
propExpression
);
var predicate = Expression.Lambda<Func<TEntity, bool>>(anyCall, param);
return queryable.Where(predicate);
}
我正在尝试编写一种基于表达式的通用方法,用于在 DbSet 的导航 属性 上添加“任何”查询。我正在使用 dotnet 核心 5 和 entity framework 核心。目前我得到以下信息:
'DbSet().Where(u => u.UserRoles.Any())' could not be translated
这对我来说似乎是一个合理的查询,但我不确定是否所有类型都正确,或者这是否可能。我目前必须构建的方法如下:
private IQueryable<TEntity> GenericAny(IQueryable<TEntity> queryable)
{
// attempting to replicate
// users.Where(u => u.UserRoles.Any());
var linkedEntityName = "UserRoles";
// once working look at passing these in as parameters
Type listType = typeof(TEntity).GetProperty(linkedEntityName).PropertyType.GetGenericArguments()[0];
var param = Expression.Parameter(typeof(TEntity), "u");
MemberExpression body = Expression.Property(param, linkedEntityName);
// find AsQueryable method to be called on navigation prop
var toQueryable = typeof(Queryable).GetMethods()
.Where(m => m.Name == "AsQueryable")
.Single(m => m.IsGenericMethod)
.MakeGenericMethod(listType);
var anyLambda = Expression.Lambda<Func<TEntity, bool>>(
Expression.Call(
typeof(Enumerable),
"Any",
new Type[] { listType },
Expression.Call(null, toQueryable, body)),
Expression.Parameter(typeof(TEntity), "u"));
var whereMethod = typeof(Queryable)
.GetMethods()
.Where(m => m.Name == "Where" && m.GetParameters().Length == 2)
.First()
.MakeGenericMethod(typeof(TEntity));
var whereCallExpression = Expression.Call(
whereMethod,
queryable.Expression,
anyLambda);
return queryable = queryable.Provider.CreateQuery<TEntity>(whereCallExpression);
}
UserRoles 属性 在用户对象上定义为:
[InverseProperty(nameof(UserRole.User))]
public virtual ICollection<UserRole> UserRoles { get; set; }
我可以直接调用数据库集:
var query = _context.Users
.Include(u => u.UserRoles)
.AsQueryable();
return query.Where(u => u.UserRoles.Any());
我是不是漏掉了什么?非常感谢任何帮助。
这是正确的实现,没有不需要的操作。
public static IQueryable<TEntity> GenericAny<TEntity>(this IQueryable<TEntity> queryable, string linkedEntityName)
{
var param = Expression.Parameter(typeof(TEntity), "e");
var propExpression = Expression.Property(param, linkedEntityName);
var listType = propExpression.Type.GetGenericArguments()[0];
var anyCall =
Expression.Call(
typeof(Enumerable),
nameof(Enumerable.Any),
new[] { listType },
propExpression
);
var predicate = Expression.Lambda<Func<TEntity, bool>>(anyCall, param);
return queryable.Where(predicate);
}