mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 09:15:27 +08:00 
			
		
		
		
	- 增加 PostgreSQL 特有功能 On Conflict Do Update 功能;
This commit is contained in:
		@@ -99,7 +99,7 @@
 | 
				
			|||||||
            总分
 | 
					            总分
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="P:FreeSql.Tests.UnitTest2.SysModulePermission.SysModulePermissionId">
 | 
					        <member name="P:FreeSql.Tests.UnitTest2.SysModulePermission.Id">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            菜单权限ID
 | 
					            菜单权限ID
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
@@ -119,7 +119,7 @@
 | 
				
			|||||||
            菜单权限
 | 
					            菜单权限
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="P:FreeSql.Tests.UnitTest2.SysModule.SysModuleId">
 | 
					        <member name="P:FreeSql.Tests.UnitTest2.SysModule.Id">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            主键
 | 
					            主键
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
@@ -164,7 +164,7 @@
 | 
				
			|||||||
            创建日期
 | 
					            创建日期
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="P:FreeSql.Tests.UnitTest2.SysModuleButton.SysModuleButtonId">
 | 
					        <member name="P:FreeSql.Tests.UnitTest2.SysModuleButton.Id">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            按钮主键
 | 
					            按钮主键
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,201 @@
 | 
				
			|||||||
 | 
					using FreeSql.DataAnnotations;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Tests.PostgreSQL
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class OnConflictDoUpdateTest
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        class TestOnConflictDoUpdateInfo
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            [Column(IsIdentity = true)]
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string title { get; set; }
 | 
				
			||||||
 | 
					            public DateTime? time { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void ExecuteAffrows()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            g.pgsql.Delete<TestOnConflictDoUpdateInfo>(new[] { 100, 101, 102 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					            var odku1 = g.pgsql.Insert(new TestOnConflictDoUpdateInfo { id = 100, title = "title-100", time = DateTime.Parse("2000-01-01") }).NoneParameter().OnConflictDoUpdate();
 | 
				
			||||||
 | 
					            Assert.Equal(odku1.ToSql(), @"INSERT INTO ""testonconflictdoupdateinfo"" AS _ftb_ (""id"", ""title"", ""time"") VALUES(100, 'title-100', '2000-01-01 00:00:00.000000')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""title"" = EXCLUDED.""title"", 
 | 
				
			||||||
 | 
					""time"" = EXCLUDED.""time""");
 | 
				
			||||||
 | 
					            Assert.Equal(1, odku1.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var odku2 = g.pgsql.Insert(new[] {
 | 
				
			||||||
 | 
					                new TestOnConflictDoUpdateInfo { id = 100, title = "title-100", time = DateTime.Parse("2000-01-01") },
 | 
				
			||||||
 | 
					                new TestOnConflictDoUpdateInfo { id = 101, title = "title-101", time = DateTime.Parse("2000-01-01") },
 | 
				
			||||||
 | 
					                new TestOnConflictDoUpdateInfo { id = 102, title = "title-102", time = DateTime.Parse("2000-01-01") }
 | 
				
			||||||
 | 
					            }).NoneParameter().OnConflictDoUpdate();
 | 
				
			||||||
 | 
					            Assert.Equal(odku2.ToSql(), @"INSERT INTO ""testonconflictdoupdateinfo"" AS _ftb_ (""id"", ""title"", ""time"") VALUES(100, 'title-100', '2000-01-01 00:00:00.000000'), (101, 'title-101', '2000-01-01 00:00:00.000000'), (102, 'title-102', '2000-01-01 00:00:00.000000')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""title"" = EXCLUDED.""title"", 
 | 
				
			||||||
 | 
					""time"" = EXCLUDED.""time""");
 | 
				
			||||||
 | 
					            odku2.ExecuteAffrows();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void IgnoreColumns()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            g.pgsql.Delete<TestOnConflictDoUpdateInfo>(new[] { 200, 201, 202 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					            var odku1 = g.pgsql.Insert(new TestOnConflictDoUpdateInfo { id = 200, title = "title-200", time = DateTime.Parse("2000-01-01") }).IgnoreColumns(a => a.time).NoneParameter().OnConflictDoUpdate();
 | 
				
			||||||
 | 
					            Assert.Equal(odku1.ToSql(), @"INSERT INTO ""testonconflictdoupdateinfo"" AS _ftb_ (""id"", ""title"") VALUES(200, 'title-200')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""title"" = EXCLUDED.""title"", 
 | 
				
			||||||
 | 
					""time"" = '2000-01-01 00:00:00.000000'");
 | 
				
			||||||
 | 
					            Assert.Equal(1, odku1.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var odku2 = g.pgsql.Insert(new[] {
 | 
				
			||||||
 | 
					                new TestOnConflictDoUpdateInfo { id = 200, title = "title-200", time = DateTime.Parse("2000-01-01") },
 | 
				
			||||||
 | 
					                new TestOnConflictDoUpdateInfo { id = 201, title = "title-201", time = DateTime.Parse("2000-01-01") },
 | 
				
			||||||
 | 
					                new TestOnConflictDoUpdateInfo { id = 202, title = "title-202", time = DateTime.Parse("2000-01-01") }
 | 
				
			||||||
 | 
					            }).IgnoreColumns(a => a.time).NoneParameter().OnConflictDoUpdate();
 | 
				
			||||||
 | 
					            Assert.Equal(odku2.ToSql(), @"INSERT INTO ""testonconflictdoupdateinfo"" AS _ftb_ (""id"", ""title"") VALUES(200, 'title-200'), (201, 'title-201'), (202, 'title-202')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""title"" = EXCLUDED.""title"", 
 | 
				
			||||||
 | 
					""time"" = CASE EXCLUDED.""id"" 
 | 
				
			||||||
 | 
					WHEN 200 THEN '2000-01-01 00:00:00.000000' 
 | 
				
			||||||
 | 
					WHEN 201 THEN '2000-01-01 00:00:00.000000' 
 | 
				
			||||||
 | 
					WHEN 202 THEN '2000-01-01 00:00:00.000000' END::timestamp");
 | 
				
			||||||
 | 
					            odku2.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            g.pgsql.Delete<TestOnConflictDoUpdateInfo>(new[] { 200, 201, 202 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					            odku1 = g.pgsql.Insert(new TestOnConflictDoUpdateInfo { id = 200, title = "title-200", time = DateTime.Parse("2000-01-01") }).IgnoreColumns(a => a.time).NoneParameter().OnConflictDoUpdate().IgnoreColumns(a => a.title);
 | 
				
			||||||
 | 
					            Assert.Equal(odku1.ToSql(), @"INSERT INTO ""testonconflictdoupdateinfo"" AS _ftb_ (""id"", ""title"") VALUES(200, 'title-200')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""time"" = '2000-01-01 00:00:00.000000'");
 | 
				
			||||||
 | 
					            Assert.Equal(1, odku1.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            odku2 = g.pgsql.Insert(new[] {
 | 
				
			||||||
 | 
					                new TestOnConflictDoUpdateInfo { id = 200, title = "title-200", time = DateTime.Parse("2000-01-01") },
 | 
				
			||||||
 | 
					                new TestOnConflictDoUpdateInfo { id = 201, title = "title-201", time = DateTime.Parse("2000-01-01") },
 | 
				
			||||||
 | 
					                new TestOnConflictDoUpdateInfo { id = 202, title = "title-202", time = DateTime.Parse("2000-01-01") }
 | 
				
			||||||
 | 
					            }).IgnoreColumns(a => a.time).NoneParameter().OnConflictDoUpdate().IgnoreColumns(a => a.title);
 | 
				
			||||||
 | 
					            Assert.Equal(odku2.ToSql(), @"INSERT INTO ""testonconflictdoupdateinfo"" AS _ftb_ (""id"", ""title"") VALUES(200, 'title-200'), (201, 'title-201'), (202, 'title-202')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""time"" = CASE EXCLUDED.""id"" 
 | 
				
			||||||
 | 
					WHEN 200 THEN '2000-01-01 00:00:00.000000' 
 | 
				
			||||||
 | 
					WHEN 201 THEN '2000-01-01 00:00:00.000000' 
 | 
				
			||||||
 | 
					WHEN 202 THEN '2000-01-01 00:00:00.000000' END::timestamp");
 | 
				
			||||||
 | 
					            odku2.ExecuteAffrows();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void UpdateColumns()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            g.pgsql.Delete<TestOnConflictDoUpdateInfo>(new[] { 300, 301, 302 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					            var odku1 = g.pgsql.Insert(new TestOnConflictDoUpdateInfo { id = 300, title = "title-300", time = DateTime.Parse("2000-01-01") }).InsertColumns(a => a.title).NoneParameter().OnConflictDoUpdate();
 | 
				
			||||||
 | 
					            Assert.Equal(odku1.ToSql(), @"INSERT INTO ""testonconflictdoupdateinfo"" AS _ftb_ (""id"", ""title"") VALUES(300, 'title-300')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""title"" = EXCLUDED.""title"", 
 | 
				
			||||||
 | 
					""time"" = '2000-01-01 00:00:00.000000'");
 | 
				
			||||||
 | 
					            Assert.Equal(1, odku1.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var odku2 = g.pgsql.Insert(new[] {
 | 
				
			||||||
 | 
					                new TestOnConflictDoUpdateInfo { id = 300, title = "title-300", time = DateTime.Parse("2000-01-01") },
 | 
				
			||||||
 | 
					                new TestOnConflictDoUpdateInfo { id = 301, title = "title-301", time = DateTime.Parse("2000-01-01") },
 | 
				
			||||||
 | 
					                new TestOnConflictDoUpdateInfo { id = 302, title = "title-302", time = DateTime.Parse("2000-01-01") }
 | 
				
			||||||
 | 
					            }).InsertColumns(a => a.title).NoneParameter().OnConflictDoUpdate();
 | 
				
			||||||
 | 
					            Assert.Equal(odku2.ToSql(), @"INSERT INTO ""testonconflictdoupdateinfo"" AS _ftb_ (""id"", ""title"") VALUES(300, 'title-300'), (301, 'title-301'), (302, 'title-302')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""title"" = EXCLUDED.""title"", 
 | 
				
			||||||
 | 
					""time"" = CASE EXCLUDED.""id"" 
 | 
				
			||||||
 | 
					WHEN 300 THEN '2000-01-01 00:00:00.000000' 
 | 
				
			||||||
 | 
					WHEN 301 THEN '2000-01-01 00:00:00.000000' 
 | 
				
			||||||
 | 
					WHEN 302 THEN '2000-01-01 00:00:00.000000' END::timestamp");
 | 
				
			||||||
 | 
					            odku2.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            g.pgsql.Delete<TestOnConflictDoUpdateInfo>(new[] { 300, 301, 302 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					            odku1 = g.pgsql.Insert(new TestOnConflictDoUpdateInfo { id = 300, title = "title-300", time = DateTime.Parse("2000-01-01") }).InsertColumns(a => a.title).NoneParameter().OnConflictDoUpdate().UpdateColumns(a => a.time);
 | 
				
			||||||
 | 
					            Assert.Equal(odku1.ToSql(), @"INSERT INTO ""testonconflictdoupdateinfo"" AS _ftb_ (""id"", ""title"") VALUES(300, 'title-300')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""time"" = '2000-01-01 00:00:00.000000'");
 | 
				
			||||||
 | 
					            Assert.Equal(1, odku1.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            odku2 = g.pgsql.Insert(new[] {
 | 
				
			||||||
 | 
					                new TestOnConflictDoUpdateInfo { id = 300, title = "title-300", time = DateTime.Parse("2000-01-01") },
 | 
				
			||||||
 | 
					                new TestOnConflictDoUpdateInfo { id = 301, title = "title-301", time = DateTime.Parse("2000-01-01") },
 | 
				
			||||||
 | 
					                new TestOnConflictDoUpdateInfo { id = 302, title = "title-302", time = DateTime.Parse("2000-01-01") }
 | 
				
			||||||
 | 
					            }).InsertColumns(a => a.title).NoneParameter().OnConflictDoUpdate().UpdateColumns(a => a.time);
 | 
				
			||||||
 | 
					            Assert.Equal(odku2.ToSql(), @"INSERT INTO ""testonconflictdoupdateinfo"" AS _ftb_ (""id"", ""title"") VALUES(300, 'title-300'), (301, 'title-301'), (302, 'title-302')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""time"" = CASE EXCLUDED.""id"" 
 | 
				
			||||||
 | 
					WHEN 300 THEN '2000-01-01 00:00:00.000000' 
 | 
				
			||||||
 | 
					WHEN 301 THEN '2000-01-01 00:00:00.000000' 
 | 
				
			||||||
 | 
					WHEN 302 THEN '2000-01-01 00:00:00.000000' END::timestamp");
 | 
				
			||||||
 | 
					            odku2.ExecuteAffrows();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void Set()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            g.pgsql.Delete<TestOnConflictDoUpdateInfo>(new[] { 400, 401, 402 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					            var odku1 = g.pgsql.Insert(new TestOnConflictDoUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") }).NoneParameter().OnConflictDoUpdate().Set(a => a.time, DateTime.Parse("2020-1-1"));
 | 
				
			||||||
 | 
					            Assert.Equal(odku1.ToSql(), @"INSERT INTO ""testonconflictdoupdateinfo"" AS _ftb_ (""id"", ""title"", ""time"") VALUES(400, 'title-400', '2000-01-01 00:00:00.000000')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""time"" = '2020-01-01 00:00:00.000000'");
 | 
				
			||||||
 | 
					            Assert.Equal(1, odku1.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var odku2 = g.pgsql.Insert(new[] {
 | 
				
			||||||
 | 
					                new TestOnConflictDoUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") },
 | 
				
			||||||
 | 
					                new TestOnConflictDoUpdateInfo { id = 401, title = "title-401", time = DateTime.Parse("2000-01-01") },
 | 
				
			||||||
 | 
					                new TestOnConflictDoUpdateInfo { id = 402, title = "title-402", time = DateTime.Parse("2000-01-01") }
 | 
				
			||||||
 | 
					            }).NoneParameter().OnConflictDoUpdate().Set(a => a.time, DateTime.Parse("2020-1-1"));
 | 
				
			||||||
 | 
					            Assert.Equal(odku2.ToSql(), @"INSERT INTO ""testonconflictdoupdateinfo"" AS _ftb_ (""id"", ""title"", ""time"") VALUES(400, 'title-400', '2000-01-01 00:00:00.000000'), (401, 'title-401', '2000-01-01 00:00:00.000000'), (402, 'title-402', '2000-01-01 00:00:00.000000')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""time"" = '2020-01-01 00:00:00.000000'");
 | 
				
			||||||
 | 
					            odku2.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//            var dt2020 = DateTime.Parse("2020-1-1");
 | 
				
			||||||
 | 
					//            g.pgsql.Delete<TestOnConflictDoUpdateInfo>(new[] { 400, 401, 402 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					//            odku1 = g.pgsql.Insert(new TestOnConflictDoUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") }).NoneParameter().OnConflictDoUpdate().Set(a => a.time == dt2020);
 | 
				
			||||||
 | 
					//            Assert.Equal(odku1.ToSql(), @"INSERT INTO ""testonconflictdoupdateinfo"" AS _ftb_ (""id"", ""title"", ""time"") VALUES(400, 'title-400', '2000-01-01 00:00:00.000000')
 | 
				
			||||||
 | 
					//ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					//""time"" = '2020-01-01 00:00:00.000000'");
 | 
				
			||||||
 | 
					//            Assert.Equal(1, odku1.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//            odku2 = g.pgsql.Insert(new[] {
 | 
				
			||||||
 | 
					//                new TestOnConflictDoUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") },
 | 
				
			||||||
 | 
					//                new TestOnConflictDoUpdateInfo { id = 401, title = "title-401", time = DateTime.Parse("2000-01-01") },
 | 
				
			||||||
 | 
					//                new TestOnConflictDoUpdateInfo { id = 402, title = "title-402", time = DateTime.Parse("2000-01-01") }
 | 
				
			||||||
 | 
					//            }).NoneParameter().OnConflictDoUpdate().Set(a => a.time == dt2020);
 | 
				
			||||||
 | 
					//            Assert.Equal(odku2.ToSql(), @"INSERT INTO ""testonconflictdoupdateinfo"" AS _ftb_ (""id"", ""title"", ""time"") VALUES(400, 'title-400', '2000-01-01 00:00:00.000000'), (401, 'title-401', '2000-01-01 00:00:00.000000'), (402, 'title-402', '2000-01-01 00:00:00.000000')
 | 
				
			||||||
 | 
					//ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					//""time"" = '2020-01-01 00:00:00.000000'");
 | 
				
			||||||
 | 
					//            odku2.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//            g.pgsql.Delete<TestOnConflictDoUpdateInfo>(new[] { 400, 401, 402 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					//            odku1 = g.pgsql.Insert(new TestOnConflictDoUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") }).NoneParameter().OnConflictDoUpdate().Set(a => new { time = dt2020, title = a.title + "123" });
 | 
				
			||||||
 | 
					//            Assert.Equal(odku1.ToSql(), @"INSERT INTO ""testonconflictdoupdateinfo"" AS _ftb_ (""id"", ""title"", ""time"") VALUES(400, 'title-400', '2000-01-01 00:00:00.000000')
 | 
				
			||||||
 | 
					//ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					//""time"" = '2020-01-01 00:00:00.000000', ""title"" = _ftb_.""title"" || '123'");
 | 
				
			||||||
 | 
					//            Assert.Equal(1, odku1.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//            odku2 = g.pgsql.Insert(new[] {
 | 
				
			||||||
 | 
					//                new TestOnConflictDoUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") },
 | 
				
			||||||
 | 
					//                new TestOnConflictDoUpdateInfo { id = 401, title = "title-401", time = DateTime.Parse("2000-01-01") },
 | 
				
			||||||
 | 
					//                new TestOnConflictDoUpdateInfo { id = 402, title = "title-402", time = DateTime.Parse("2000-01-01") }
 | 
				
			||||||
 | 
					//            }).NoneParameter().OnConflictDoUpdate().Set(a => new { time = dt2020, title = a.title + "123" });
 | 
				
			||||||
 | 
					//            Assert.Equal(odku2.ToSql(), @"INSERT INTO ""testonconflictdoupdateinfo"" AS _ftb_ (""id"", ""title"", ""time"") VALUES(400, 'title-400', '2000-01-01 00:00:00.000000'), (401, 'title-401', '2000-01-01 00:00:00.000000'), (402, 'title-402', '2000-01-01 00:00:00.000000')
 | 
				
			||||||
 | 
					//ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					//""time"" = '2020-01-01 00:00:00.000000', ""title"" = _ftb_.""title"" || '123'");
 | 
				
			||||||
 | 
					//            odku2.ExecuteAffrows();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void SetRaw()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -427,6 +427,10 @@ namespace FreeSql.Tests
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void Test1()
 | 
					        public void Test1()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            g.sqlite.Update<Model1>(1).NoneParameter().Set(a => a.title, null).ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var testExNewRet1 = g.sqlite.Delete<TestAddEnumEx>().Where("1=1").ExecuteAffrows();
 | 
					            var testExNewRet1 = g.sqlite.Delete<TestAddEnumEx>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
            var testExNewRet2 = g.sqlite.Insert<TestAddEnumEx>(new TestAddEnumEx { Id = 1, Type = TestAddEnumType.中国人 }).ExecuteAffrows();
 | 
					            var testExNewRet2 = g.sqlite.Insert<TestAddEnumEx>(new TestAddEnumEx { Id = 1, Type = TestAddEnumType.中国人 }).ExecuteAffrows();
 | 
				
			||||||
            var testExNewRet3 = g.sqlite.Insert<TestAddEnumEx>(new TestAddEnumEx { Id = 2, Type = TestAddEnumType.日本人 }).ExecuteAffrows();
 | 
					            var testExNewRet3 = g.sqlite.Insert<TestAddEnumEx>(new TestAddEnumEx { Id = 2, Type = TestAddEnumType.日本人 }).ExecuteAffrows();
 | 
				
			||||||
@@ -858,8 +862,6 @@ namespace FreeSql.Tests
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            var ttt1 = g.sqlite.Select<Model1>().Where(a => a.Childs.AsSelect().Any(b => b.Title == "111")).ToList();
 | 
					            var ttt1 = g.sqlite.Select<Model1>().Where(a => a.Childs.AsSelect().Any(b => b.Title == "111")).ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,7 +21,8 @@ namespace FreeSql.Tests
 | 
				
			|||||||
            /// <summary>
 | 
					            /// <summary>
 | 
				
			||||||
            /// 菜单权限ID
 | 
					            /// 菜单权限ID
 | 
				
			||||||
            /// </summary>
 | 
					            /// </summary>
 | 
				
			||||||
            [Column(IsPrimary = true)] public String SysModulePermissionId { get; set; }
 | 
					            [Column(IsPrimary = true, OldName = "SysModulePermissionId")] 
 | 
				
			||||||
 | 
					            public String Id { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            /// <summary>
 | 
					            /// <summary>
 | 
				
			||||||
            /// 菜单主键ID
 | 
					            /// 菜单主键ID
 | 
				
			||||||
@@ -43,8 +44,8 @@ namespace FreeSql.Tests
 | 
				
			|||||||
            /// <summary>
 | 
					            /// <summary>
 | 
				
			||||||
            /// 主键
 | 
					            /// 主键
 | 
				
			||||||
            /// </summary>
 | 
					            /// </summary>
 | 
				
			||||||
            [Column(IsPrimary = true)]
 | 
					            [Column(IsPrimary = true, OldName = "SysModuleId")]
 | 
				
			||||||
            public String SysModuleId { get; set; }
 | 
					            public String Id { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            /// <summary>
 | 
					            /// <summary>
 | 
				
			||||||
            /// 父级ID
 | 
					            /// 父级ID
 | 
				
			||||||
@@ -92,8 +93,8 @@ namespace FreeSql.Tests
 | 
				
			|||||||
            /// <summary>
 | 
					            /// <summary>
 | 
				
			||||||
            /// 按钮主键
 | 
					            /// 按钮主键
 | 
				
			||||||
            /// </summary>
 | 
					            /// </summary>
 | 
				
			||||||
            [Column(IsPrimary = true)]
 | 
					            [Column(IsPrimary = true, OldName = "SysModuleButtonId")]
 | 
				
			||||||
            public String SysModuleButtonId { get; set; }
 | 
					            public String Id { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            /// <summary>
 | 
					            /// <summary>
 | 
				
			||||||
            /// 名称
 | 
					            /// 名称
 | 
				
			||||||
@@ -127,10 +128,12 @@ namespace FreeSql.Tests
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        partial class SysModulePermission
 | 
					        partial class SysModulePermission
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            [Navigate("SysModuleButtonId")]
 | 
				
			||||||
            public SysModuleButton Button { get; set; }
 | 
					            public SysModuleButton Button { get; set; }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        partial class SysModule
 | 
					        partial class SysModule
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            [Navigate("SysModuleId")]
 | 
				
			||||||
            public List<SysModulePermission> Permissions { get; set; }
 | 
					            public List<SysModulePermission> Permissions { get; set; }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        partial class SysModuleButton
 | 
					        partial class SysModuleButton
 | 
				
			||||||
@@ -164,10 +167,25 @@ namespace FreeSql.Tests
 | 
				
			|||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void Test02()
 | 
					        public void Test02()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            var list111 = g.sqlite.Select<SysModule>()
 | 
				
			||||||
 | 
					               .Page(1, 10)
 | 
				
			||||||
 | 
					               .ToList(a => new { Id = a.Id })
 | 
				
			||||||
 | 
					               .Select(a => new SysModule { Id = a.Id }).ToList()
 | 
				
			||||||
 | 
					               .IncludeMany(g.sqlite, a => a.Permissions, then => then.Include(a => a.Button));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var list222 = g.sqlite.Select<SysModule>()
 | 
				
			||||||
 | 
					                .IncludeMany(m => m.Permissions, then => then.Include(a => a.Button))
 | 
				
			||||||
 | 
					                .Page(1, 10)
 | 
				
			||||||
 | 
					                .ToList();
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
            var comments1 = g.mysql.Select<Comment, UserLike>()
 | 
					            var comments1 = g.mysql.Select<Comment, UserLike>()
 | 
				
			||||||
    .LeftJoin((a, b) => a.Id == b.SubjectId)
 | 
					                .LeftJoin((a, b) => a.Id == b.SubjectId)
 | 
				
			||||||
    .ToList((a, b) => new { comment = a, b.SubjectId, user = a.UserInfo });
 | 
					                .ToList((a, b) => new { comment = a, b.SubjectId, user = a.UserInfo });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var comments2 = g.mysql.Select<Comment>()
 | 
					            var comments2 = g.mysql.Select<Comment>()
 | 
				
			||||||
    .Include(r => r.UserInfo)
 | 
					    .Include(r => r.UserInfo)
 | 
				
			||||||
@@ -178,36 +196,32 @@ namespace FreeSql.Tests
 | 
				
			|||||||
            g.sqlite.Delete<SysModuleButton>().Where("1=1").ExecuteAffrows();
 | 
					            g.sqlite.Delete<SysModuleButton>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
            g.sqlite.Delete<SysModule>().Where("1=1").ExecuteAffrows();
 | 
					            g.sqlite.Delete<SysModule>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var menu1 = new SysModule { SysModuleId = "menu1", Name = "菜单1" };
 | 
					            var menu1 = new SysModule { Id = "menu1", Name = "菜单1" };
 | 
				
			||||||
            var menu2 = new SysModule { SysModuleId = "menu2", Name = "菜单2" };
 | 
					            var menu2 = new SysModule { Id = "menu2", Name = "菜单2" };
 | 
				
			||||||
            g.sqlite.Insert(new[] { menu1, menu2 }).ExecuteAffrows();
 | 
					            g.sqlite.Insert(new[] { menu1, menu2 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var button1 = new SysModuleButton { SysModuleButtonId = "button1", Name = "添加" };
 | 
					            var button1 = new SysModuleButton { Id = "button1", Name = "添加" };
 | 
				
			||||||
            var button2 = new SysModuleButton { SysModuleButtonId = "button2", Name = "修改" };
 | 
					            var button2 = new SysModuleButton { Id = "button2", Name = "修改" };
 | 
				
			||||||
            var button3 = new SysModuleButton { SysModuleButtonId = "button3", Name = "删除" };
 | 
					            var button3 = new SysModuleButton { Id = "button3", Name = "删除" };
 | 
				
			||||||
            var button4 = new SysModuleButton { SysModuleButtonId = "button4", Name = "查询" };
 | 
					            var button4 = new SysModuleButton { Id = "button4", Name = "查询" };
 | 
				
			||||||
            g.sqlite.Insert(new[] { button1, button2, button3, button4 }).ExecuteAffrows();
 | 
					            g.sqlite.Insert(new[] { button1, button2, button3, button4 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            g.sqlite.Insert(new[] {
 | 
					            g.sqlite.Insert(new[] {
 | 
				
			||||||
                new SysModulePermission { SysModulePermissionId = "menu1_button1", SysModuleId = menu1.SysModuleId, SysModuleButtonId = button1.SysModuleButtonId },
 | 
					                new SysModulePermission { Id = "menu1_button1", SysModuleId = menu1.Id, SysModuleButtonId = button1.Id },
 | 
				
			||||||
                new SysModulePermission { SysModulePermissionId = "menu1_button2", SysModuleId = menu1.SysModuleId, SysModuleButtonId = button2.SysModuleButtonId },
 | 
					                new SysModulePermission { Id = "menu1_button2", SysModuleId = menu1.Id, SysModuleButtonId = button2.Id },
 | 
				
			||||||
                new SysModulePermission { SysModulePermissionId = "menu1_button3", SysModuleId = menu1.SysModuleId, SysModuleButtonId = button3.SysModuleButtonId },
 | 
					                new SysModulePermission { Id = "menu1_button3", SysModuleId = menu1.Id, SysModuleButtonId = button3.Id },
 | 
				
			||||||
                new SysModulePermission { SysModulePermissionId = "menu1_button4", SysModuleId = menu1.SysModuleId, SysModuleButtonId = button4.SysModuleButtonId },
 | 
					                new SysModulePermission { Id = "menu1_button4", SysModuleId = menu1.Id, SysModuleButtonId = button4.Id },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                new SysModulePermission { SysModulePermissionId = "menu2_button1", SysModuleId = menu2.SysModuleId, SysModuleButtonId = button1.SysModuleButtonId },
 | 
					                new SysModulePermission { Id = "menu2_button1", SysModuleId = menu2.Id, SysModuleButtonId = button1.Id },
 | 
				
			||||||
                new SysModulePermission { SysModulePermissionId = "menu2_button2", SysModuleId = menu2.SysModuleId, SysModuleButtonId = button2.SysModuleButtonId },
 | 
					                new SysModulePermission { Id = "menu2_button2", SysModuleId = menu2.Id, SysModuleButtonId = button2.Id },
 | 
				
			||||||
                new SysModulePermission { SysModulePermissionId = "menu2_button3", SysModuleId = menu2.SysModuleId, SysModuleButtonId = button3.SysModuleButtonId },
 | 
					                new SysModulePermission { Id = "menu2_button3", SysModuleId = menu2.Id, SysModuleButtonId = button3.Id },
 | 
				
			||||||
                new SysModulePermission { SysModulePermissionId = "menu2_button4", SysModuleId = menu2.SysModuleId, SysModuleButtonId = button4.SysModuleButtonId },
 | 
					                new SysModulePermission { Id = "menu2_button4", SysModuleId = menu2.Id, SysModuleButtonId = button4.Id },
 | 
				
			||||||
            }).ExecuteAffrows();
 | 
					            }).ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            //var list = g.sqlite.Select<SysModule>()
 | 
					 | 
				
			||||||
            //   .IncludeMany(m => m.Buttons)
 | 
					 | 
				
			||||||
            //   .Page(1, 10)
 | 
					 | 
				
			||||||
            //   .ToList();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var list = g.sqlite.Select<SysModule>()
 | 
					            var list123123 = g.sqlite.Select<SysModule>()
 | 
				
			||||||
                .IncludeMany(m => m.Permissions.Where(p => p.SysModuleId == m.SysModuleId),
 | 
					                .IncludeMany(m => m.Permissions.Where(p => p.SysModuleId == m.Id),
 | 
				
			||||||
                    then => then.LeftJoin(p => p.Button.SysModuleButtonId == p.SysModuleButtonId))
 | 
					                    then => then.LeftJoin(p => p.Button.Id == p.SysModuleButtonId))
 | 
				
			||||||
                .ToList();
 | 
					                .ToList();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,7 @@ namespace FreeSql.MySql.Curd
 | 
				
			|||||||
        internal Dictionary<string, bool> InternalIgnore => _ignore;
 | 
					        internal Dictionary<string, bool> InternalIgnore => _ignore;
 | 
				
			||||||
        internal void InternalResetSource(List<T1> source) => _source = source;
 | 
					        internal void InternalResetSource(List<T1> source) => _source = source;
 | 
				
			||||||
        internal string InternalWhereCaseSource(string CsName, Func<string, string> thenValue) => WhereCaseSource(CsName, thenValue);
 | 
					        internal string InternalWhereCaseSource(string CsName, Func<string, string> thenValue) => WhereCaseSource(CsName, thenValue);
 | 
				
			||||||
 | 
					        internal void InternalToSqlCaseWhenEnd(StringBuilder sb, ColumnInfo col) => ToSqlCaseWhenEnd(sb, col);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public override int ExecuteAffrows() => base.SplitExecuteAffrows(500, 3000);
 | 
					        public override int ExecuteAffrows() => base.SplitExecuteAffrows(500, 3000);
 | 
				
			||||||
        public override List<T1> ExecuteUpdated() => base.SplitExecuteUpdated(500, 3000);
 | 
					        public override List<T1> ExecuteUpdated() => base.SplitExecuteUpdated(500, 3000);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -94,7 +94,11 @@ namespace FreeSql.MySql.Curd
 | 
				
			|||||||
                        sb.Append(field).Append(" = ").Append(field).Append(" + 1");
 | 
					                        sb.Append(field).Append(" = ").Append(field).Append(" + 1");
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    else if (_mysqlInsert.InternalIgnore.ContainsKey(col.Attribute.Name))
 | 
					                    else if (_mysqlInsert.InternalIgnore.ContainsKey(col.Attribute.Name))
 | 
				
			||||||
                        sb.Append(_mysqlUpdate.InternalWhereCaseSource(col.CsName, sqlval => sqlval).Trim());
 | 
					                    {
 | 
				
			||||||
 | 
					                        var caseWhen = _mysqlUpdate.InternalWhereCaseSource(col.CsName, sqlval => sqlval).Trim();
 | 
				
			||||||
 | 
					                        sb.Append(caseWhen);
 | 
				
			||||||
 | 
					                        if (caseWhen.EndsWith(" END")) _mysqlUpdate.InternalToSqlCaseWhenEnd(sb, col);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                    else
 | 
					                    else
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        var field = _mysqlInsert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name);
 | 
					                        var field = _mysqlInsert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										197
									
								
								Providers/FreeSql.Provider.PostgreSQL/Curd/OnConflictDoUpdate.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								Providers/FreeSql.Provider.PostgreSQL/Curd/OnConflictDoUpdate.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,197 @@
 | 
				
			|||||||
 | 
					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.Text.RegularExpressions;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.PostgreSQL.Curd
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class OnConflictDoUpdate<T1> where T1 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        internal PostgreSQLInsert<T1> _pgsqlInsert;
 | 
				
			||||||
 | 
					        internal PostgreSQLUpdate<T1> _pgsqlUpdatePriv;
 | 
				
			||||||
 | 
					        internal PostgreSQLUpdate<T1> _pgsqlUpdate => _pgsqlUpdatePriv ?? 
 | 
				
			||||||
 | 
					            (_pgsqlUpdatePriv = new PostgreSQLUpdate<T1>(_pgsqlInsert.InternalOrm, _pgsqlInsert.InternalCommonUtils, _pgsqlInsert.InternalCommonExpression, null) { InternalTableAlias = "EXCLUDED" }
 | 
				
			||||||
 | 
					                .NoneParameter().SetSource(_pgsqlInsert.InternalSource) as PostgreSQLUpdate<T1>);
 | 
				
			||||||
 | 
					        ColumnInfo[] _columns;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public OnConflictDoUpdate(IInsert<T1> insert, Expression<Func<T1, object>> columns = null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _pgsqlInsert = insert as PostgreSQLInsert<T1>;
 | 
				
			||||||
 | 
					            if (_pgsqlInsert == null) throw new Exception("OnConflictDoUpdate 是 FreeSql.Provider.PostgreSQL 特有的功能");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (columns != null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var colsList = new List<ColumnInfo>();
 | 
				
			||||||
 | 
					                var cols = _pgsqlInsert.InternalCommonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(null, columns?.Body, false, null).ToDictionary(a => a, a => true);
 | 
				
			||||||
 | 
					                foreach (var col in _pgsqlInsert.InternalTable.Columns.Values)
 | 
				
			||||||
 | 
					                    if (cols.ContainsKey(col.Attribute.Name))
 | 
				
			||||||
 | 
					                        colsList.Add(col);
 | 
				
			||||||
 | 
					                _columns = colsList.ToArray();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (_columns == null || _columns.Any() == false)
 | 
				
			||||||
 | 
					                _columns = _pgsqlInsert.InternalTable.Primarys;
 | 
				
			||||||
 | 
					            if (_columns.Any() == false) throw new Exception("OnConflictDoUpdate 功能要求实体类必须设置 IsPrimary 属性");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected void ClearData()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _pgsqlInsert.InternalClearData();
 | 
				
			||||||
 | 
					            _pgsqlUpdatePriv = null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public OnConflictDoUpdate<T1> IgnoreColumns(Expression<Func<T1, object>> columns)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _pgsqlUpdate.IgnoreColumns(columns);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public OnConflictDoUpdate<T1> UpdateColumns(Expression<Func<T1, object>> columns)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _pgsqlUpdate.UpdateColumns(columns);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public OnConflictDoUpdate<T1> IgnoreColumns(string[] columns)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _pgsqlUpdate.IgnoreColumns(columns);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public OnConflictDoUpdate<T1> UpdateColumns(string[] columns)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _pgsqlUpdate.UpdateColumns(columns);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public OnConflictDoUpdate<T1> Set<TMember>(Expression<Func<T1, TMember>> column, TMember value)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _pgsqlUpdate.Set(column, value);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        //由于表达式解析问题,ON CONFLICT("id") DO UPDATE SET 需要指定表别名,如 Set(a => a.Clicks + 1) 解析会失败
 | 
				
			||||||
 | 
					        //暂时不开放这个功能,如有需要使用 SetRaw("click = t.click + 1") 替代该操作
 | 
				
			||||||
 | 
					        //public OnConflictDoUpdate<T1> Set<TMember>(Expression<Func<T1, TMember>> exp)
 | 
				
			||||||
 | 
					        //{
 | 
				
			||||||
 | 
					        //    _pgsqlUpdate.Set(exp);
 | 
				
			||||||
 | 
					        //    return this;
 | 
				
			||||||
 | 
					        //}
 | 
				
			||||||
 | 
					        public OnConflictDoUpdate<T1> SetRaw(string sql)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _pgsqlUpdate.SetRaw(sql);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public string ToSql()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var sb = new StringBuilder();
 | 
				
			||||||
 | 
					            var insertSql = _pgsqlInsert.ToSql();
 | 
				
			||||||
 | 
					            sb.Append(insertSql).Insert(insertSql.IndexOf('('), " AS _ftb_ ").Append("\r\nON CONFLICT(");
 | 
				
			||||||
 | 
					            for (var a = 0; a < _columns.Length; a++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (a > 0) sb.Append(", ");
 | 
				
			||||||
 | 
					                sb.Append(_pgsqlInsert.InternalCommonUtils.QuoteSqlName(_columns[a].Attribute.Name));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            sb.Append(") DO UPDATE SET\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var sbSetEmpty = _pgsqlUpdate.InternalSbSet.Length == 0;
 | 
				
			||||||
 | 
					            var sbSetIncrEmpty = _pgsqlUpdate.InternalSbSetIncr.Length == 0;
 | 
				
			||||||
 | 
					            if (sbSetEmpty == false || sbSetIncrEmpty == false)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (sbSetEmpty == false) sb.Append(_pgsqlUpdate.InternalSbSet.ToString().Substring(2));
 | 
				
			||||||
 | 
					                if (sbSetIncrEmpty == false) sb.Append(sbSetEmpty ? _pgsqlUpdate.InternalSbSetIncr.ToString().Substring(2) : _pgsqlUpdate.InternalSbSetIncr.ToString());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var colidx = 0;
 | 
				
			||||||
 | 
					                foreach (var col in _pgsqlInsert.InternalTable.Columns.Values)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (col.Attribute.IsPrimary || _pgsqlUpdate.InternalIgnore.ContainsKey(col.Attribute.Name)) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (colidx > 0) sb.Append(", \r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (col.Attribute.IsVersion == true)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var field = _pgsqlInsert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name);
 | 
				
			||||||
 | 
					                        sb.Append(field).Append(" = _ftb_.").Append(field).Append(" + 1");
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else if (_pgsqlInsert.InternalIgnore.ContainsKey(col.Attribute.Name))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var caseWhen = _pgsqlUpdate.InternalWhereCaseSource(col.CsName, sqlval => sqlval).Trim();
 | 
				
			||||||
 | 
					                        sb.Append(caseWhen);
 | 
				
			||||||
 | 
					                        if (caseWhen.EndsWith(" END")) _pgsqlUpdate.InternalToSqlCaseWhenEnd(sb, col);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var field = _pgsqlInsert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name);
 | 
				
			||||||
 | 
					                        sb.Append(field).Append(" = EXCLUDED.").Append(field);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    ++colidx;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return sb.ToString();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public long ExecuteAffrows()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var sql = this.ToSql();
 | 
				
			||||||
 | 
					            if (string.IsNullOrEmpty(sql)) return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var before = new CurdBeforeEventArgs(_pgsqlInsert.InternalTable.Type, _pgsqlInsert.InternalTable, CurdType.Insert, sql, _pgsqlInsert.InternalParams);
 | 
				
			||||||
 | 
					            _pgsqlInsert.InternalOrm.Aop.CurdBefore?.Invoke(_pgsqlInsert, before);
 | 
				
			||||||
 | 
					            long ret = 0;
 | 
				
			||||||
 | 
					            Exception exception = null;
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                ret = _pgsqlInsert.InternalOrm.Ado.ExecuteNonQuery(_pgsqlInsert.InternalConnection, _pgsqlInsert.InternalTransaction, CommandType.Text, sql, _pgsqlInsert.InternalParams);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception ex)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                exception = ex;
 | 
				
			||||||
 | 
					                throw ex;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            finally
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var after = new CurdAfterEventArgs(before, exception, ret);
 | 
				
			||||||
 | 
					                _pgsqlInsert.InternalOrm.Aop.CurdAfter?.Invoke(_pgsqlInsert, after);
 | 
				
			||||||
 | 
					                ClearData();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if net40
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        async public Task<long> ExecuteAffrowsAsync()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var sql = this.ToSql();
 | 
				
			||||||
 | 
					            if (string.IsNullOrEmpty(sql)) return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var before = new CurdBeforeEventArgs(_pgsqlInsert.InternalTable.Type, _pgsqlInsert.InternalTable, CurdType.Insert, sql, _pgsqlInsert.InternalParams);
 | 
				
			||||||
 | 
					            _pgsqlInsert.InternalOrm.Aop.CurdBefore?.Invoke(_pgsqlInsert, before);
 | 
				
			||||||
 | 
					            long ret = 0;
 | 
				
			||||||
 | 
					            Exception exception = null;
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                ret = await _pgsqlInsert.InternalOrm.Ado.ExecuteNonQueryAsync(_pgsqlInsert.InternalConnection, _pgsqlInsert.InternalTransaction, CommandType.Text, sql, _pgsqlInsert.InternalParams);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception ex)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                exception = ex;
 | 
				
			||||||
 | 
					                throw ex;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            finally
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var after = new CurdAfterEventArgs(before, exception, ret);
 | 
				
			||||||
 | 
					                _pgsqlInsert.InternalOrm.Aop.CurdAfter?.Invoke(_pgsqlInsert, after);
 | 
				
			||||||
 | 
					                ClearData();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,7 +1,9 @@
 | 
				
			|||||||
using FreeSql.Internal;
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
 | 
					using System.Data.Common;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using System.Text;
 | 
					using System.Text;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
@@ -16,6 +18,17 @@ namespace FreeSql.PostgreSQL.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<T1> InternalSource => _source;
 | 
				
			||||||
 | 
					        internal Dictionary<string, bool> InternalIgnore => _ignore;
 | 
				
			||||||
 | 
					        internal void InternalClearData() => ClearData();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public override int ExecuteAffrows() => base.SplitExecuteAffrows(5000, 3000);
 | 
					        public override int ExecuteAffrows() => base.SplitExecuteAffrows(5000, 3000);
 | 
				
			||||||
        public override long ExecuteIdentity() => base.SplitExecuteIdentity(5000, 3000);
 | 
					        public override long ExecuteIdentity() => base.SplitExecuteIdentity(5000, 3000);
 | 
				
			||||||
        public override List<T1> ExecuteInserted() => base.SplitExecuteInserted(5000, 3000);
 | 
					        public override List<T1> ExecuteInserted() => base.SplitExecuteInserted(5000, 3000);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,14 @@ namespace FreeSql.PostgreSQL.Curd
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        internal string InternalTableAlias;
 | 
				
			||||||
 | 
					        internal StringBuilder InternalSbSet => _set;
 | 
				
			||||||
 | 
					        internal StringBuilder InternalSbSetIncr => _setIncr;
 | 
				
			||||||
 | 
					        internal Dictionary<string, bool> InternalIgnore => _ignore;
 | 
				
			||||||
 | 
					        internal void InternalResetSource(List<T1> source) => _source = source;
 | 
				
			||||||
 | 
					        internal string InternalWhereCaseSource(string CsName, Func<string, string> thenValue) => WhereCaseSource(CsName, thenValue);
 | 
				
			||||||
 | 
					        internal void InternalToSqlCaseWhenEnd(StringBuilder sb, ColumnInfo col) => ToSqlCaseWhenEnd(sb, col);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public override int ExecuteAffrows() => base.SplitExecuteAffrows(500, 3000);
 | 
					        public override int ExecuteAffrows() => base.SplitExecuteAffrows(500, 3000);
 | 
				
			||||||
        public override List<T1> ExecuteUpdated() => base.SplitExecuteUpdated(500, 3000);
 | 
					        public override List<T1> ExecuteUpdated() => base.SplitExecuteUpdated(500, 3000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -64,6 +72,7 @@ namespace FreeSql.PostgreSQL.Curd
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            if (_table.Primarys.Length == 1)
 | 
					            if (_table.Primarys.Length == 1)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(InternalTableAlias) == false) caseWhen.Append(InternalTableAlias).Append(".");
 | 
				
			||||||
                caseWhen.Append(_commonUtils.QuoteReadColumn(_table.Primarys.First().Attribute.MapType, _commonUtils.QuoteSqlName(_table.Primarys.First().Attribute.Name)));
 | 
					                caseWhen.Append(_commonUtils.QuoteReadColumn(_table.Primarys.First().Attribute.MapType, _commonUtils.QuoteSqlName(_table.Primarys.First().Attribute.Name)));
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -72,6 +81,7 @@ namespace FreeSql.PostgreSQL.Curd
 | 
				
			|||||||
            foreach (var pk in _table.Primarys)
 | 
					            foreach (var pk in _table.Primarys)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                if (pkidx > 0) caseWhen.Append(" || ");
 | 
					                if (pkidx > 0) caseWhen.Append(" || ");
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(InternalTableAlias) == false) caseWhen.Append(InternalTableAlias).Append(".");
 | 
				
			||||||
                caseWhen.Append(_commonUtils.QuoteReadColumn(pk.Attribute.MapType, _commonUtils.QuoteSqlName(pk.Attribute.Name))).Append("::varchar");
 | 
					                caseWhen.Append(_commonUtils.QuoteReadColumn(pk.Attribute.MapType, _commonUtils.QuoteSqlName(pk.Attribute.Name))).Append("::varchar");
 | 
				
			||||||
                ++pkidx;
 | 
					                ++pkidx;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,9 @@
 | 
				
			|||||||
public static partial class FreeSqlPostgreSQLGlobalExtensions
 | 
					using FreeSql;
 | 
				
			||||||
 | 
					using FreeSql.PostgreSQL.Curd;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public static partial class FreeSqlPostgreSQLGlobalExtensions
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
@@ -9,4 +14,14 @@
 | 
				
			|||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    public static string FormatPostgreSQL(this string that, params object[] args) => _postgresqlAdo.Addslashes(that, args);
 | 
					    public static string FormatPostgreSQL(this string that, params object[] args) => _postgresqlAdo.Addslashes(that, args);
 | 
				
			||||||
    static FreeSql.PostgreSQL.PostgreSQLAdo _postgresqlAdo = new FreeSql.PostgreSQL.PostgreSQLAdo();
 | 
					    static FreeSql.PostgreSQL.PostgreSQLAdo _postgresqlAdo = new FreeSql.PostgreSQL.PostgreSQLAdo();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// PostgreSQL9.5+ 特有的功能,On Conflict Do Update<para></para>
 | 
				
			||||||
 | 
					    /// 注意:此功能会开启插入【自增列】
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <typeparam name="T1"></typeparam>
 | 
				
			||||||
 | 
					    /// <param name="that"></param>
 | 
				
			||||||
 | 
					    /// <param name="columns">默认是以主键作为重复判断,也可以指定其他列:a => a.Name | a => new{a.Name,a.Time} | a => new[]{"name","time"}</param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    public static OnConflictDoUpdate<T1> OnConflictDoUpdate<T1>(this IInsert<T1> that, Expression<Func<T1, object>> columns = null) where T1 : class => new FreeSql.PostgreSQL.Curd.OnConflictDoUpdate<T1>(that.InsertIdentity(), columns);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user