Bläddra i källkod

为EF Core增加AddOrUpdate方法

懒得勤快 5 år sedan
förälder
incheckning
a2e4167fb3

+ 106 - 0
Masuit.Tools.Core/AspNetCore/DbSetExtensions.cs

@@ -0,0 +1,106 @@
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
+
+namespace Masuit.Tools.Core.AspNetCore
+{
+    public static class DbSetExtensions
+    {
+        /// <summary>
+        /// 添加或更新
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <typeparam name="TKey">按哪个字段更新</typeparam>
+        /// <param name="dbSet"></param>
+        /// <param name="keySelector">按哪个字段更新</param>
+        /// <param name="entities"></param>
+        public static void AddOrUpdate<T, TKey>(this DbSet<T> dbSet, Expression<Func<T, TKey>> keySelector, params T[] entities) where T : class
+        {
+            foreach (var entity in entities)
+            {
+                AddOrUpdate(dbSet, keySelector, entity);
+            }
+        }
+
+        /// <summary>
+        /// 添加或更新
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <typeparam name="TKey">按哪个字段更新</typeparam>
+        /// <param name="dbSet"></param>
+        /// <param name="keySelector">按哪个字段更新</param>
+        /// <param name="entity"></param>
+        public static void AddOrUpdate<T, TKey>(this DbSet<T> dbSet, Expression<Func<T, TKey>> keySelector, T entity) where T : class
+        {
+            if (keySelector == null)
+            {
+                throw new ArgumentNullException(nameof(keySelector));
+            }
+
+            if (entity == null)
+            {
+                throw new ArgumentNullException(nameof(entity));
+            }
+
+            var keyObject = keySelector.Compile()(entity);
+            var parameter = Expression.Parameter(typeof(T), "p");
+            var lambda = Expression.Lambda<Func<T, bool>>(Expression.Equal(ReplaceParameter(keySelector.Body, parameter), Expression.Constant(keyObject)), parameter);
+            var item = dbSet.FirstOrDefault(lambda);
+            if (item == null)
+            {
+                dbSet.Add(entity);
+            }
+            else
+            {
+                // 获取主键字段
+                var dataType = typeof(T);
+                var keyFields = dataType.GetProperties().Where(p => p.GetCustomAttribute<KeyAttribute>() != null).ToList();
+                if (!keyFields.Any())
+                {
+                    string idName = dataType.Name + "Id";
+                    keyFields = dataType.GetProperties().Where(p =>
+                        string.Equals(p.Name, "Id", StringComparison.OrdinalIgnoreCase) ||
+                        string.Equals(p.Name, idName, StringComparison.OrdinalIgnoreCase)).ToList();
+                }
+
+                // 更新所有非主键和非集合属性
+                foreach (var p in typeof(T).GetProperties().Where(p => p.GetSetMethod() != null && p.GetGetMethod() != null))
+                {
+                    // 忽略主键
+                    if (keyFields.Any(x => x.Name == p.Name))
+                    {
+                        continue;
+                    }
+
+                    var existingValue = p.GetValue(entity);
+                    if (!Equals(p.GetValue(item), existingValue))
+                    {
+                        p.SetValue(item, existingValue);
+                    }
+                }
+
+                foreach (var idField in keyFields.Where(p => p.GetSetMethod() != null && p.GetGetMethod() != null))
+                {
+                    var existingValue = idField.GetValue(item);
+                    if (!Equals(idField.GetValue(entity), existingValue))
+                    {
+                        idField.SetValue(entity, existingValue);
+                    }
+                }
+            }
+        }
+
+        private static Expression ReplaceParameter(Expression oldExpression, ParameterExpression newParameter)
+        {
+            return oldExpression.NodeType switch
+            {
+                ExpressionType.MemberAccess => (Expression)Expression.MakeMemberAccess(newParameter, ((MemberExpression)oldExpression).Member),
+                ExpressionType.New => Expression.New(((NewExpression)oldExpression).Constructor, ((NewExpression)oldExpression).Arguments.Select(a => ReplaceParameter(a, newParameter)).ToArray()),
+                _ => throw new NotSupportedException("不支持的表达式类型:" + oldExpression.NodeType)
+            };
+        }
+    }
+}

+ 0 - 1
Masuit.Tools.Core/AspNetCore/ServiceCollectionExtensions.cs

@@ -4,7 +4,6 @@ using Masuit.Tools.Core.Net;
 using Masuit.Tools.Files;
 using Microsoft.AspNetCore.Builder;
 using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Mvc;
 using Microsoft.AspNetCore.Mvc.Infrastructure;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.DependencyInjection.Extensions;

+ 3 - 2
Masuit.Tools.Core/Masuit.Tools.Core.csproj

@@ -2,7 +2,7 @@
 
   <PropertyGroup>
     <TargetFramework>netstandard2.1</TargetFramework>
-    <Version>2.2.8.2</Version>
+    <Version>2.2.8.3</Version>
     <Authors>懒得勤快</Authors>
     <Company>masuit.com</Company>
     <Description>包含一些常用的操作类,大都是静态类,加密解密,反射操作,硬件信息,字符串扩展方法,日期时间扩展操作,大文件拷贝,图像裁剪,html处理,验证码、NoSql等常用封装。
@@ -129,8 +129,9 @@ github:https://github.com/ldqk/Masuit.Tools</Description>
 
   <ItemGroup>
     <PackageReference Include="HtmlAgilityPack" Version="1.11.21" />
-    <PackageReference Include="HtmlSanitizer" Version="4.0.217" />
+    <PackageReference Include="HtmlSanitizer" Version="5.0.298" />
     <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
+    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.2" />
     <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.2" />
     <PackageReference Include="Microsoft.Extensions.Http" Version="3.1.2" />
     <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />

+ 2 - 2
Masuit.Tools/Masuit.Tools.csproj

@@ -52,8 +52,8 @@
     <Reference Include="HtmlAgilityPack, Version=1.11.21.0, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
       <HintPath>..\packages\HtmlAgilityPack.1.11.21\lib\Net45\HtmlAgilityPack.dll</HintPath>
     </Reference>
-    <Reference Include="HtmlSanitizer, Version=4.0.0.0, Culture=neutral, PublicKeyToken=61c49a1a9e79cc28, processorArchitecture=MSIL">
-      <HintPath>..\packages\HtmlSanitizer.4.0.217\lib\net45\HtmlSanitizer.dll</HintPath>
+    <Reference Include="HtmlSanitizer, Version=5.0.0.0, Culture=neutral, PublicKeyToken=61c49a1a9e79cc28, processorArchitecture=MSIL">
+      <HintPath>..\packages\HtmlSanitizer.5.0.298\lib\net46\HtmlSanitizer.dll</HintPath>
     </Reference>
     <Reference Include="Microsoft.CSharp" />
     <Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">

+ 1 - 1
Masuit.Tools/packages.config

@@ -2,7 +2,7 @@
 <packages>
   <package id="AngleSharp" version="0.13.0" targetFramework="net461" />
   <package id="HtmlAgilityPack" version="1.11.21" targetFramework="net461" />
-  <package id="HtmlSanitizer" version="4.0.217" targetFramework="net461" />
+  <package id="HtmlSanitizer" version="5.0.298" targetFramework="net461" />
   <package id="Microsoft.AspNet.Mvc" version="5.2.7" targetFramework="net45" />
   <package id="Microsoft.AspNet.Razor" version="3.2.7" targetFramework="net45" />
   <package id="Microsoft.AspNet.WebPages" version="3.2.7" targetFramework="net45" />