using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Query; using System.Reflection; namespace IRaCIS.Core.Infra.EFCore { public static class DynamicRelationalExtensions { ////升级efcore9 RelationalQueryableExtensions-> EntityFrameworkQueryableExtensions //static MethodInfo UpdateMethodInfo = // typeof(EntityFrameworkQueryableExtensions).GetMethod(nameof(EntityFrameworkQueryableExtensions.ExecuteUpdate)); static MethodInfo UpdateAsyncMethodInfo = typeof(EntityFrameworkQueryableExtensions).GetMethod(nameof(EntityFrameworkQueryableExtensions.ExecuteUpdateAsync)); 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) { ParameterExpression propertyParam = Expression.Parameter(query.ElementType, "p"); Type SetPropertyBuilder = typeof(UpdateSettersBuilder<>).MakeGenericType(query.ElementType); Action BuilderAction = r => { }; foreach (KeyValuePair FieldValue in fieldValues) { MemberExpression propertyExp = Expression.PropertyOrField(propertyParam, FieldValue.Key); MethodInfo? SetPropertyMethodInfo = (SetPropertyBuilder.GetMethods() .FirstOrDefault(r => r.Name == nameof(UpdateSettersBuilder<>.SetProperty) && r.GetParameters().Any(p => p.ParameterType.BaseType == typeof(object)))? .MakeGenericMethod(propertyExp.Type)) ?? throw new Exception("SetPropertyBuilder.SetProperty method is not found"); BuilderAction += r => SetPropertyMethodInfo.Invoke(r, [Expression.Lambda(propertyExp, propertyParam), FieldValue.Value]); } return (Task)UpdateAsyncMethodInfo.MakeGenericMethod(query.ElementType).Invoke(null, [query, BuilderAction, 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); //} } }