我怀着极大的热情在 EF Core 7 中发现了 ExecuteDeleteAsync 和 ExecuteUpdateAsync。它们有助于使我的代码变得更简单、更快。无需使用自制程序批量删除或更新1-2个字段。 无论如何,我遇到了应该在运行时选择要更新的数据库的确切表和字段的情况。
我可以使用数据库表:
public static IQueryable<object> Set(this DbContext context, Type entity) =>
context.ClrQuery(context.ClrType(entity));
我有制作表达式来过滤行的方法:
public static IQueryable Where(this IQueryable source, string equalProperty, object value, [NotNull] Type EntityType)
{
PropertyInfo? property = EntityType.GetProperty(equalProperty);
if (property == null)
throw new NotImplementedException($"Type {EntityType.Name} does not contain property {equalProperty}");
ParameterExpression parameter = Expression.Parameter(EntityType, "r");
MemberExpression member = Expression.MakeMemberAccess(parameter, property);
LambdaExpression whereExpression = Expression.Lambda(Expression.Equal(member, Expression.Constant(value, property.PropertyType)), parameter);
MethodCallExpression resultExpression = WhereCall(source, whereExpression);
return source.Provider.CreateQuery(resultExpression);
}
所以我可以找到要进行更新的行
IQueryable Source = db.Set(EntityType).Where(FieldName, FieldValue, EntityType);
我应该做出表情来更新
IQueryable ExecuteUpdateQuery = Source.ExecuteUpdateAsync(EntityType, FieldName, FieldValue);
SetProperty 的表达式的访问方式是什么?
尝试以下扩展。我还更正了方法签名:
var affected = anyQuery.ExecuteUpdate(FieldName, FieldValue);
var affected = await anyQuery.ExecuteUpdateAsync(FieldName, FieldValue, cancellationToken);
更新版本还支持ppdate的多个字段:
var affected = anyQuery.ExecuteUpdate(new Dictionary<string, object?>
{
{ FieldName1, FieldValue2 },
{ FieldName2, FieldValue2 }
});
和实施:
public static class DynamicRelationalExtensions
{
static MethodInfo UpdateMethodInfo =
typeof(RelationalQueryableExtensions).GetMethod(nameof(RelationalQueryableExtensions.ExecuteUpdate));
static MethodInfo UpdateAsyncMethodInfo =
typeof(RelationalQueryableExtensions).GetMethod(nameof(RelationalQueryableExtensions.ExecuteUpdateAsync));
public static int ExecuteUpdate(this IQueryable query, string fieldName, object? fieldValue)
{
var updateBody = BuildUpdateBody(query.ElementType,
new Dictionary<string, object?> { { fieldName, fieldValue } });
return (int)UpdateMethodInfo.MakeGenericMethod(query.ElementType).Invoke(null, new object?[] { query, updateBody });
}
public static Task<int> ExecuteUpdateAsync(this IQueryable query, string fieldName, object? fieldValue, CancellationToken cancellationToken = default)
{
var updateBody = BuildUpdateBody(query.ElementType,
new Dictionary<string, object?> { { fieldName, fieldValue } });
return (Task<int>)UpdateAsyncMethodInfo.MakeGenericMethod(query.ElementType).Invoke(null, new object?[] { query, updateBody, cancellationToken })!;
}
public static int ExecuteUpdate(this IQueryable query, IReadOnlyDictionary<string, object?> fieldValues)
{
var updateBody = BuildUpdateBody(query.ElementType, fieldValues);
return (int)UpdateMethodInfo.MakeGenericMethod(query.ElementType).Invoke(null, new object?[] { query, updateBody });
}
public static Task<int> ExecuteUpdateAsync(this IQueryable query, IReadOnlyDictionary<string, object?> fieldValues, CancellationToken cancellationToken = default)
{
var updateBody = BuildUpdateBody(query.ElementType, fieldValues);
return (Task<int>)UpdateAsyncMethodInfo.MakeGenericMethod(query.ElementType).Invoke(null, new object?[] { query, updateBody, cancellationToken })!;
}
static LambdaExpression BuildUpdateBody(Type entityType, IReadOnlyDictionary<string, object?> fieldValues)
{
var setParam = Expression.Parameter(typeof(SetPropertyCalls<>).MakeGenericType(entityType), "s");
var objParam = Expression.Parameter(entityType, "e");
Expression setBody = setParam;
foreach (var pair in fieldValues)
{
var propExpression = Expression.PropertyOrField(objParam, pair.Key);
var valueExpression = ValueForType(propExpression.Type, pair.Value);
// s.SetProperty(e => e.SomeField, value)
setBody = Expression.Call(setBody, nameof(SetPropertyCalls<object>.SetProperty),
new[] { propExpression.Type }, Expression.Lambda(propExpression, objParam), valueExpression);
}
// s => s.SetProperty(e => e.SomeField, value)
var updateBody = Expression.Lambda(setBody, setParam);
return updateBody;
}
static Expression ValueForType(Type desiredType, object? value)
{
if (value == null)
{
return Expression.Default(desiredType);
}
if (value.GetType() != desiredType)
{
value = Convert.ChangeType(value, desiredType);
}
return Expression.Constant(value);
}
}