动态 LINQ 而不是 ExecuteSqlRaw
Dynamic LINQ instead of ExecuteSqlRaw
因为我要使用Entity Framework Core,所以我尝试转换一个SqlRaw语句
var sql = @$"
update ItemList
set flag = 1
where
flag = 0 and
{groupingField} in (select {groupingField} from ItemList
where ID in (select itemID from selectedItems))
";
int noOfRowsAffected = DbContext.ExecuteSqlRaw(sql);
转换为一系列 LINQ 语句。
var ids = DbContext.selectedItems
.Select(x => x.itemID).ToList();
var groupIds = DbContext.ItemList
.Where(p => ids.Contains(p.Id) && p.flag == 0
.Select(p => p.GetType().GetProperty(groupingField).GetValue(p)).ToList();
var rows = DbContext.ItemList
.Where(p => groupIds.Contains(p.GetType().GetProperty(groupingField).GetValue(p)))
.ToList();
foreach(var row in rows)
{
row.flag = 1;
}
当我执行语句时,我在第三条语句 (var rows = ...) 上捕获到异常:
The LINQ expression 'DbSet<ItemList>
.Where(t => __groupIds_0.Contains(t.GetType().GetProperty(__groupingField_1).GetValue(t)))' could not be
translated. Either rewrite the query in a form that can be translated, or switch to client evaluation
explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync().
See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
如何重写可以翻译的声明?
以下扩展有助于完成您想要的工作,甚至支持 IEnumerable
和 IQueryable
项目:
var ids = DbContext.selectedItems.Select(x => x.itemID);
var rows = DbContext.ItemList
.FilterByItems(ids, groupingField)
.Where(p => p.flag == 0)
.ToList();
foreach (var row in rows)
{
row.flag = 1;
}
和实现:
public static class FilterExtensions
{
public static IQueryable<TEntity> FilterByItems<TEntity, TKey>(this IQueryable<TEntity> query,
IEnumerable<TKey> items, Expression<Func<TEntity, TKey>> entityKey)
{
var entityParam = entityKey.Parameters[0];
if (items is IQueryable queryableItems)
{
var containsLambda = Expression.Lambda<Func<TEntity, bool>>(
Expression.Call(typeof(Queryable), nameof(Queryable.Contains),
new[] {typeof(TKey)},
queryableItems.Expression,
entityKey.Body
),
entityParam);
return query.Where(containsLambda);
}
else
{
var containsLambda = Expression.Lambda<Func<TEntity, bool>>(
Expression.Call(typeof(Enumerable), nameof(Enumerable.Contains),
new[] {typeof(TKey)},
Expression.Constant(items),
entityKey.Body
),
entityParam);
return query.Where(containsLambda);
}
}
public static IQueryable<TEntity> FilterByItems<TEntity, TKey>(this IQueryable<TEntity> query,
IEnumerable<TKey> items, string entityKey)
{
var entityParam = Expression.Parameter(typeof(TEntity), "e");
var entityKeyLambda =
Expression.Lambda<Func<TEntity, TKey>>(Expression.PropertyOrField(entityParam, entityKey), entityParam);
return query.FilterByItems(items, entityKeyLambda);
}
}
因为我要使用Entity Framework Core,所以我尝试转换一个SqlRaw语句
var sql = @$"
update ItemList
set flag = 1
where
flag = 0 and
{groupingField} in (select {groupingField} from ItemList
where ID in (select itemID from selectedItems))
";
int noOfRowsAffected = DbContext.ExecuteSqlRaw(sql);
转换为一系列 LINQ 语句。
var ids = DbContext.selectedItems
.Select(x => x.itemID).ToList();
var groupIds = DbContext.ItemList
.Where(p => ids.Contains(p.Id) && p.flag == 0
.Select(p => p.GetType().GetProperty(groupingField).GetValue(p)).ToList();
var rows = DbContext.ItemList
.Where(p => groupIds.Contains(p.GetType().GetProperty(groupingField).GetValue(p)))
.ToList();
foreach(var row in rows)
{
row.flag = 1;
}
当我执行语句时,我在第三条语句 (var rows = ...) 上捕获到异常:
The LINQ expression 'DbSet<ItemList>
.Where(t => __groupIds_0.Contains(t.GetType().GetProperty(__groupingField_1).GetValue(t)))' could not be
translated. Either rewrite the query in a form that can be translated, or switch to client evaluation
explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync().
See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
如何重写可以翻译的声明?
以下扩展有助于完成您想要的工作,甚至支持 IEnumerable
和 IQueryable
项目:
var ids = DbContext.selectedItems.Select(x => x.itemID);
var rows = DbContext.ItemList
.FilterByItems(ids, groupingField)
.Where(p => p.flag == 0)
.ToList();
foreach (var row in rows)
{
row.flag = 1;
}
和实现:
public static class FilterExtensions
{
public static IQueryable<TEntity> FilterByItems<TEntity, TKey>(this IQueryable<TEntity> query,
IEnumerable<TKey> items, Expression<Func<TEntity, TKey>> entityKey)
{
var entityParam = entityKey.Parameters[0];
if (items is IQueryable queryableItems)
{
var containsLambda = Expression.Lambda<Func<TEntity, bool>>(
Expression.Call(typeof(Queryable), nameof(Queryable.Contains),
new[] {typeof(TKey)},
queryableItems.Expression,
entityKey.Body
),
entityParam);
return query.Where(containsLambda);
}
else
{
var containsLambda = Expression.Lambda<Func<TEntity, bool>>(
Expression.Call(typeof(Enumerable), nameof(Enumerable.Contains),
new[] {typeof(TKey)},
Expression.Constant(items),
entityKey.Body
),
entityParam);
return query.Where(containsLambda);
}
}
public static IQueryable<TEntity> FilterByItems<TEntity, TKey>(this IQueryable<TEntity> query,
IEnumerable<TKey> items, string entityKey)
{
var entityParam = Expression.Parameter(typeof(TEntity), "e");
var entityKeyLambda =
Expression.Lambda<Func<TEntity, TKey>>(Expression.PropertyOrField(entityParam, entityKey), entityParam);
return query.FilterByItems(items, entityKeyLambda);
}
}