diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml
index 3f9fb047..2711e35d 100644
--- a/FreeSql.DbContext/FreeSql.DbContext.xml
+++ b/FreeSql.DbContext/FreeSql.DbContext.xml
@@ -99,6 +99,13 @@
清空状态数据
+
+
+ 根据 lambda 条件删除数据
+
+
+
+
添加
diff --git a/FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/MySqlConnector/Curd/OnDuplicateKeyUpdateTest.cs b/FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/MySqlConnector/Curd/OnDuplicateKeyUpdateTest.cs
new file mode 100644
index 00000000..ff852737
--- /dev/null
+++ b/FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/MySqlConnector/Curd/OnDuplicateKeyUpdateTest.cs
@@ -0,0 +1,201 @@
+using FreeSql.DataAnnotations;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Xunit;
+
+namespace FreeSql.Tests.MySqlConnector
+{
+ public class OnDuplicateKeyUpdateTest
+ {
+ class TestOnDuplicateKeyUpdateInfo
+ {
+ [Column(IsIdentity = true)]
+ public int id { get; set; }
+ public string title { get; set; }
+ public DateTime time { get; set; }
+ }
+
+ [Fact]
+ public void ExecuteAffrows()
+ {
+ g.mysql.Delete(new[] { 100, 101, 102 }).ExecuteAffrows();
+ var odku1 = g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 100, title = "title-100", time = DateTime.Parse("2000-01-01") }).NoneParameter().OnDuplicateKeyUpdate();
+ Assert.Equal(odku1.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`, `time`) VALUES(100, 'title-100', '2000-01-01 00:00:00.000')
+ON DUPLICATE KEY UPDATE
+`title` = VALUES(`title`),
+`time` = VALUES(`time`)");
+ Assert.Equal(1, odku1.ExecuteAffrows());
+
+ var odku2 = g.mysql.Insert(new[] {
+ new TestOnDuplicateKeyUpdateInfo { id = 100, title = "title-100", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 101, title = "title-101", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 102, title = "title-102", time = DateTime.Parse("2000-01-01") }
+ }).NoneParameter().OnDuplicateKeyUpdate();
+ Assert.Equal(odku2.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`, `time`) VALUES(100, 'title-100', '2000-01-01 00:00:00.000'), (101, 'title-101', '2000-01-01 00:00:00.000'), (102, 'title-102', '2000-01-01 00:00:00.000')
+ON DUPLICATE KEY UPDATE
+`title` = VALUES(`title`),
+`time` = VALUES(`time`)");
+ odku2.ExecuteAffrows();
+ }
+
+ [Fact]
+ public void IgnoreColumns()
+ {
+ g.mysql.Delete(new[] { 200, 201, 202 }).ExecuteAffrows();
+ var odku1 = g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 200, title = "title-200", time = DateTime.Parse("2000-01-01") }).IgnoreColumns(a => a.time).NoneParameter().OnDuplicateKeyUpdate();
+ Assert.Equal(odku1.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(200, 'title-200')
+ON DUPLICATE KEY UPDATE
+`title` = VALUES(`title`),
+`time` = '2000-01-01 00:00:00.000'");
+ Assert.Equal(1, odku1.ExecuteAffrows());
+
+ var odku2 = g.mysql.Insert(new[] {
+ new TestOnDuplicateKeyUpdateInfo { id = 200, title = "title-200", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 201, title = "title-201", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 202, title = "title-202", time = DateTime.Parse("2000-01-01") }
+ }).IgnoreColumns(a => a.time).NoneParameter().OnDuplicateKeyUpdate();
+ Assert.Equal(odku2.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(200, 'title-200'), (201, 'title-201'), (202, 'title-202')
+ON DUPLICATE KEY UPDATE
+`title` = VALUES(`title`),
+`time` = CASE `id`
+WHEN 200 THEN '2000-01-01 00:00:00.000'
+WHEN 201 THEN '2000-01-01 00:00:00.000'
+WHEN 202 THEN '2000-01-01 00:00:00.000' END");
+ odku2.ExecuteAffrows();
+
+
+ g.mysql.Delete(new[] { 200, 201, 202 }).ExecuteAffrows();
+ odku1 = g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 200, title = "title-200", time = DateTime.Parse("2000-01-01") }).IgnoreColumns(a => a.time).NoneParameter().OnDuplicateKeyUpdate().IgnoreColumns(a => a.title);
+ Assert.Equal(odku1.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(200, 'title-200')
+ON DUPLICATE KEY UPDATE
+`time` = '2000-01-01 00:00:00.000'");
+ Assert.Equal(1, odku1.ExecuteAffrows());
+
+ odku2 = g.mysql.Insert(new[] {
+ new TestOnDuplicateKeyUpdateInfo { id = 200, title = "title-200", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 201, title = "title-201", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 202, title = "title-202", time = DateTime.Parse("2000-01-01") }
+ }).IgnoreColumns(a => a.time).NoneParameter().OnDuplicateKeyUpdate().IgnoreColumns(a => a.title);
+ Assert.Equal(odku2.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(200, 'title-200'), (201, 'title-201'), (202, 'title-202')
+ON DUPLICATE KEY UPDATE
+`time` = CASE `id`
+WHEN 200 THEN '2000-01-01 00:00:00.000'
+WHEN 201 THEN '2000-01-01 00:00:00.000'
+WHEN 202 THEN '2000-01-01 00:00:00.000' END");
+ odku2.ExecuteAffrows();
+ }
+
+ [Fact]
+ public void UpdateColumns()
+ {
+ g.mysql.Delete(new[] { 300, 301, 302 }).ExecuteAffrows();
+ var odku1 = g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 300, title = "title-300", time = DateTime.Parse("2000-01-01") }).InsertColumns(a => a.title).NoneParameter().OnDuplicateKeyUpdate();
+ Assert.Equal(odku1.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(300, 'title-300')
+ON DUPLICATE KEY UPDATE
+`title` = VALUES(`title`),
+`time` = '2000-01-01 00:00:00.000'");
+ Assert.Equal(1, odku1.ExecuteAffrows());
+
+ var odku2 = g.mysql.Insert(new[] {
+ new TestOnDuplicateKeyUpdateInfo { id = 300, title = "title-300", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 301, title = "title-301", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 302, title = "title-302", time = DateTime.Parse("2000-01-01") }
+ }).InsertColumns(a => a.title).NoneParameter().OnDuplicateKeyUpdate();
+ Assert.Equal(odku2.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(300, 'title-300'), (301, 'title-301'), (302, 'title-302')
+ON DUPLICATE KEY UPDATE
+`title` = VALUES(`title`),
+`time` = CASE `id`
+WHEN 300 THEN '2000-01-01 00:00:00.000'
+WHEN 301 THEN '2000-01-01 00:00:00.000'
+WHEN 302 THEN '2000-01-01 00:00:00.000' END");
+ odku2.ExecuteAffrows();
+
+
+ g.mysql.Delete(new[] { 300, 301, 302 }).ExecuteAffrows();
+ odku1 = g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 300, title = "title-300", time = DateTime.Parse("2000-01-01") }).InsertColumns(a => a.title).NoneParameter().OnDuplicateKeyUpdate().UpdateColumns(a => a.time);
+ Assert.Equal(odku1.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(300, 'title-300')
+ON DUPLICATE KEY UPDATE
+`time` = '2000-01-01 00:00:00.000'");
+ Assert.Equal(1, odku1.ExecuteAffrows());
+
+ odku2 = g.mysql.Insert(new[] {
+ new TestOnDuplicateKeyUpdateInfo { id = 300, title = "title-300", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 301, title = "title-301", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 302, title = "title-302", time = DateTime.Parse("2000-01-01") }
+ }).InsertColumns(a => a.title).NoneParameter().OnDuplicateKeyUpdate().UpdateColumns(a => a.time);
+ Assert.Equal(odku2.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(300, 'title-300'), (301, 'title-301'), (302, 'title-302')
+ON DUPLICATE KEY UPDATE
+`time` = CASE `id`
+WHEN 300 THEN '2000-01-01 00:00:00.000'
+WHEN 301 THEN '2000-01-01 00:00:00.000'
+WHEN 302 THEN '2000-01-01 00:00:00.000' END");
+ odku2.ExecuteAffrows();
+ }
+
+ [Fact]
+ public void Set()
+ {
+ g.mysql.Delete(new[] { 400, 401, 402 }).ExecuteAffrows();
+ var odku1 = g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") }).NoneParameter().OnDuplicateKeyUpdate().Set(a => a.time, DateTime.Parse("2020-1-1"));
+ Assert.Equal(odku1.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`, `time`) VALUES(400, 'title-400', '2000-01-01 00:00:00.000')
+ON DUPLICATE KEY UPDATE
+`time` = '2020-01-01 00:00:00.000'");
+ Assert.Equal(1, odku1.ExecuteAffrows());
+
+ var odku2 = g.mysql.Insert(new[] {
+ new TestOnDuplicateKeyUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 401, title = "title-401", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 402, title = "title-402", time = DateTime.Parse("2000-01-01") }
+ }).NoneParameter().OnDuplicateKeyUpdate().Set(a => a.time, DateTime.Parse("2020-1-1"));
+ Assert.Equal(odku2.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`, `time`) VALUES(400, 'title-400', '2000-01-01 00:00:00.000'), (401, 'title-401', '2000-01-01 00:00:00.000'), (402, 'title-402', '2000-01-01 00:00:00.000')
+ON DUPLICATE KEY UPDATE
+`time` = '2020-01-01 00:00:00.000'");
+ odku2.ExecuteAffrows();
+
+
+ var dt2020 = DateTime.Parse("2020-1-1");
+ g.mysql.Delete(new[] { 400, 401, 402 }).ExecuteAffrows();
+ odku1 = g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") }).NoneParameter().OnDuplicateKeyUpdate().Set(a => a.time == dt2020);
+ Assert.Equal(odku1.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`, `time`) VALUES(400, 'title-400', '2000-01-01 00:00:00.000')
+ON DUPLICATE KEY UPDATE
+`time` = '2020-01-01 00:00:00.000'");
+ Assert.Equal(1, odku1.ExecuteAffrows());
+
+ odku2 = g.mysql.Insert(new[] {
+ new TestOnDuplicateKeyUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 401, title = "title-401", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 402, title = "title-402", time = DateTime.Parse("2000-01-01") }
+ }).NoneParameter().OnDuplicateKeyUpdate().Set(a => a.time == dt2020);
+ Assert.Equal(odku2.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`, `time`) VALUES(400, 'title-400', '2000-01-01 00:00:00.000'), (401, 'title-401', '2000-01-01 00:00:00.000'), (402, 'title-402', '2000-01-01 00:00:00.000')
+ON DUPLICATE KEY UPDATE
+`time` = '2020-01-01 00:00:00.000'");
+ odku2.ExecuteAffrows();
+
+
+ g.mysql.Delete(new[] { 400, 401, 402 }).ExecuteAffrows();
+ odku1 = g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") }).NoneParameter().OnDuplicateKeyUpdate().Set(a => new { time = dt2020, title = a.title + "123" });
+ Assert.Equal(odku1.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`, `time`) VALUES(400, 'title-400', '2000-01-01 00:00:00.000')
+ON DUPLICATE KEY UPDATE
+`time` = '2020-01-01 00:00:00.000', `title` = concat(`title`, '123')");
+ Assert.Equal(1, odku1.ExecuteAffrows());
+
+ odku2 = g.mysql.Insert(new[] {
+ new TestOnDuplicateKeyUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 401, title = "title-401", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 402, title = "title-402", time = DateTime.Parse("2000-01-01") }
+ }).NoneParameter().OnDuplicateKeyUpdate().Set(a => new { time = dt2020, title = a.title + "123" });
+ Assert.Equal(odku2.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`, `time`) VALUES(400, 'title-400', '2000-01-01 00:00:00.000'), (401, 'title-401', '2000-01-01 00:00:00.000'), (402, 'title-402', '2000-01-01 00:00:00.000')
+ON DUPLICATE KEY UPDATE
+`time` = '2020-01-01 00:00:00.000', `title` = concat(`title`, '123')");
+ odku2.ExecuteAffrows();
+ }
+
+ [Fact]
+ public void SetRaw()
+ {
+
+ }
+
+ }
+}
diff --git a/FreeSql.Tests/FreeSql.Tests/.editorconfig b/FreeSql.Tests/FreeSql.Tests/.editorconfig
new file mode 100644
index 00000000..d2f6a096
--- /dev/null
+++ b/FreeSql.Tests/FreeSql.Tests/.editorconfig
@@ -0,0 +1,4 @@
+[*.cs]
+
+# xUnit2000: Constants and literals should be the expected argument
+dotnet_diagnostic.xUnit2000.severity = none
diff --git a/FreeSql.Tests/FreeSql.Tests/MySql/Curd/OnDuplicateKeyUpdateTest.cs b/FreeSql.Tests/FreeSql.Tests/MySql/Curd/OnDuplicateKeyUpdateTest.cs
new file mode 100644
index 00000000..00ec83ad
--- /dev/null
+++ b/FreeSql.Tests/FreeSql.Tests/MySql/Curd/OnDuplicateKeyUpdateTest.cs
@@ -0,0 +1,201 @@
+using FreeSql.DataAnnotations;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Xunit;
+
+namespace FreeSql.Tests.MySql
+{
+ public class OnDuplicateKeyUpdateTest
+ {
+ class TestOnDuplicateKeyUpdateInfo
+ {
+ [Column(IsIdentity = true)]
+ public int id { get; set; }
+ public string title { get; set; }
+ public DateTime time { get; set; }
+ }
+
+ [Fact]
+ public void ExecuteAffrows()
+ {
+ g.mysql.Delete(new[] { 100, 101, 102 }).ExecuteAffrows();
+ var odku1 = g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 100, title = "title-100", time = DateTime.Parse("2000-01-01") }).NoneParameter().OnDuplicateKeyUpdate();
+ Assert.Equal(odku1.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`, `time`) VALUES(100, 'title-100', '2000-01-01 00:00:00.000')
+ON DUPLICATE KEY UPDATE
+`title` = VALUES(`title`),
+`time` = VALUES(`time`)");
+ Assert.Equal(1, odku1.ExecuteAffrows());
+
+ var odku2 = g.mysql.Insert(new[] {
+ new TestOnDuplicateKeyUpdateInfo { id = 100, title = "title-100", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 101, title = "title-101", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 102, title = "title-102", time = DateTime.Parse("2000-01-01") }
+ }).NoneParameter().OnDuplicateKeyUpdate();
+ Assert.Equal(odku2.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`, `time`) VALUES(100, 'title-100', '2000-01-01 00:00:00.000'), (101, 'title-101', '2000-01-01 00:00:00.000'), (102, 'title-102', '2000-01-01 00:00:00.000')
+ON DUPLICATE KEY UPDATE
+`title` = VALUES(`title`),
+`time` = VALUES(`time`)");
+ odku2.ExecuteAffrows();
+ }
+
+ [Fact]
+ public void IgnoreColumns()
+ {
+ g.mysql.Delete(new[] { 200, 201, 202 }).ExecuteAffrows();
+ var odku1 = g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 200, title = "title-200", time = DateTime.Parse("2000-01-01") }).IgnoreColumns(a => a.time).NoneParameter().OnDuplicateKeyUpdate();
+ Assert.Equal(odku1.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(200, 'title-200')
+ON DUPLICATE KEY UPDATE
+`title` = VALUES(`title`),
+`time` = '2000-01-01 00:00:00.000'");
+ Assert.Equal(1, odku1.ExecuteAffrows());
+
+ var odku2 = g.mysql.Insert(new[] {
+ new TestOnDuplicateKeyUpdateInfo { id = 200, title = "title-200", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 201, title = "title-201", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 202, title = "title-202", time = DateTime.Parse("2000-01-01") }
+ }).IgnoreColumns(a => a.time).NoneParameter().OnDuplicateKeyUpdate();
+ Assert.Equal(odku2.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(200, 'title-200'), (201, 'title-201'), (202, 'title-202')
+ON DUPLICATE KEY UPDATE
+`title` = VALUES(`title`),
+`time` = CASE `id`
+WHEN 200 THEN '2000-01-01 00:00:00.000'
+WHEN 201 THEN '2000-01-01 00:00:00.000'
+WHEN 202 THEN '2000-01-01 00:00:00.000' END");
+ odku2.ExecuteAffrows();
+
+
+ g.mysql.Delete(new[] { 200, 201, 202 }).ExecuteAffrows();
+ odku1 = g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 200, title = "title-200", time = DateTime.Parse("2000-01-01") }).IgnoreColumns(a => a.time).NoneParameter().OnDuplicateKeyUpdate().IgnoreColumns(a => a.title);
+ Assert.Equal(odku1.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(200, 'title-200')
+ON DUPLICATE KEY UPDATE
+`time` = '2000-01-01 00:00:00.000'");
+ Assert.Equal(1, odku1.ExecuteAffrows());
+
+ odku2 = g.mysql.Insert(new[] {
+ new TestOnDuplicateKeyUpdateInfo { id = 200, title = "title-200", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 201, title = "title-201", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 202, title = "title-202", time = DateTime.Parse("2000-01-01") }
+ }).IgnoreColumns(a => a.time).NoneParameter().OnDuplicateKeyUpdate().IgnoreColumns(a => a.title);
+ Assert.Equal(odku2.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(200, 'title-200'), (201, 'title-201'), (202, 'title-202')
+ON DUPLICATE KEY UPDATE
+`time` = CASE `id`
+WHEN 200 THEN '2000-01-01 00:00:00.000'
+WHEN 201 THEN '2000-01-01 00:00:00.000'
+WHEN 202 THEN '2000-01-01 00:00:00.000' END");
+ odku2.ExecuteAffrows();
+ }
+
+ [Fact]
+ public void UpdateColumns()
+ {
+ g.mysql.Delete(new[] { 300, 301, 302 }).ExecuteAffrows();
+ var odku1 = g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 300, title = "title-300", time = DateTime.Parse("2000-01-01") }).InsertColumns(a => a.title).NoneParameter().OnDuplicateKeyUpdate();
+ Assert.Equal(odku1.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(300, 'title-300')
+ON DUPLICATE KEY UPDATE
+`title` = VALUES(`title`),
+`time` = '2000-01-01 00:00:00.000'");
+ Assert.Equal(1, odku1.ExecuteAffrows());
+
+ var odku2 = g.mysql.Insert(new[] {
+ new TestOnDuplicateKeyUpdateInfo { id = 300, title = "title-300", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 301, title = "title-301", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 302, title = "title-302", time = DateTime.Parse("2000-01-01") }
+ }).InsertColumns(a => a.title).NoneParameter().OnDuplicateKeyUpdate();
+ Assert.Equal(odku2.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(300, 'title-300'), (301, 'title-301'), (302, 'title-302')
+ON DUPLICATE KEY UPDATE
+`title` = VALUES(`title`),
+`time` = CASE `id`
+WHEN 300 THEN '2000-01-01 00:00:00.000'
+WHEN 301 THEN '2000-01-01 00:00:00.000'
+WHEN 302 THEN '2000-01-01 00:00:00.000' END");
+ odku2.ExecuteAffrows();
+
+
+ g.mysql.Delete(new[] { 300, 301, 302 }).ExecuteAffrows();
+ odku1 = g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 300, title = "title-300", time = DateTime.Parse("2000-01-01") }).InsertColumns(a => a.title).NoneParameter().OnDuplicateKeyUpdate().UpdateColumns(a => a.time);
+ Assert.Equal(odku1.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(300, 'title-300')
+ON DUPLICATE KEY UPDATE
+`time` = '2000-01-01 00:00:00.000'");
+ Assert.Equal(1, odku1.ExecuteAffrows());
+
+ odku2 = g.mysql.Insert(new[] {
+ new TestOnDuplicateKeyUpdateInfo { id = 300, title = "title-300", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 301, title = "title-301", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 302, title = "title-302", time = DateTime.Parse("2000-01-01") }
+ }).InsertColumns(a => a.title).NoneParameter().OnDuplicateKeyUpdate().UpdateColumns(a => a.time);
+ Assert.Equal(odku2.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(300, 'title-300'), (301, 'title-301'), (302, 'title-302')
+ON DUPLICATE KEY UPDATE
+`time` = CASE `id`
+WHEN 300 THEN '2000-01-01 00:00:00.000'
+WHEN 301 THEN '2000-01-01 00:00:00.000'
+WHEN 302 THEN '2000-01-01 00:00:00.000' END");
+ odku2.ExecuteAffrows();
+ }
+
+ [Fact]
+ public void Set()
+ {
+ g.mysql.Delete(new[] { 400, 401, 402 }).ExecuteAffrows();
+ var odku1 = g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") }).NoneParameter().OnDuplicateKeyUpdate().Set(a => a.time, DateTime.Parse("2020-1-1"));
+ Assert.Equal(odku1.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`, `time`) VALUES(400, 'title-400', '2000-01-01 00:00:00.000')
+ON DUPLICATE KEY UPDATE
+`time` = '2020-01-01 00:00:00.000'");
+ Assert.Equal(1, odku1.ExecuteAffrows());
+
+ var odku2 = g.mysql.Insert(new[] {
+ new TestOnDuplicateKeyUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 401, title = "title-401", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 402, title = "title-402", time = DateTime.Parse("2000-01-01") }
+ }).NoneParameter().OnDuplicateKeyUpdate().Set(a => a.time, DateTime.Parse("2020-1-1"));
+ Assert.Equal(odku2.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`, `time`) VALUES(400, 'title-400', '2000-01-01 00:00:00.000'), (401, 'title-401', '2000-01-01 00:00:00.000'), (402, 'title-402', '2000-01-01 00:00:00.000')
+ON DUPLICATE KEY UPDATE
+`time` = '2020-01-01 00:00:00.000'");
+ odku2.ExecuteAffrows();
+
+
+ var dt2020 = DateTime.Parse("2020-1-1");
+ g.mysql.Delete(new[] { 400, 401, 402 }).ExecuteAffrows();
+ odku1 = g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") }).NoneParameter().OnDuplicateKeyUpdate().Set(a => a.time == dt2020);
+ Assert.Equal(odku1.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`, `time`) VALUES(400, 'title-400', '2000-01-01 00:00:00.000')
+ON DUPLICATE KEY UPDATE
+`time` = '2020-01-01 00:00:00.000'");
+ Assert.Equal(1, odku1.ExecuteAffrows());
+
+ odku2 = g.mysql.Insert(new[] {
+ new TestOnDuplicateKeyUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 401, title = "title-401", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 402, title = "title-402", time = DateTime.Parse("2000-01-01") }
+ }).NoneParameter().OnDuplicateKeyUpdate().Set(a => a.time == dt2020);
+ Assert.Equal(odku2.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`, `time`) VALUES(400, 'title-400', '2000-01-01 00:00:00.000'), (401, 'title-401', '2000-01-01 00:00:00.000'), (402, 'title-402', '2000-01-01 00:00:00.000')
+ON DUPLICATE KEY UPDATE
+`time` = '2020-01-01 00:00:00.000'");
+ odku2.ExecuteAffrows();
+
+
+ g.mysql.Delete(new[] { 400, 401, 402 }).ExecuteAffrows();
+ odku1 = g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") }).NoneParameter().OnDuplicateKeyUpdate().Set(a => new { time = dt2020, title = a.title + "123" });
+ Assert.Equal(odku1.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`, `time`) VALUES(400, 'title-400', '2000-01-01 00:00:00.000')
+ON DUPLICATE KEY UPDATE
+`time` = '2020-01-01 00:00:00.000', `title` = concat(`title`, '123')");
+ Assert.Equal(1, odku1.ExecuteAffrows());
+
+ odku2 = g.mysql.Insert(new[] {
+ new TestOnDuplicateKeyUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 401, title = "title-401", time = DateTime.Parse("2000-01-01") },
+ new TestOnDuplicateKeyUpdateInfo { id = 402, title = "title-402", time = DateTime.Parse("2000-01-01") }
+ }).NoneParameter().OnDuplicateKeyUpdate().Set(a => new { time = dt2020, title = a.title + "123" });
+ Assert.Equal(odku2.ToSql(), @"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`, `time`) VALUES(400, 'title-400', '2000-01-01 00:00:00.000'), (401, 'title-401', '2000-01-01 00:00:00.000'), (402, 'title-402', '2000-01-01 00:00:00.000')
+ON DUPLICATE KEY UPDATE
+`time` = '2020-01-01 00:00:00.000', `title` = concat(`title`, '123')");
+ odku2.ExecuteAffrows();
+ }
+
+ [Fact]
+ public void SetRaw()
+ {
+
+ }
+
+ }
+}
diff --git a/FreeSql/Internal/CommonProvider/InsertProvider.cs b/FreeSql/Internal/CommonProvider/InsertProvider.cs
index f0389815..d7a95343 100644
--- a/FreeSql/Internal/CommonProvider/InsertProvider.cs
+++ b/FreeSql/Internal/CommonProvider/InsertProvider.cs
@@ -419,8 +419,8 @@ namespace FreeSql.Internal.CommonProvider
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
- if (_ignore.ContainsKey(col.Attribute.Name)) continue;
if (col.Attribute.IsIdentity && _insertIdentity == false) continue;
+ if (col.Attribute.IsIdentity == false && _ignore.ContainsKey(col.Attribute.Name)) continue;
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name));
@@ -437,8 +437,8 @@ namespace FreeSql.Internal.CommonProvider
var colidx2 = 0;
foreach (var col in _table.Columns.Values)
{
- if (_ignore.ContainsKey(col.Attribute.Name)) continue;
if (col.Attribute.IsIdentity && _insertIdentity == false) continue;
+ if (col.Attribute.IsIdentity == false && _ignore.ContainsKey(col.Attribute.Name)) continue;
if (colidx2 > 0) sb.Append(", ");
object val = col.GetMapValue(d);
diff --git a/Providers/FreeSql.Provider.MySql/Curd/MySqlInsert.cs b/Providers/FreeSql.Provider.MySql/Curd/MySqlInsert.cs
index 41b20ac4..c49a4597 100644
--- a/Providers/FreeSql.Provider.MySql/Curd/MySqlInsert.cs
+++ b/Providers/FreeSql.Provider.MySql/Curd/MySqlInsert.cs
@@ -1,7 +1,9 @@
using FreeSql.Internal;
+using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Data;
+using System.Data.Common;
using System.Text;
using System.Threading.Tasks;
@@ -15,6 +17,17 @@ namespace FreeSql.MySql.Curd
{
}
+ internal IFreeSql InternalOrm => _orm;
+ internal TableInfo InternalTable => _table;
+ internal DbParameter[] InternalParams => _params;
+ internal DbConnection InternalConnection => _connection;
+ internal DbTransaction InternalTransaction => _transaction;
+ internal CommonUtils InternalCommonUtils => _commonUtils;
+ internal CommonExpression InternalCommonExpression => _commonExpression;
+ internal List InternalSource => _source;
+ internal Dictionary InternalIgnore => _ignore;
+ internal void InternalClearData() => ClearData();
+
public override int ExecuteAffrows() => base.SplitExecuteAffrows(5000, 3000);
public override long ExecuteIdentity() => base.SplitExecuteIdentity(5000, 3000);
public override List ExecuteInserted() => base.SplitExecuteInserted(5000, 3000);
diff --git a/Providers/FreeSql.Provider.MySql/Curd/MySqlUpdate.cs b/Providers/FreeSql.Provider.MySql/Curd/MySqlUpdate.cs
index dff4be5c..97e17653 100644
--- a/Providers/FreeSql.Provider.MySql/Curd/MySqlUpdate.cs
+++ b/Providers/FreeSql.Provider.MySql/Curd/MySqlUpdate.cs
@@ -18,6 +18,12 @@ namespace FreeSql.MySql.Curd
{
}
+ internal StringBuilder InternalSbSet => _set;
+ internal StringBuilder InternalSbSetIncr => _setIncr;
+ internal Dictionary InternalIgnore => _ignore;
+ internal void InternalResetSource(List source) => _source = source;
+ internal string InternalWhereCaseSource(string CsName, Func thenValue) => WhereCaseSource(CsName, thenValue);
+
public override int ExecuteAffrows() => base.SplitExecuteAffrows(500, 3000);
public override List ExecuteUpdated() => base.SplitExecuteUpdated(500, 3000);
diff --git a/Providers/FreeSql.Provider.MySql/Curd/OnDuplicateKeyUpdate.cs b/Providers/FreeSql.Provider.MySql/Curd/OnDuplicateKeyUpdate.cs
new file mode 100644
index 00000000..6b67e18d
--- /dev/null
+++ b/Providers/FreeSql.Provider.MySql/Curd/OnDuplicateKeyUpdate.cs
@@ -0,0 +1,167 @@
+using FreeSql.Aop;
+using FreeSql.Internal;
+using FreeSql.Internal.Model;
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Data.Common;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FreeSql.MySql.Curd
+{
+ public class OnDuplicateKeyUpdate where T1 : class
+ {
+ internal MySqlInsert _mysqlInsert;
+ internal MySqlUpdate _mysqlUpdatePriv;
+ internal MySqlUpdate _mysqlUpdate => _mysqlUpdatePriv ?? (_mysqlUpdatePriv = new MySqlUpdate(_mysqlInsert.InternalOrm, _mysqlInsert.InternalCommonUtils, _mysqlInsert.InternalCommonExpression, null).NoneParameter().SetSource(_mysqlInsert.InternalSource) as MySqlUpdate);
+
+ public OnDuplicateKeyUpdate(IInsert insert)
+ {
+ _mysqlInsert = insert as MySqlInsert;
+ if (_mysqlInsert == null) throw new Exception("OnDuplicateKeyUpdate 是 FreeSql.Provider.MySql/FreeSql.Provider.MySqlConnector 特有的功能");
+ }
+
+ protected void ClearData()
+ {
+ _mysqlInsert.InternalClearData();
+ _mysqlUpdatePriv = null;
+ }
+
+ public OnDuplicateKeyUpdate IgnoreColumns(Expression> columns)
+ {
+ _mysqlUpdate.IgnoreColumns(columns);
+ return this;
+ }
+ public OnDuplicateKeyUpdate UpdateColumns(Expression> columns)
+ {
+ _mysqlUpdate.UpdateColumns(columns);
+ return this;
+ }
+ public OnDuplicateKeyUpdate IgnoreColumns(string[] columns)
+ {
+ _mysqlUpdate.IgnoreColumns(columns);
+ return this;
+ }
+ public OnDuplicateKeyUpdate UpdateColumns(string[] columns)
+ {
+ _mysqlUpdate.UpdateColumns(columns);
+ return this;
+ }
+
+ public OnDuplicateKeyUpdate Set(Expression> column, TMember value)
+ {
+ _mysqlUpdate.Set(column, value);
+ return this;
+ }
+ public OnDuplicateKeyUpdate Set(Expression> exp)
+ {
+ _mysqlUpdate.Set(exp);
+ return this;
+ }
+ public OnDuplicateKeyUpdate SetRaw(string sql)
+ {
+ _mysqlUpdate.SetRaw(sql);
+ return this;
+ }
+
+ public string ToSql()
+ {
+ var sb = new StringBuilder();
+ sb.Append(_mysqlInsert.ToSql()).Append("\r\nON DUPLICATE KEY UPDATE\r\n");
+
+ var sbSetEmpty = _mysqlUpdate.InternalSbSet.Length == 0;
+ var sbSetIncrEmpty = _mysqlUpdate.InternalSbSetIncr.Length == 0;
+ if (sbSetEmpty == false || sbSetIncrEmpty == false)
+ {
+ if (sbSetEmpty == false) sb.Append(_mysqlUpdate.InternalSbSet.ToString().Substring(2));
+ if (sbSetIncrEmpty == false) sb.Append(sbSetEmpty ? _mysqlUpdate.InternalSbSetIncr.ToString().Substring(2) : _mysqlUpdate.InternalSbSetIncr.ToString());
+ }
+ else
+ {
+ var colidx = 0;
+ foreach (var col in _mysqlInsert.InternalTable.Columns.Values)
+ {
+ if (col.Attribute.IsPrimary || _mysqlUpdate.InternalIgnore.ContainsKey(col.Attribute.Name)) continue;
+
+ if (colidx > 0) sb.Append(", \r\n");
+
+ if (col.Attribute.IsVersion == true)
+ {
+ var field = _mysqlInsert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name);
+ sb.Append(field).Append(" = ").Append(field).Append(" + 1");
+ }
+ else if (_mysqlInsert.InternalIgnore.ContainsKey(col.Attribute.Name))
+ sb.Append(_mysqlUpdate.InternalWhereCaseSource(col.CsName, sqlval => sqlval).Trim());
+ else
+ {
+ var field = _mysqlInsert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name);
+ sb.Append(field).Append(" = VALUES(").Append(field).Append(")");
+ }
+ ++colidx;
+ }
+ }
+
+ return sb.ToString();
+ }
+
+ public long ExecuteAffrows()
+ {
+ var sql = this.ToSql();
+ if (string.IsNullOrEmpty(sql)) return 0;
+
+ var before = new CurdBeforeEventArgs(_mysqlInsert.InternalTable.Type, _mysqlInsert.InternalTable, CurdType.Insert, sql, _mysqlInsert.InternalParams);
+ _mysqlInsert.InternalOrm.Aop.CurdBefore?.Invoke(_mysqlInsert, before);
+ long ret = 0;
+ Exception exception = null;
+ try
+ {
+ ret = _mysqlInsert.InternalOrm.Ado.ExecuteNonQuery(_mysqlInsert.InternalConnection, _mysqlInsert.InternalTransaction, CommandType.Text, sql, _mysqlInsert.InternalParams);
+ }
+ catch (Exception ex)
+ {
+ exception = ex;
+ throw ex;
+ }
+ finally
+ {
+ var after = new CurdAfterEventArgs(before, exception, ret);
+ _mysqlInsert.InternalOrm.Aop.CurdAfter?.Invoke(_mysqlInsert, after);
+ ClearData();
+ }
+ return ret;
+ }
+
+#if net40
+#else
+ async public Task ExecuteAffrowsAsync()
+ {
+ var sql = this.ToSql();
+ if (string.IsNullOrEmpty(sql)) return 0;
+
+ var before = new CurdBeforeEventArgs(_mysqlInsert.InternalTable.Type, _mysqlInsert.InternalTable, CurdType.Insert, sql, _mysqlInsert.InternalParams);
+ _mysqlInsert.InternalOrm.Aop.CurdBefore?.Invoke(_mysqlInsert, before);
+ long ret = 0;
+ Exception exception = null;
+ try
+ {
+ ret = await _mysqlInsert.InternalOrm.Ado.ExecuteNonQueryAsync(_mysqlInsert.InternalConnection, _mysqlInsert.InternalTransaction, CommandType.Text, sql, _mysqlInsert.InternalParams);
+ }
+ catch (Exception ex)
+ {
+ exception = ex;
+ throw ex;
+ }
+ finally
+ {
+ var after = new CurdAfterEventArgs(before, exception, ret);
+ _mysqlInsert.InternalOrm.Aop.CurdAfter?.Invoke(_mysqlInsert, after);
+ ClearData();
+ }
+ return ret;
+ }
+#endif
+ }
+}
diff --git a/Providers/FreeSql.Provider.MySql/MySqlExtensions.cs b/Providers/FreeSql.Provider.MySql/MySqlExtensions.cs
index a08d689d..262aa716 100644
--- a/Providers/FreeSql.Provider.MySql/MySqlExtensions.cs
+++ b/Providers/FreeSql.Provider.MySql/MySqlExtensions.cs
@@ -1,4 +1,7 @@
-public static partial class FreeSqlMySqlGlobalExtensions
+using FreeSql;
+using FreeSql.MySql.Curd;
+
+public static partial class FreeSqlMySqlGlobalExtensions
{
///
@@ -9,4 +12,14 @@
///
public static string FormatMySql(this string that, params object[] args) => _mysqlAdo.Addslashes(that, args);
static FreeSql.MySql.MySqlAdo _mysqlAdo = new FreeSql.MySql.MySqlAdo();
+
+ ///
+ /// MySql 特有的功能,On Duplicate Key Update
+ /// 注意:此功能会开启插入【自增列】
+ ///
+ ///
+ ///
+ ///
+ public static OnDuplicateKeyUpdate OnDuplicateKeyUpdate(this IInsert that) where T1 : class => new FreeSql.MySql.Curd.OnDuplicateKeyUpdate(that.InsertIdentity());
+
}
diff --git a/Providers/FreeSql.Provider.Odbc/Oracle/Curd/OdbcOracleInsert.cs b/Providers/FreeSql.Provider.Odbc/Oracle/Curd/OdbcOracleInsert.cs
index 0405c439..9b542be3 100644
--- a/Providers/FreeSql.Provider.Odbc/Oracle/Curd/OdbcOracleInsert.cs
+++ b/Providers/FreeSql.Provider.Odbc/Oracle/Curd/OdbcOracleInsert.cs
@@ -37,8 +37,8 @@ namespace FreeSql.Odbc.Oracle
foreach (var col in _table.Columns.Values)
{
if (col.Attribute.IsIdentity) _identCol = col;
- if (_ignore.ContainsKey(col.Attribute.Name)) continue;
if (col.Attribute.IsIdentity && _insertIdentity == false) continue;
+ if (col.Attribute.IsIdentity == false && _ignore.ContainsKey(col.Attribute.Name)) continue;
if (colidx > 0) sbtb.Append(", ");
sbtb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name));
@@ -58,8 +58,8 @@ namespace FreeSql.Odbc.Oracle
var colidx2 = 0;
foreach (var col in _table.Columns.Values)
{
- if (_ignore.ContainsKey(col.Attribute.Name)) continue;
if (col.Attribute.IsIdentity && _insertIdentity == false) continue;
+ if (col.Attribute.IsIdentity == false && _ignore.ContainsKey(col.Attribute.Name)) continue;
if (colidx2 > 0) sb.Append(", ");
object val = col.GetMapValue(d);
diff --git a/Providers/FreeSql.Provider.Oracle/Curd/OracleInsert.cs b/Providers/FreeSql.Provider.Oracle/Curd/OracleInsert.cs
index 8585da3e..e1d632ca 100644
--- a/Providers/FreeSql.Provider.Oracle/Curd/OracleInsert.cs
+++ b/Providers/FreeSql.Provider.Oracle/Curd/OracleInsert.cs
@@ -39,8 +39,8 @@ namespace FreeSql.Oracle.Curd
foreach (var col in _table.Columns.Values)
{
if (col.Attribute.IsIdentity) _identCol = col;
- if (_ignore.ContainsKey(col.Attribute.Name)) continue;
if (col.Attribute.IsIdentity && _insertIdentity == false) continue;
+ if (col.Attribute.IsIdentity == false && _ignore.ContainsKey(col.Attribute.Name)) continue;
if (colidx > 0) sbtb.Append(", ");
sbtb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name));
@@ -60,8 +60,8 @@ namespace FreeSql.Oracle.Curd
var colidx2 = 0;
foreach (var col in _table.Columns.Values)
{
- if (_ignore.ContainsKey(col.Attribute.Name)) continue;
if (col.Attribute.IsIdentity && _insertIdentity == false) continue;
+ if (col.Attribute.IsIdentity == false && _ignore.ContainsKey(col.Attribute.Name)) continue;
if (colidx2 > 0) sb.Append(", ");
object val = col.GetMapValue(d);