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);