114 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C#
		
	
	
			
		
		
	
	
			114 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C#
		
	
	
| 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<string, object?> { { fieldName, fieldValue } });
 | |
| 
 | |
|             return (int)UpdateMethodInfo.MakeGenericMethod(query.ElementType).Invoke(null, new object?[] { query, updateBody });
 | |
|         }
 | |
| 
 | |
|         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, 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 })!;
 | |
|         }
 | |
|         #endregion
 | |
| 
 | |
|         public static Dictionary<string, object?> ExtractFieldValues<TSource>(this Expression<Func<TSource, TSource>> updateFactory)
 | |
|         {
 | |
|             var dic = new Dictionary<string, object?>();
 | |
|             var obj = (TSource)Activator.CreateInstance(typeof(TSource));
 | |
| 
 | |
|             Func<TSource, TSource> 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<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)
 | |
|             {
 | |
|                 return Expression.Convert(Expression.Constant(value), desiredType);
 | |
|             }
 | |
| 
 | |
|             return Expression.Constant(value);
 | |
|         }
 | |
|     }
 | |
| 
 | |
| }
 |