using Microsoft.EntityFrameworkCore.Query; using System.Reflection; namespace IRaCIS.Core.Infra.EFCore { public static class DynamicRelationalExtensions { //升级efcore9 RelationalQueryableExtensions-> EntityFrameworkQueryableExtensions static MethodInfo UpdateMethodInfo = typeof(RelationalQueryableExtensions).GetMethod(nameof(RelationalQueryableExtensions.ExecuteUpdate)); static MethodInfo UpdateAsyncMethodInfo = typeof(RelationalQueryableExtensions).GetMethod(nameof(RelationalQueryableExtensions.ExecuteUpdateAsync)); #region 避免使用 public static int ExecuteUpdate(this IQueryable query, string fieldName, object? fieldValue) { var updateBody = BuildUpdateBody(query.ElementType, new Dictionary { { fieldName, fieldValue } }); return (int)UpdateMethodInfo.MakeGenericMethod(query.ElementType).Invoke(null, new object?[] { query, updateBody }); } public static int ExecuteUpdate(this IQueryable query, IReadOnlyDictionary fieldValues) { var updateBody = BuildUpdateBody(query.ElementType, fieldValues); return (int)UpdateMethodInfo.MakeGenericMethod(query.ElementType).Invoke(null, new object?[] { query, updateBody }); } public static Task ExecuteUpdateAsync(this IQueryable query, string fieldName, object? fieldValue, CancellationToken cancellationToken = default) { var updateBody = BuildUpdateBody(query.ElementType, new Dictionary { { fieldName, fieldValue } }); return (Task)UpdateAsyncMethodInfo.MakeGenericMethod(query.ElementType).Invoke(null, new object?[] { query, updateBody, cancellationToken })!; } #endregion public static Dictionary ExtractFieldValues(this Expression> updateFactory) { var dic = new Dictionary(); var obj = (TSource)Activator.CreateInstance(typeof(TSource)); Func func = updateFactory.Compile(); TSource applyObj = func(obj); var propList = ((MemberInitExpression)updateFactory.Body).Bindings.Select(mb => mb.Member.Name) .Select(propName => typeof(TSource).GetProperty(propName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)).ToList(); foreach (PropertyInfo prop in propList) { object value = prop.GetValue(applyObj); dic.Add(prop.Name, value); } return dic; } public static Task ExecuteUpdateAsync(this IQueryable query, IReadOnlyDictionary fieldValues, CancellationToken cancellationToken = default) { var updateBody = BuildUpdateBody(query.ElementType, fieldValues); return (Task)UpdateAsyncMethodInfo.MakeGenericMethod(query.ElementType).Invoke(null, new object?[] { query, updateBody, cancellationToken })!; } static LambdaExpression BuildUpdateBody(Type entityType, IReadOnlyDictionary 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.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) { return Expression.Convert(Expression.Constant(value), desiredType); } return Expression.Constant(value); } } }