From 6ad7a7cce40170ca39fe816745c7e4dc383c1d6f Mon Sep 17 00:00:00 2001 From: ly303550688 Date: Wed, 22 Jun 2022 12:11:03 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20sqlserver=20InsertOrUpdate?= =?UTF-8?q?=20=E6=8C=87=E5=AE=9AOn=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Curd/SqlServerInsertOrUpdateTest.cs | 27 ++++++++++++++++++- .../Curd/SqlServerInsertOrUpdate.cs | 9 ++++++- .../SqlServerExtensions.cs | 19 +++++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/FreeSql.Tests/FreeSql.Tests/SqlServer/Curd/SqlServerInsertOrUpdateTest.cs b/FreeSql.Tests/FreeSql.Tests/SqlServer/Curd/SqlServerInsertOrUpdateTest.cs index 3342e96e..9991361c 100644 --- a/FreeSql.Tests/FreeSql.Tests/SqlServer/Curd/SqlServerInsertOrUpdateTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/SqlServer/Curd/SqlServerInsertOrUpdateTest.cs @@ -1,4 +1,4 @@ -using FreeSql.DataAnnotations; +using FreeSql.DataAnnotations; using FreeSql.Tests.DataContext.SqlServer; using SaleIDO.Entity.Storeage; using System; @@ -371,6 +371,31 @@ WHEN NOT MATCHED THEN var lst = fsql.Select().Where(a => a.id1 == 1 && a.id2 == "01" || a.id1 == 2 && a.id2 == "02" || a.id1 == 3 && a.id2 == "03" || a.id1 == 4 && a.id2 == "04").ToList(); Assert.Equal(4, lst.Where(a => a.name == "00" + a.id1).Count()); } + + [Fact] + public void InsertOrUpdate_OnColumns() + { + var iou = fsql.InsertOrUpdate() + .SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "001" }, new tbiou03 { id1 = 2, id2 = "02", name = "002" }, new tbiou03 { id1 = 3, id2 = "03", name = "003" }, new tbiou03 { id1 = 4, id2 = "04", name = "004" } }) + .OnColumns("name"); + var sql = iou.ToSql(); + Assert.Equal(@"MERGE INTO [tbiou03] t1 +USING (SELECT 1 as [id1], N'01' as [id2], N'001' as [name] +UNION ALL + SELECT 2, N'02', N'002' +UNION ALL + SELECT 3, N'03', N'003' +UNION ALL + SELECT 4, N'04', N'004' ) t2 ON (t1.[name] = t2.[name]) +WHEN MATCHED THEN + update set [name] = t2.[name] +WHEN NOT MATCHED THEN + insert ([id1], [id2], [name]) + values (t2.[id1], t2.[id2], t2.[name]);", sql); + Assert.Equal(4, iou.ExecuteAffrows()); + + } + class tbiou03 { [Column(IsPrimary = true)] diff --git a/Providers/FreeSql.Provider.SqlServer/Curd/SqlServerInsertOrUpdate.cs b/Providers/FreeSql.Provider.SqlServer/Curd/SqlServerInsertOrUpdate.cs index 3fc99fd1..4d1d7bbe 100644 --- a/Providers/FreeSql.Provider.SqlServer/Curd/SqlServerInsertOrUpdate.cs +++ b/Providers/FreeSql.Provider.SqlServer/Curd/SqlServerInsertOrUpdate.cs @@ -10,6 +10,8 @@ namespace FreeSql.SqlServer.Curd class SqlServerInsertOrUpdate : Internal.CommonProvider.InsertOrUpdateProvider where T1 : class { + internal string[] _columns; + public SqlServerInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { @@ -37,7 +39,12 @@ namespace FreeSql.SqlServer.Curd if (IdentityColumn != null) sb.Append("SET IDENTITY_INSERT ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(" ON;\r\n"); sb.Append("MERGE INTO ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(" t1 \r\nUSING ("); WriteSourceSelectUnionAll(data, sb, dbParams); - sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _table.Primarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}"))).Append(") \r\n"); + IEnumerable onColumns; + if (_columns?.Length > 0) + onColumns = _columns.Select(a => $"t1.{_commonUtils.QuoteSqlName(a)} = t2.{_commonUtils.QuoteSqlName(a)}"); + else + onColumns = _table.Primarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}"); + sb.Append(" ) t2 ON (").Append(string.Join(" AND ", onColumns)).Append(") \r\n"); var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true && _updateIgnore.ContainsKey(a.Attribute.Name) == false); if (_doNothing == false && cols.Any()) diff --git a/Providers/FreeSql.Provider.SqlServer/SqlServerExtensions.cs b/Providers/FreeSql.Provider.SqlServer/SqlServerExtensions.cs index a2a6dfd7..d13e580c 100644 --- a/Providers/FreeSql.Provider.SqlServer/SqlServerExtensions.cs +++ b/Providers/FreeSql.Provider.SqlServer/SqlServerExtensions.cs @@ -49,6 +49,25 @@ public static partial class FreeSqlSqlServerGlobalExtensions } internal static ConcurrentDictionary>> _dicSetGlobalSelectWithLock = new ConcurrentDictionary>>(); + /// + /// 使用merge on条件替换默认主键条件 + /// + /// + /// + /// + /// + /// + public static IInsertOrUpdate OnColumns(this IInsertOrUpdate that, params string[] columns) where T : class + { + var insertOrUpdate = that as FreeSql.SqlServer.Curd.SqlServerInsertOrUpdate; + if (insertOrUpdate == null) throw new Exception(CoreStrings.S_Features_Unique("OnColumns", "SqlServer")); + if (columns.Length > 0) + { + insertOrUpdate._columns = columns; + } + return that; + } + #region ExecuteSqlBulkCopy /// /// SqlServer SqlCopyBulk 批量插入功能