mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 09:15:27 +08:00 
			
		
		
		
	- 增加 IFreeSql.InsertOrUpdate 方法 #316
This commit is contained in:
		@@ -76,6 +76,11 @@ namespace FreeSql
 | 
				
			|||||||
        public IInsert<T1> Insert<T1>(T1[] source) where T1 : class => Insert<T1>().AppendData(source);
 | 
					        public IInsert<T1> Insert<T1>(T1[] source) where T1 : class => Insert<T1>().AppendData(source);
 | 
				
			||||||
        public IInsert<T1> Insert<T1>(List<T1> source) where T1 : class => Insert<T1>().AppendData(source);
 | 
					        public IInsert<T1> Insert<T1>(List<T1> source) where T1 : class => Insert<T1>().AppendData(source);
 | 
				
			||||||
        public IInsert<T1> Insert<T1>(IEnumerable<T1> source) where T1 : class => Insert<T1>().AppendData(source);
 | 
					        public IInsert<T1> Insert<T1>(IEnumerable<T1> source) where T1 : class => Insert<T1>().AppendData(source);
 | 
				
			||||||
 | 
					        public IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var db = _resolveDbContext?.Invoke();
 | 
				
			||||||
 | 
					            db?.FlushCommand();
 | 
				
			||||||
 | 
					            return _originalFsql.InsertOrUpdate<T1>().WithTransaction(_resolveUnitOfWork()?.GetOrBeginTransaction());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -125,13 +125,6 @@
 | 
				
			|||||||
            清空状态数据
 | 
					            清空状态数据
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:FreeSql.DbSet`1.RemoveAsync(System.Linq.Expressions.Expression{System.Func{`0,System.Boolean}})">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            根据 lambda 条件删除数据
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="predicate"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.DbSet`1.Add(`0)">
 | 
					        <member name="M:FreeSql.DbSet`1.Add(`0)">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            添加
 | 
					            添加
 | 
				
			||||||
@@ -486,14 +479,5 @@
 | 
				
			|||||||
            <param name="that"></param>
 | 
					            <param name="that"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:Microsoft.Extensions.DependencyInjection.FreeSqlRepositoryDependencyInjection.AddFreeRepository(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Action{FreeSql.FluentDataFilter},System.Reflection.Assembly[])">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            批量注入 Repository,可以参考代码自行调整
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="services"></param>
 | 
					 | 
				
			||||||
            <param name="globalDataFilter"></param>
 | 
					 | 
				
			||||||
            <param name="assemblies"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
    </members>
 | 
					    </members>
 | 
				
			||||||
</doc>
 | 
					</doc>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,167 @@
 | 
				
			|||||||
 | 
					using FreeSql.DataAnnotations;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Tests.MySqlConnector
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class MySqlInsertOrUpdateTest
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        IFreeSql fsql => g.mysql;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou02>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou02`(`id`, `name`) VALUES(1, '01')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou02`(`id`, `name`) VALUES(1, '011')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(2, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou02`(`id`, `name`) VALUES(2, '02')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "01" }, new tbiou02 { id = 2, name = "02" }, new tbiou02 { id = 3, name = "03" }, new tbiou02 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou02`(`id`, `name`) VALUES(1, '01'), (2, '02'), (3, '03'), (4, '04')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(5, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "001" }, new tbiou02 { id = 2, name = "002" }, new tbiou02 { id = 3, name = "003" }, new tbiou02 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou02`(`id`, `name`) VALUES(1, '001'), (2, '002'), (3, '003'), (4, '004')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(8, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou02>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou02
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_TwoPrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou03>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "01", name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou03`(`id1`, `id2`, `name`) VALUES(1, '01', '01')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "01", name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou03`(`id1`, `id2`, `name`) VALUES(1, '01', '011')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(2, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 2, id2 = "02", name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou03`(`id1`, `id2`, `name`) VALUES(2, '02', '02')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "01" }, new tbiou03 { id1 = 2, id2 = "02", name = "02" }, new tbiou03 { id1 = 3, id2 = "03", name = "03" }, new tbiou03 { id1 = 4, id2 = "04", name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou03`(`id1`, `id2`, `name`) VALUES(1, '01', '01'), (2, '02', '02'), (3, '03', '03'), (4, '04', '04')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(5, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "001" }, new tbiou03 { id1 = 2, id2 = "02", name = "002" }, new tbiou03 { id1 = 3, id2 = "03", name = "003" }, new tbiou03 { id1 = 4, id2 = "04", name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou03`(`id1`, `id2`, `name`) VALUES(1, '01', '001'), (2, '02', '002'), (3, '03', '003'), (4, '04', '004')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(8, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou03>().Where(a => a.id1 == 1 && a.id2 == "01" || a.id1 == 2 && a.id2 == "02" || a.id1 == 3 && a.id2 == "03" || a.id1 == 4 && a.id2 == "04").ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id1).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou03
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public int id1 { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public string id2 { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimaryAndVersionAndCanUpdate()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou04>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou04`(`id`, `name`, `version`, `CreateTime`) VALUES(1, '01', 0, now(3))
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`), 
 | 
				
			||||||
 | 
					`version` = `version` + 1", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou04`(`id`, `name`, `version`, `CreateTime`) VALUES(1, '011', 0, now(3))
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`), 
 | 
				
			||||||
 | 
					`version` = `version` + 1", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(2, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou04`(`id`, `name`, `version`, `CreateTime`) VALUES(2, '02', 0, now(3))
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`), 
 | 
				
			||||||
 | 
					`version` = `version` + 1", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "01" }, new tbiou04 { id = 2, name = "02" }, new tbiou04 { id = 3, name = "03" }, new tbiou04 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou04`(`id`, `name`, `version`, `CreateTime`) VALUES(1, '01', 0, now(3)), (2, '02', 0, now(3)), (3, '03', 0, now(3)), (4, '04', 0, now(3))
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`), 
 | 
				
			||||||
 | 
					`version` = `version` + 1", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(6, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "001" }, new tbiou04 { id = 2, name = "002" }, new tbiou04 { id = 3, name = "003" }, new tbiou04 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou04`(`id`, `name`, `version`, `CreateTime`) VALUES(1, '001', 0, now(3)), (2, '002', 0, now(3)), (3, '003', 0, now(3)), (4, '004', 0, now(3))
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`), 
 | 
				
			||||||
 | 
					`version` = `version` + 1", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(8, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou04>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou04
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsVersion = true)]
 | 
				
			||||||
 | 
					            public int version { get; set; }
 | 
				
			||||||
 | 
					            [Column(CanUpdate = false, ServerTime = DateTimeKind.Local)]
 | 
				
			||||||
 | 
					            public DateTime CreateTime { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,323 @@
 | 
				
			|||||||
 | 
					using FreeSql.DataAnnotations;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Tests.Odbc.Dameng
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class DamengInsertOrUpdateTest
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        IFreeSql fsql => g.dameng;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnlyPrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou01>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 1 });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU01"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"") 
 | 
				
			||||||
 | 
					  values (t2.ID)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 1 });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU01"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"") 
 | 
				
			||||||
 | 
					  values (t2.ID)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 2 });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU01"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as ID FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"") 
 | 
				
			||||||
 | 
					  values (t2.ID)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new[] { new tbiou01 { id = 1 }, new tbiou01 { id = 2 }, new tbiou01 { id = 3 }, new tbiou01 { id = 4 } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU01"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2 FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3 FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4 FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"") 
 | 
				
			||||||
 | 
					  values (t2.ID)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new[] { new tbiou01 { id = 1 }, new tbiou01 { id = 2 }, new tbiou01 { id = 3 }, new tbiou01 { id = 4 } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU01"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2 FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3 FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4 FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"") 
 | 
				
			||||||
 | 
					  values (t2.ID)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou01
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou02>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU02"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '01' as NAME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU02"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '011' as NAME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU02"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as ID, '02' as NAME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "01" }, new tbiou02 { id = 2, name = "02" }, new tbiou02 { id = 3, name = "03" }, new tbiou02 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU02"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '01' as NAME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '02' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '03' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '04' FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "001" }, new tbiou02 { id = 2, name = "002" }, new tbiou02 { id = 3, name = "003" }, new tbiou02 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU02"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '001' as NAME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '002' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '003' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '004' FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou02>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou02
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_TwoPrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou03>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "01", name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU03"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID1, '01' as ID2, '01' as NAME FROM dual ) t2 ON (t1.""ID1"" = t2.ID1 AND t1.""ID2"" = t2.ID2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID1"", ""ID2"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID1, t2.ID2, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "02", name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU03"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID1, '02' as ID2, '011' as NAME FROM dual ) t2 ON (t1.""ID1"" = t2.ID1 AND t1.""ID2"" = t2.ID2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID1"", ""ID2"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID1, t2.ID2, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 2, id2 = "02", name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU03"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as ID1, '02' as ID2, '02' as NAME FROM dual ) t2 ON (t1.""ID1"" = t2.ID1 AND t1.""ID2"" = t2.ID2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID1"", ""ID2"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID1, t2.ID2, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "01" }, new tbiou03 { id1 = 2, id2 = "02", name = "02" }, new tbiou03 { id1 = 3, id2 = "03", name = "03" }, new tbiou03 { id1 = 4, id2 = "04", name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU03"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID1, '01' as ID2, '01' as NAME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '02', '02' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '03', '03' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '04', '04' FROM dual ) t2 ON (t1.""ID1"" = t2.ID1 AND t1.""ID2"" = t2.ID2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID1"", ""ID2"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID1, t2.ID2, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "001" }, new tbiou03 { id1 = 2, id2 = "02", name = "002" }, new tbiou03 { id1 = 3, id2 = "03", name = "003" }, new tbiou03 { id1 = 4, id2 = "04", name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU03"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID1, '01' as ID2, '001' as NAME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '02', '002' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '03', '003' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '04', '004' FROM dual ) t2 ON (t1.""ID1"" = t2.ID1 AND t1.""ID2"" = t2.ID2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID1"", ""ID2"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID1, t2.ID2, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou03>().Where(a => a.id1 == 1 && a.id2 == "01" || a.id1 == 2 && a.id2 == "02" || a.id1 == 3 && a.id2 == "03" || a.id1 == 4 && a.id2 == "04").ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id1).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou03
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public int id1 { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public string id2 { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimaryAndVersionAndCanUpdate()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou04>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU04"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '01' as NAME, 0 as VERSION, systimestamp as CREATETIME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME, ""VERSION"" = t1.""VERSION"" + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME, t2.VERSION, t2.CREATETIME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU04"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '011' as NAME, 0 as VERSION, systimestamp as CREATETIME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME, ""VERSION"" = t1.""VERSION"" + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME, t2.VERSION, t2.CREATETIME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU04"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as ID, '02' as NAME, 0 as VERSION, systimestamp as CREATETIME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME, ""VERSION"" = t1.""VERSION"" + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME, t2.VERSION, t2.CREATETIME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "01" }, new tbiou04 { id = 2, name = "02" }, new tbiou04 { id = 3, name = "03" }, new tbiou04 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU04"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '01' as NAME, 0 as VERSION, systimestamp as CREATETIME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '02', 0, systimestamp FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '03', 0, systimestamp FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '04', 0, systimestamp FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME, ""VERSION"" = t1.""VERSION"" + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME, t2.VERSION, t2.CREATETIME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "001" }, new tbiou04 { id = 2, name = "002" }, new tbiou04 { id = 3, name = "003" }, new tbiou04 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU04"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '001' as NAME, 0 as VERSION, systimestamp as CREATETIME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '002', 0, systimestamp FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '003', 0, systimestamp FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '004', 0, systimestamp FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME, ""VERSION"" = t1.""VERSION"" + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME, t2.VERSION, t2.CREATETIME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou04>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou04
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsVersion = true)]
 | 
				
			||||||
 | 
					            public int version { get; set; }
 | 
				
			||||||
 | 
					            [Column(CanUpdate = false, ServerTime = DateTimeKind.Local)]
 | 
				
			||||||
 | 
					            public DateTime CreateTime { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,167 @@
 | 
				
			|||||||
 | 
					using FreeSql.DataAnnotations;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Tests.Odbc.MySql
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class MySqlInsertOrUpdateTest
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        IFreeSql fsql => g.mysql;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou02>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou02`(`id`, `name`) VALUES(1, '01')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou02`(`id`, `name`) VALUES(1, '011')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou02`(`id`, `name`) VALUES(2, '02')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "01" }, new tbiou02 { id = 2, name = "02" }, new tbiou02 { id = 3, name = "03" }, new tbiou02 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou02`(`id`, `name`) VALUES(1, '01'), (2, '02'), (3, '03'), (4, '04')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "001" }, new tbiou02 { id = 2, name = "002" }, new tbiou02 { id = 3, name = "003" }, new tbiou02 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou02`(`id`, `name`) VALUES(1, '001'), (2, '002'), (3, '003'), (4, '004')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou02>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou02
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_TwoPrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou03>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "01", name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou03`(`id1`, `id2`, `name`) VALUES(1, '01', '01')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "01", name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou03`(`id1`, `id2`, `name`) VALUES(1, '01', '011')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 2, id2 = "02", name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou03`(`id1`, `id2`, `name`) VALUES(2, '02', '02')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "01" }, new tbiou03 { id1 = 2, id2 = "02", name = "02" }, new tbiou03 { id1 = 3, id2 = "03", name = "03" }, new tbiou03 { id1 = 4, id2 = "04", name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou03`(`id1`, `id2`, `name`) VALUES(1, '01', '01'), (2, '02', '02'), (3, '03', '03'), (4, '04', '04')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "001" }, new tbiou03 { id1 = 2, id2 = "02", name = "002" }, new tbiou03 { id1 = 3, id2 = "03", name = "003" }, new tbiou03 { id1 = 4, id2 = "04", name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou03`(`id1`, `id2`, `name`) VALUES(1, '01', '001'), (2, '02', '002'), (3, '03', '003'), (4, '04', '004')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou03>().Where(a => a.id1 == 1 && a.id2 == "01" || a.id1 == 2 && a.id2 == "02" || a.id1 == 3 && a.id2 == "03" || a.id1 == 4 && a.id2 == "04").ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id1).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou03
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public int id1 { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public string id2 { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimaryAndVersionAndCanUpdate()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou04>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou04`(`id`, `name`, `version`, `CreateTime`) VALUES(1, '01', 0, now(3))
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`), 
 | 
				
			||||||
 | 
					`version` = `version` + 1", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou04`(`id`, `name`, `version`, `CreateTime`) VALUES(1, '011', 0, now(3))
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`), 
 | 
				
			||||||
 | 
					`version` = `version` + 1", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou04`(`id`, `name`, `version`, `CreateTime`) VALUES(2, '02', 0, now(3))
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`), 
 | 
				
			||||||
 | 
					`version` = `version` + 1", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "01" }, new tbiou04 { id = 2, name = "02" }, new tbiou04 { id = 3, name = "03" }, new tbiou04 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou04`(`id`, `name`, `version`, `CreateTime`) VALUES(1, '01', 0, now(3)), (2, '02', 0, now(3)), (3, '03', 0, now(3)), (4, '04', 0, now(3))
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`), 
 | 
				
			||||||
 | 
					`version` = `version` + 1", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "001" }, new tbiou04 { id = 2, name = "002" }, new tbiou04 { id = 3, name = "003" }, new tbiou04 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou04`(`id`, `name`, `version`, `CreateTime`) VALUES(1, '001', 0, now(3)), (2, '002', 0, now(3)), (3, '003', 0, now(3)), (4, '004', 0, now(3))
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`), 
 | 
				
			||||||
 | 
					`version` = `version` + 1", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou04>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou04
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsVersion = true)]
 | 
				
			||||||
 | 
					            public int version { get; set; }
 | 
				
			||||||
 | 
					            [Column(CanUpdate = false, ServerTime = DateTimeKind.Local)]
 | 
				
			||||||
 | 
					            public DateTime CreateTime { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,195 @@
 | 
				
			|||||||
 | 
					using FreeSql.DataAnnotations;
 | 
				
			||||||
 | 
					using FreeSql.Odbc.MySql;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Tests.Odbc.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<TestOnDuplicateKeyUpdateInfo>(new[] { 100, 101, 102 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					            var odku1 = new OdbcMySqlOnDuplicateKeyUpdate<TestOnDuplicateKeyUpdateInfo>(g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 100, title = "title-100", time = DateTime.Parse("2000-01-01") }).NoneParameter().InsertIdentity());
 | 
				
			||||||
 | 
					            Assert.Equal(@"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`)", odku1.ToSql());
 | 
				
			||||||
 | 
					            Assert.Equal(1, odku1.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var odku2 = new OdbcMySqlOnDuplicateKeyUpdate<TestOnDuplicateKeyUpdateInfo>(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().InsertIdentity());
 | 
				
			||||||
 | 
					            Assert.Equal(@"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.ToSql());
 | 
				
			||||||
 | 
					            odku2.ExecuteAffrows();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void IgnoreColumns()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            g.mysql.Delete<TestOnDuplicateKeyUpdateInfo>(new[] { 200, 201, 202 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					            var odku1 = new OdbcMySqlOnDuplicateKeyUpdate<TestOnDuplicateKeyUpdateInfo>(g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 200, title = "title-200", time = DateTime.Parse("2000-01-01") }).IgnoreColumns(a => a.time).NoneParameter().InsertIdentity());
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(200, 'title-200')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`title` = VALUES(`title`), 
 | 
				
			||||||
 | 
					`time` = '2000-01-01 00:00:00.000'", odku1.ToSql());
 | 
				
			||||||
 | 
					            Assert.Equal(1, odku1.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var odku2 = new OdbcMySqlOnDuplicateKeyUpdate<TestOnDuplicateKeyUpdateInfo>(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().InsertIdentity());
 | 
				
			||||||
 | 
					            Assert.Equal(@"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.ToSql());
 | 
				
			||||||
 | 
					            odku2.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            g.mysql.Delete<TestOnDuplicateKeyUpdateInfo>(new[] { 200, 201, 202 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					            odku1 = new OdbcMySqlOnDuplicateKeyUpdate<TestOnDuplicateKeyUpdateInfo>(g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 200, title = "title-200", time = DateTime.Parse("2000-01-01") }).IgnoreColumns(a => a.time).NoneParameter().InsertIdentity()).IgnoreColumns(a => a.title);
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(200, 'title-200')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`time` = '2000-01-01 00:00:00.000'", odku1.ToSql());
 | 
				
			||||||
 | 
					            Assert.Equal(1, odku1.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            odku2 = new OdbcMySqlOnDuplicateKeyUpdate<TestOnDuplicateKeyUpdateInfo>(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().InsertIdentity()).IgnoreColumns(a => a.title);
 | 
				
			||||||
 | 
					            Assert.Equal(@"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.ToSql());
 | 
				
			||||||
 | 
					            odku2.ExecuteAffrows();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void UpdateColumns()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            g.mysql.Delete<TestOnDuplicateKeyUpdateInfo>(new[] { 300, 301, 302 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					            var odku1 = new OdbcMySqlOnDuplicateKeyUpdate<TestOnDuplicateKeyUpdateInfo>(g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 300, title = "title-300", time = DateTime.Parse("2000-01-01") }).InsertColumns(a => a.title).NoneParameter().InsertIdentity());
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(300, 'title-300')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`title` = VALUES(`title`), 
 | 
				
			||||||
 | 
					`time` = '2000-01-01 00:00:00.000'", odku1.ToSql());
 | 
				
			||||||
 | 
					            Assert.Equal(1, odku1.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var odku2 = new OdbcMySqlOnDuplicateKeyUpdate<TestOnDuplicateKeyUpdateInfo>(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().InsertIdentity());
 | 
				
			||||||
 | 
					            Assert.Equal(@"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.ToSql());
 | 
				
			||||||
 | 
					            odku2.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            g.mysql.Delete<TestOnDuplicateKeyUpdateInfo>(new[] { 300, 301, 302 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					            odku1 = new OdbcMySqlOnDuplicateKeyUpdate<TestOnDuplicateKeyUpdateInfo>(g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 300, title = "title-300", time = DateTime.Parse("2000-01-01") }).InsertColumns(a => a.title).NoneParameter().InsertIdentity()).UpdateColumns(a => a.time);
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(300, 'title-300')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`time` = '2000-01-01 00:00:00.000'", odku1.ToSql());
 | 
				
			||||||
 | 
					            Assert.Equal(1, odku1.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            odku2 = new OdbcMySqlOnDuplicateKeyUpdate<TestOnDuplicateKeyUpdateInfo>(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().InsertIdentity()).UpdateColumns(a => a.time);
 | 
				
			||||||
 | 
					            Assert.Equal(@"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.ToSql());
 | 
				
			||||||
 | 
					            odku2.ExecuteAffrows();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void Set()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            g.mysql.Delete<TestOnDuplicateKeyUpdateInfo>(new[] { 400, 401, 402 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					            var odku1 = new OdbcMySqlOnDuplicateKeyUpdate<TestOnDuplicateKeyUpdateInfo>(g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") }).NoneParameter().InsertIdentity()).Set(a => a.time, DateTime.Parse("2020-1-1"));
 | 
				
			||||||
 | 
					            Assert.Equal(@"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'", odku1.ToSql());
 | 
				
			||||||
 | 
					            Assert.Equal(1, odku1.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var odku2 = new OdbcMySqlOnDuplicateKeyUpdate<TestOnDuplicateKeyUpdateInfo>(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().InsertIdentity()).Set(a => a.time, DateTime.Parse("2020-1-1"));
 | 
				
			||||||
 | 
					            Assert.Equal(@"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.ToSql());
 | 
				
			||||||
 | 
					            odku2.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var dt2020 = DateTime.Parse("2020-1-1");
 | 
				
			||||||
 | 
					            g.mysql.Delete<TestOnDuplicateKeyUpdateInfo>(new[] { 400, 401, 402 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					            odku1 = new OdbcMySqlOnDuplicateKeyUpdate<TestOnDuplicateKeyUpdateInfo>(g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") }).NoneParameter().InsertIdentity()).Set(a => a.time == dt2020);
 | 
				
			||||||
 | 
					            Assert.Equal(@"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'", odku1.ToSql());
 | 
				
			||||||
 | 
					            Assert.Equal(1, odku1.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            odku2 = new OdbcMySqlOnDuplicateKeyUpdate<TestOnDuplicateKeyUpdateInfo>(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().InsertIdentity()).Set(a => a.time == dt2020);
 | 
				
			||||||
 | 
					            Assert.Equal(@"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.ToSql());
 | 
				
			||||||
 | 
					            odku2.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            g.mysql.Delete<TestOnDuplicateKeyUpdateInfo>(new[] { 400, 401, 402 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					            odku1 = new OdbcMySqlOnDuplicateKeyUpdate<TestOnDuplicateKeyUpdateInfo>(g.mysql.Insert(new TestOnDuplicateKeyUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") }).NoneParameter().InsertIdentity()).Set(a => new { time = dt2020, title = a.title + "123" });
 | 
				
			||||||
 | 
					            Assert.Equal(@"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')", odku1.ToSql());
 | 
				
			||||||
 | 
					            Assert.Equal(1, odku1.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            odku2 = new OdbcMySqlOnDuplicateKeyUpdate<TestOnDuplicateKeyUpdateInfo>(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().InsertIdentity()).Set(a => new { time = dt2020, title = a.title + "123" });
 | 
				
			||||||
 | 
					            Assert.Equal(@"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.ToSql());
 | 
				
			||||||
 | 
					            odku2.ExecuteAffrows();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,323 @@
 | 
				
			|||||||
 | 
					using FreeSql.DataAnnotations;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Tests.Odbc.Oracle
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class OracleInsertOrUpdateTest
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        IFreeSql fsql => g.oracle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnlyPrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou01>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 1 });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU01"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"") 
 | 
				
			||||||
 | 
					  values (t2.ID)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 1 });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU01"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"") 
 | 
				
			||||||
 | 
					  values (t2.ID)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 2 });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU01"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as ID FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"") 
 | 
				
			||||||
 | 
					  values (t2.ID)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new[] { new tbiou01 { id = 1 }, new tbiou01 { id = 2 }, new tbiou01 { id = 3 }, new tbiou01 { id = 4 } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU01"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2 FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3 FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4 FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"") 
 | 
				
			||||||
 | 
					  values (t2.ID)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new[] { new tbiou01 { id = 1 }, new tbiou01 { id = 2 }, new tbiou01 { id = 3 }, new tbiou01 { id = 4 } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU01"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2 FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3 FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4 FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"") 
 | 
				
			||||||
 | 
					  values (t2.ID)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou01
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou02>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU02"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '01' as NAME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU02"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '011' as NAME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU02"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as ID, '02' as NAME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "01" }, new tbiou02 { id = 2, name = "02" }, new tbiou02 { id = 3, name = "03" }, new tbiou02 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU02"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '01' as NAME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '02' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '03' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '04' FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "001" }, new tbiou02 { id = 2, name = "002" }, new tbiou02 { id = 3, name = "003" }, new tbiou02 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU02"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '001' as NAME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '002' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '003' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '004' FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou02>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou02
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_TwoPrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou03>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "01", name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU03"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID1, '01' as ID2, '01' as NAME FROM dual ) t2 ON (t1.""ID1"" = t2.ID1 AND t1.""ID2"" = t2.ID2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID1"", ""ID2"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID1, t2.ID2, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "02", name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU03"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID1, '02' as ID2, '011' as NAME FROM dual ) t2 ON (t1.""ID1"" = t2.ID1 AND t1.""ID2"" = t2.ID2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID1"", ""ID2"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID1, t2.ID2, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 2, id2 = "02", name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU03"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as ID1, '02' as ID2, '02' as NAME FROM dual ) t2 ON (t1.""ID1"" = t2.ID1 AND t1.""ID2"" = t2.ID2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID1"", ""ID2"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID1, t2.ID2, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "01" }, new tbiou03 { id1 = 2, id2 = "02", name = "02" }, new tbiou03 { id1 = 3, id2 = "03", name = "03" }, new tbiou03 { id1 = 4, id2 = "04", name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU03"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID1, '01' as ID2, '01' as NAME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '02', '02' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '03', '03' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '04', '04' FROM dual ) t2 ON (t1.""ID1"" = t2.ID1 AND t1.""ID2"" = t2.ID2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID1"", ""ID2"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID1, t2.ID2, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "001" }, new tbiou03 { id1 = 2, id2 = "02", name = "002" }, new tbiou03 { id1 = 3, id2 = "03", name = "003" }, new tbiou03 { id1 = 4, id2 = "04", name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU03"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID1, '01' as ID2, '001' as NAME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '02', '002' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '03', '003' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '04', '004' FROM dual ) t2 ON (t1.""ID1"" = t2.ID1 AND t1.""ID2"" = t2.ID2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID1"", ""ID2"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID1, t2.ID2, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou03>().Where(a => a.id1 == 1 && a.id2 == "01" || a.id1 == 2 && a.id2 == "02" || a.id1 == 3 && a.id2 == "03" || a.id1 == 4 && a.id2 == "04").ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id1).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou03
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public int id1 { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public string id2 { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimaryAndVersionAndCanUpdate()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou04>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU04"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '01' as NAME, 0 as VERSION, systimestamp as CREATETIME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME, ""VERSION"" = t1.""VERSION"" + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME, t2.VERSION, t2.CREATETIME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU04"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '011' as NAME, 0 as VERSION, systimestamp as CREATETIME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME, ""VERSION"" = t1.""VERSION"" + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME, t2.VERSION, t2.CREATETIME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU04"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as ID, '02' as NAME, 0 as VERSION, systimestamp as CREATETIME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME, ""VERSION"" = t1.""VERSION"" + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME, t2.VERSION, t2.CREATETIME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "01" }, new tbiou04 { id = 2, name = "02" }, new tbiou04 { id = 3, name = "03" }, new tbiou04 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU04"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '01' as NAME, 0 as VERSION, systimestamp as CREATETIME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '02', 0, systimestamp FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '03', 0, systimestamp FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '04', 0, systimestamp FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME, ""VERSION"" = t1.""VERSION"" + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME, t2.VERSION, t2.CREATETIME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "001" }, new tbiou04 { id = 2, name = "002" }, new tbiou04 { id = 3, name = "003" }, new tbiou04 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU04"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '001' as NAME, 0 as VERSION, systimestamp as CREATETIME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '002', 0, systimestamp FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '003', 0, systimestamp FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '004', 0, systimestamp FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME, ""VERSION"" = t1.""VERSION"" + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME, t2.VERSION, t2.CREATETIME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou04>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou04
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsVersion = true)]
 | 
				
			||||||
 | 
					            public int version { get; set; }
 | 
				
			||||||
 | 
					            [Column(CanUpdate = false, ServerTime = DateTimeKind.Local)]
 | 
				
			||||||
 | 
					            public DateTime CreateTime { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,158 @@
 | 
				
			|||||||
 | 
					using FreeSql.DataAnnotations;
 | 
				
			||||||
 | 
					using FreeSql.Odbc.PostgreSQL;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Tests.Odbc.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 = new OdbcPostgreSQLOnConflictDoUpdate<TestOnConflictDoUpdateInfo>(g.pgsql.Insert(new TestOnConflictDoUpdateInfo { id = 100, title = "title-100", time = DateTime.Parse("2000-01-01") }).NoneParameter().InsertIdentity());
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""testonconflictdoupdateinfo""(""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""", odku1.ToSql());
 | 
				
			||||||
 | 
					            Assert.Equal(1, odku1.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var odku2 = new OdbcPostgreSQLOnConflictDoUpdate<TestOnConflictDoUpdateInfo>(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().InsertIdentity());
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""testonconflictdoupdateinfo""(""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.ToSql());
 | 
				
			||||||
 | 
					            odku2.ExecuteAffrows();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void IgnoreColumns()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            g.pgsql.Delete<TestOnConflictDoUpdateInfo>(new[] { 200, 201, 202 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					            var odku1 = new OdbcPostgreSQLOnConflictDoUpdate<TestOnConflictDoUpdateInfo>(g.pgsql.Insert(new TestOnConflictDoUpdateInfo { id = 200, title = "title-200", time = DateTime.Parse("2000-01-01") }).IgnoreColumns(a => a.time).NoneParameter().InsertIdentity());
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""testonconflictdoupdateinfo""(""id"", ""title"") VALUES(200, 'title-200')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""title"" = EXCLUDED.""title"", 
 | 
				
			||||||
 | 
					""time"" = '2000-01-01 00:00:00.000000'", odku1.ToSql());
 | 
				
			||||||
 | 
					            Assert.Equal(1, odku1.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var odku2 = new OdbcPostgreSQLOnConflictDoUpdate<TestOnConflictDoUpdateInfo>(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().InsertIdentity());
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""testonconflictdoupdateinfo""(""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.ToSql());
 | 
				
			||||||
 | 
					            odku2.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            g.pgsql.Delete<TestOnConflictDoUpdateInfo>(new[] { 200, 201, 202 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					            odku1 = new OdbcPostgreSQLOnConflictDoUpdate<TestOnConflictDoUpdateInfo>(g.pgsql.Insert(new TestOnConflictDoUpdateInfo { id = 200, title = "title-200", time = DateTime.Parse("2000-01-01") }).IgnoreColumns(a => a.time).NoneParameter().InsertIdentity()).IgnoreColumns(a => a.title);
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""testonconflictdoupdateinfo""(""id"", ""title"") VALUES(200, 'title-200')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""time"" = '2000-01-01 00:00:00.000000'", odku1.ToSql());
 | 
				
			||||||
 | 
					            Assert.Equal(1, odku1.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            odku2 = new OdbcPostgreSQLOnConflictDoUpdate<TestOnConflictDoUpdateInfo>(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().InsertIdentity()).IgnoreColumns(a => a.title);
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""testonconflictdoupdateinfo""(""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.ToSql());
 | 
				
			||||||
 | 
					            odku2.ExecuteAffrows();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void UpdateColumns()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            g.pgsql.Delete<TestOnConflictDoUpdateInfo>(new[] { 300, 301, 302 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					            var odku1 = new OdbcPostgreSQLOnConflictDoUpdate<TestOnConflictDoUpdateInfo>(g.pgsql.Insert(new TestOnConflictDoUpdateInfo { id = 300, title = "title-300", time = DateTime.Parse("2000-01-01") }).InsertColumns(a => a.title).NoneParameter().InsertIdentity());
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""testonconflictdoupdateinfo""(""id"", ""title"") VALUES(300, 'title-300')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""title"" = EXCLUDED.""title"", 
 | 
				
			||||||
 | 
					""time"" = '2000-01-01 00:00:00.000000'", odku1.ToSql());
 | 
				
			||||||
 | 
					            Assert.Equal(1, odku1.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var odku2 = new OdbcPostgreSQLOnConflictDoUpdate<TestOnConflictDoUpdateInfo>(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().InsertIdentity());
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""testonconflictdoupdateinfo""(""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.ToSql());
 | 
				
			||||||
 | 
					            odku2.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            g.pgsql.Delete<TestOnConflictDoUpdateInfo>(new[] { 300, 301, 302 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					            odku1 = new OdbcPostgreSQLOnConflictDoUpdate<TestOnConflictDoUpdateInfo>(g.pgsql.Insert(new TestOnConflictDoUpdateInfo { id = 300, title = "title-300", time = DateTime.Parse("2000-01-01") }).InsertColumns(a => a.title).NoneParameter().InsertIdentity()).UpdateColumns(a => a.time);
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""testonconflictdoupdateinfo""(""id"", ""title"") VALUES(300, 'title-300')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""time"" = '2000-01-01 00:00:00.000000'", odku1.ToSql());
 | 
				
			||||||
 | 
					            Assert.Equal(1, odku1.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            odku2 = new OdbcPostgreSQLOnConflictDoUpdate<TestOnConflictDoUpdateInfo>(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().InsertIdentity()).UpdateColumns(a => a.time);
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""testonconflictdoupdateinfo""(""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.ToSql());
 | 
				
			||||||
 | 
					            odku2.ExecuteAffrows();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void Set()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            g.pgsql.Delete<TestOnConflictDoUpdateInfo>(new[] { 400, 401, 402 }).ExecuteAffrows();
 | 
				
			||||||
 | 
					            var odku1 = new OdbcPostgreSQLOnConflictDoUpdate<TestOnConflictDoUpdateInfo>(g.pgsql.Insert(new TestOnConflictDoUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") }).NoneParameter().InsertIdentity()).Set(a => a.time, DateTime.Parse("2020-1-1"));
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""testonconflictdoupdateinfo""(""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'", odku1.ToSql());
 | 
				
			||||||
 | 
					            Assert.Equal(1, odku1.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var odku2 = new OdbcPostgreSQLOnConflictDoUpdate<TestOnConflictDoUpdateInfo>(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().InsertIdentity()).Set(a => a.time, DateTime.Parse("2020-1-1"));
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""testonconflictdoupdateinfo""(""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.ToSql());
 | 
				
			||||||
 | 
					            odku2.ExecuteAffrows();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,205 @@
 | 
				
			|||||||
 | 
					using FreeSql.DataAnnotations;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Tests.Odbc.PostgreSQL
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class PostgreSQLInsertOrUpdateTest
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        IFreeSql fsql => g.pgsql;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnlyPrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou01>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 1 });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou01""(""id"") VALUES(1)
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO NOTHING", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 1 });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou01""(""id"") VALUES(1)
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO NOTHING", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(0, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 2 });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou01""(""id"") VALUES(2)
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO NOTHING", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new[] { new tbiou01 { id = 1 }, new tbiou01 { id = 2 }, new tbiou01 { id = 3 }, new tbiou01 { id = 4 } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou01""(""id"") VALUES(1), (2), (3), (4)
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO NOTHING", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(2, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new[] { new tbiou01 { id = 1 }, new tbiou01 { id = 2 }, new tbiou01 { id = 3 }, new tbiou01 { id = 4 } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou01""(""id"") VALUES(1), (2), (3), (4)
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO NOTHING", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(0, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou01
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou02>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou02""(""id"", ""name"") VALUES(1, '01')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name""", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou02""(""id"", ""name"") VALUES(1, '011')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name""", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou02""(""id"", ""name"") VALUES(2, '02')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name""", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "01" }, new tbiou02 { id = 2, name = "02" }, new tbiou02 { id = 3, name = "03" }, new tbiou02 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou02""(""id"", ""name"") VALUES(1, '01'), (2, '02'), (3, '03'), (4, '04')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name""", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "001" }, new tbiou02 { id = 2, name = "002" }, new tbiou02 { id = 3, name = "003" }, new tbiou02 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou02""(""id"", ""name"") VALUES(1, '001'), (2, '002'), (3, '003'), (4, '004')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name""", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou02>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou02
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_TwoPrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou03>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "01", name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou03""(""id1"", ""id2"", ""name"") VALUES(1, '01', '01')
 | 
				
			||||||
 | 
					ON CONFLICT(""id1"", ""id2"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name""", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "02", name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou03""(""id1"", ""id2"", ""name"") VALUES(1, '02', '011')
 | 
				
			||||||
 | 
					ON CONFLICT(""id1"", ""id2"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name""", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 2, id2 = "02", name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou03""(""id1"", ""id2"", ""name"") VALUES(2, '02', '02')
 | 
				
			||||||
 | 
					ON CONFLICT(""id1"", ""id2"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name""", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "01" }, new tbiou03 { id1 = 2, id2 = "02", name = "02" }, new tbiou03 { id1 = 3, id2 = "03", name = "03" }, new tbiou03 { id1 = 4, id2 = "04", name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou03""(""id1"", ""id2"", ""name"") VALUES(1, '01', '01'), (2, '02', '02'), (3, '03', '03'), (4, '04', '04')
 | 
				
			||||||
 | 
					ON CONFLICT(""id1"", ""id2"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name""", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "001" }, new tbiou03 { id1 = 2, id2 = "02", name = "002" }, new tbiou03 { id1 = 3, id2 = "03", name = "003" }, new tbiou03 { id1 = 4, id2 = "04", name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou03""(""id1"", ""id2"", ""name"") VALUES(1, '01', '001'), (2, '02', '002'), (3, '03', '003'), (4, '04', '004')
 | 
				
			||||||
 | 
					ON CONFLICT(""id1"", ""id2"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name""", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou03>().Where(a => a.id1 == 1 && a.id2 == "01" || a.id1 == 2 && a.id2 == "02" || a.id1 == 3 && a.id2 == "03" || a.id1 == 4 && a.id2 == "04").ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id1).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou03
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public int id1 { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public string id2 { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimaryAndVersionAndCanUpdate()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou04>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou04""(""id"", ""name"", ""version"", ""createtime"") VALUES(1, '01', 0, current_timestamp)
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name"", 
 | 
				
			||||||
 | 
					""version"" = ""tbiou04"".""version"" + 1", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou04""(""id"", ""name"", ""version"", ""createtime"") VALUES(1, '011', 0, current_timestamp)
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name"", 
 | 
				
			||||||
 | 
					""version"" = ""tbiou04"".""version"" + 1", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou04""(""id"", ""name"", ""version"", ""createtime"") VALUES(2, '02', 0, current_timestamp)
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name"", 
 | 
				
			||||||
 | 
					""version"" = ""tbiou04"".""version"" + 1", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "01" }, new tbiou04 { id = 2, name = "02" }, new tbiou04 { id = 3, name = "03" }, new tbiou04 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou04""(""id"", ""name"", ""version"", ""createtime"") VALUES(1, '01', 0, current_timestamp), (2, '02', 0, current_timestamp), (3, '03', 0, current_timestamp), (4, '04', 0, current_timestamp)
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name"", 
 | 
				
			||||||
 | 
					""version"" = ""tbiou04"".""version"" + 1", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "001" }, new tbiou04 { id = 2, name = "002" }, new tbiou04 { id = 3, name = "003" }, new tbiou04 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou04""(""id"", ""name"", ""version"", ""createtime"") VALUES(1, '001', 0, current_timestamp), (2, '002', 0, current_timestamp), (3, '003', 0, current_timestamp), (4, '004', 0, current_timestamp)
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name"", 
 | 
				
			||||||
 | 
					""version"" = ""tbiou04"".""version"" + 1", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou04>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou04
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsVersion = true)]
 | 
				
			||||||
 | 
					            public int version { get; set; }
 | 
				
			||||||
 | 
					            [Column(CanUpdate = false, ServerTime = DateTimeKind.Local)]
 | 
				
			||||||
 | 
					            public DateTime CreateTime { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,323 @@
 | 
				
			|||||||
 | 
					using FreeSql.DataAnnotations;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Tests.Odbc.SqlServer
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class SqlServerInsertOrUpdateTest
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        IFreeSql fsql => g.sqlserver;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnlyPrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou01>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 1 });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou01] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id]) 
 | 
				
			||||||
 | 
					  values (t2.id);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 1 });
 | 
				
			||||||
 | 
					            sql = iou.ToSql(); 
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou01] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id]) 
 | 
				
			||||||
 | 
					  values (t2.id);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(0, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 2 });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou01] t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as id ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id]) 
 | 
				
			||||||
 | 
					  values (t2.id);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new[] { new tbiou01 { id = 1 }, new tbiou01 { id = 2 }, new tbiou01 { id = 3 }, new tbiou01 { id = 4 } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou01] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4 ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id]) 
 | 
				
			||||||
 | 
					  values (t2.id);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(2, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new[] { new tbiou01 { id = 1 }, new tbiou01 { id = 2 }, new tbiou01 { id = 3 }, new tbiou01 { id = 4 } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql(); 
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou01] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4 ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id]) 
 | 
				
			||||||
 | 
					  values (t2.id);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(0, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou01
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou02>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou02] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id, N'01' as name ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id], [name]) 
 | 
				
			||||||
 | 
					  values (t2.id, t2.name);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou02] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id, N'011' as name ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id], [name]) 
 | 
				
			||||||
 | 
					  values (t2.id, t2.name);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou02] t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as id, N'02' as name ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id], [name]) 
 | 
				
			||||||
 | 
					  values (t2.id, t2.name);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "01" }, new tbiou02 { id = 2, name = "02" }, new tbiou02 { id = 3, name = "03" }, new tbiou02 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou02] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id, N'01' as name 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, N'02' 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, N'03' 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, N'04' ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id], [name]) 
 | 
				
			||||||
 | 
					  values (t2.id, t2.name);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "001" }, new tbiou02 { id = 2, name = "002" }, new tbiou02 { id = 3, name = "003" }, new tbiou02 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou02] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id, N'001' as name 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, N'002' 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, N'003' 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, N'004' ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id], [name]) 
 | 
				
			||||||
 | 
					  values (t2.id, t2.name);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou02>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou02
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_TwoPrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou03>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "01", name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou03] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id1, N'01' as id2, N'01' as name ) t2 ON (t1.[id1] = t2.id1 AND t1.[id2] = t2.id2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id1], [id2], [name]) 
 | 
				
			||||||
 | 
					  values (t2.id1, t2.id2, t2.name);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "02", name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou03] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id1, N'02' as id2, N'011' as name ) t2 ON (t1.[id1] = t2.id1 AND t1.[id2] = t2.id2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id1], [id2], [name]) 
 | 
				
			||||||
 | 
					  values (t2.id1, t2.id2, t2.name);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 2, id2 = "02", name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou03] t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as id1, N'02' as id2, N'02' as name ) t2 ON (t1.[id1] = t2.id1 AND t1.[id2] = t2.id2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id1], [id2], [name]) 
 | 
				
			||||||
 | 
					  values (t2.id1, t2.id2, t2.name);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "01" }, new tbiou03 { id1 = 2, id2 = "02", name = "02" }, new tbiou03 { id1 = 3, id2 = "03", name = "03" }, new tbiou03 { id1 = 4, id2 = "04", name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou03] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id1, N'01' as id2, N'01' as name 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, N'02', N'02' 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, N'03', N'03' 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, N'04', N'04' ) t2 ON (t1.[id1] = t2.id1 AND t1.[id2] = t2.id2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id1], [id2], [name]) 
 | 
				
			||||||
 | 
					  values (t2.id1, t2.id2, t2.name);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "001" }, new tbiou03 { id1 = 2, id2 = "02", name = "002" }, new tbiou03 { id1 = 3, id2 = "03", name = "003" }, new tbiou03 { id1 = 4, id2 = "04", name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou03] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id1, N'01' as id2, N'001' as name 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, N'02', N'002' 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, N'03', N'003' 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, N'04', N'004' ) t2 ON (t1.[id1] = t2.id1 AND t1.[id2] = t2.id2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id1], [id2], [name]) 
 | 
				
			||||||
 | 
					  values (t2.id1, t2.id2, t2.name);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou03>().Where(a => a.id1 == 1 && a.id2 == "01" || a.id1 == 2 && a.id2 == "02" || a.id1 == 3 && a.id2 == "03" || a.id1 == 4 && a.id2 == "04").ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id1).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou03
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public int id1 { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public string id2 { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimaryAndVersionAndCanUpdate()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou04>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou04] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id, N'01' as name, 0 as version, getdate() as CreateTime ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name, [version] = t1.[version] + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id], [name], [version], [CreateTime]) 
 | 
				
			||||||
 | 
					  values (t2.id, t2.name, t2.version, t2.CreateTime);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou04] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id, N'011' as name, 0 as version, getdate() as CreateTime ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name, [version] = t1.[version] + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id], [name], [version], [CreateTime]) 
 | 
				
			||||||
 | 
					  values (t2.id, t2.name, t2.version, t2.CreateTime);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou04] t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as id, N'02' as name, 0 as version, getdate() as CreateTime ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name, [version] = t1.[version] + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id], [name], [version], [CreateTime]) 
 | 
				
			||||||
 | 
					  values (t2.id, t2.name, t2.version, t2.CreateTime);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "01" }, new tbiou04 { id = 2, name = "02" }, new tbiou04 { id = 3, name = "03" }, new tbiou04 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou04] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id, N'01' as name, 0 as version, getdate() as CreateTime 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, N'02', 0, getdate() 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, N'03', 0, getdate() 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, N'04', 0, getdate() ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name, [version] = t1.[version] + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id], [name], [version], [CreateTime]) 
 | 
				
			||||||
 | 
					  values (t2.id, t2.name, t2.version, t2.CreateTime);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "001" }, new tbiou04 { id = 2, name = "002" }, new tbiou04 { id = 3, name = "003" }, new tbiou04 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou04] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id, N'001' as name, 0 as version, getdate() as CreateTime 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, N'002', 0, getdate() 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, N'003', 0, getdate() 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, N'004', 0, getdate() ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name, [version] = t1.[version] + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id], [name], [version], [CreateTime]) 
 | 
				
			||||||
 | 
					  values (t2.id, t2.name, t2.version, t2.CreateTime);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou04>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou04
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsVersion = true)]
 | 
				
			||||||
 | 
					            public int version { get; set; }
 | 
				
			||||||
 | 
					            [Column(CanUpdate = false, ServerTime = DateTimeKind.Local)]
 | 
				
			||||||
 | 
					            public DateTime CreateTime { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,323 @@
 | 
				
			|||||||
 | 
					using FreeSql.DataAnnotations;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Tests.Dameng
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class DamengInsertOrUpdateTest
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        IFreeSql fsql => g.dameng;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnlyPrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou01>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 1 });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU01"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"") 
 | 
				
			||||||
 | 
					  values (t2.ID)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 1 });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU01"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"") 
 | 
				
			||||||
 | 
					  values (t2.ID)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 2 });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU01"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as ID FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"") 
 | 
				
			||||||
 | 
					  values (t2.ID)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new[] { new tbiou01 { id = 1 }, new tbiou01 { id = 2 }, new tbiou01 { id = 3 }, new tbiou01 { id = 4 } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU01"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2 FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3 FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4 FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"") 
 | 
				
			||||||
 | 
					  values (t2.ID)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new[] { new tbiou01 { id = 1 }, new tbiou01 { id = 2 }, new tbiou01 { id = 3 }, new tbiou01 { id = 4 } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU01"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2 FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3 FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4 FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"") 
 | 
				
			||||||
 | 
					  values (t2.ID)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou01
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou02>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU02"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '01' as NAME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU02"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '011' as NAME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU02"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as ID, '02' as NAME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "01" }, new tbiou02 { id = 2, name = "02" }, new tbiou02 { id = 3, name = "03" }, new tbiou02 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU02"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '01' as NAME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '02' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '03' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '04' FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "001" }, new tbiou02 { id = 2, name = "002" }, new tbiou02 { id = 3, name = "003" }, new tbiou02 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU02"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '001' as NAME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '002' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '003' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '004' FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou02>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou02
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_TwoPrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou03>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "01", name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU03"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID1, '01' as ID2, '01' as NAME FROM dual ) t2 ON (t1.""ID1"" = t2.ID1 AND t1.""ID2"" = t2.ID2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID1"", ""ID2"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID1, t2.ID2, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "02", name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU03"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID1, '02' as ID2, '011' as NAME FROM dual ) t2 ON (t1.""ID1"" = t2.ID1 AND t1.""ID2"" = t2.ID2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID1"", ""ID2"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID1, t2.ID2, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 2, id2 = "02", name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU03"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as ID1, '02' as ID2, '02' as NAME FROM dual ) t2 ON (t1.""ID1"" = t2.ID1 AND t1.""ID2"" = t2.ID2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID1"", ""ID2"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID1, t2.ID2, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "01" }, new tbiou03 { id1 = 2, id2 = "02", name = "02" }, new tbiou03 { id1 = 3, id2 = "03", name = "03" }, new tbiou03 { id1 = 4, id2 = "04", name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU03"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID1, '01' as ID2, '01' as NAME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '02', '02' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '03', '03' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '04', '04' FROM dual ) t2 ON (t1.""ID1"" = t2.ID1 AND t1.""ID2"" = t2.ID2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID1"", ""ID2"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID1, t2.ID2, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "001" }, new tbiou03 { id1 = 2, id2 = "02", name = "002" }, new tbiou03 { id1 = 3, id2 = "03", name = "003" }, new tbiou03 { id1 = 4, id2 = "04", name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU03"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID1, '01' as ID2, '001' as NAME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '02', '002' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '03', '003' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '04', '004' FROM dual ) t2 ON (t1.""ID1"" = t2.ID1 AND t1.""ID2"" = t2.ID2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID1"", ""ID2"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID1, t2.ID2, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou03>().Where(a => a.id1 == 1 && a.id2 == "01" || a.id1 == 2 && a.id2 == "02" || a.id1 == 3 && a.id2 == "03" || a.id1 == 4 && a.id2 == "04").ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id1).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou03
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public int id1 { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public string id2 { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimaryAndVersionAndCanUpdate()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou04>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU04"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '01' as NAME, 0 as VERSION, systimestamp as CREATETIME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME, ""VERSION"" = t1.""VERSION"" + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME, t2.VERSION, t2.CREATETIME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU04"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '011' as NAME, 0 as VERSION, systimestamp as CREATETIME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME, ""VERSION"" = t1.""VERSION"" + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME, t2.VERSION, t2.CREATETIME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU04"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as ID, '02' as NAME, 0 as VERSION, systimestamp as CREATETIME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME, ""VERSION"" = t1.""VERSION"" + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME, t2.VERSION, t2.CREATETIME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "01" }, new tbiou04 { id = 2, name = "02" }, new tbiou04 { id = 3, name = "03" }, new tbiou04 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU04"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '01' as NAME, 0 as VERSION, systimestamp as CREATETIME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '02', 0, systimestamp FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '03', 0, systimestamp FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '04', 0, systimestamp FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME, ""VERSION"" = t1.""VERSION"" + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME, t2.VERSION, t2.CREATETIME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "001" }, new tbiou04 { id = 2, name = "002" }, new tbiou04 { id = 3, name = "003" }, new tbiou04 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU04"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '001' as NAME, 0 as VERSION, systimestamp as CREATETIME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '002', 0, systimestamp FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '003', 0, systimestamp FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '004', 0, systimestamp FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME, ""VERSION"" = t1.""VERSION"" + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME, t2.VERSION, t2.CREATETIME)", sql);
 | 
				
			||||||
 | 
					            iou.ExecuteAffrows();
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou04>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou04
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsVersion = true)]
 | 
				
			||||||
 | 
					            public int version { get; set; }
 | 
				
			||||||
 | 
					            [Column(CanUpdate = false, ServerTime = DateTimeKind.Local)]
 | 
				
			||||||
 | 
					            public DateTime CreateTime { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,167 @@
 | 
				
			|||||||
 | 
					using FreeSql.DataAnnotations;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Tests.MySql
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class MySqlInsertOrUpdateTest
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        IFreeSql fsql => g.mysql;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou02>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou02`(`id`, `name`) VALUES(1, '01')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou02`(`id`, `name`) VALUES(1, '011')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(2, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou02`(`id`, `name`) VALUES(2, '02')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "01" }, new tbiou02 { id = 2, name = "02" }, new tbiou02 { id = 3, name = "03" }, new tbiou02 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou02`(`id`, `name`) VALUES(1, '01'), (2, '02'), (3, '03'), (4, '04')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(5, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "001" }, new tbiou02 { id = 2, name = "002" }, new tbiou02 { id = 3, name = "003" }, new tbiou02 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou02`(`id`, `name`) VALUES(1, '001'), (2, '002'), (3, '003'), (4, '004')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(8, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou02>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou02
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_TwoPrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou03>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "01", name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou03`(`id1`, `id2`, `name`) VALUES(1, '01', '01')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "01", name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou03`(`id1`, `id2`, `name`) VALUES(1, '01', '011')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(2, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 2, id2 = "02", name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou03`(`id1`, `id2`, `name`) VALUES(2, '02', '02')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "01" }, new tbiou03 { id1 = 2, id2 = "02", name = "02" }, new tbiou03 { id1 = 3, id2 = "03", name = "03" }, new tbiou03 { id1 = 4, id2 = "04", name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou03`(`id1`, `id2`, `name`) VALUES(1, '01', '01'), (2, '02', '02'), (3, '03', '03'), (4, '04', '04')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(5, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "001" }, new tbiou03 { id1 = 2, id2 = "02", name = "002" }, new tbiou03 { id1 = 3, id2 = "03", name = "003" }, new tbiou03 { id1 = 4, id2 = "04", name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou03`(`id1`, `id2`, `name`) VALUES(1, '01', '001'), (2, '02', '002'), (3, '03', '003'), (4, '04', '004')
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(8, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou03>().Where(a => a.id1 == 1 && a.id2 == "01" || a.id1 == 2 && a.id2 == "02" || a.id1 == 3 && a.id2 == "03" || a.id1 == 4 && a.id2 == "04").ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id1).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou03
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public int id1 { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public string id2 { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimaryAndVersionAndCanUpdate()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou04>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou04`(`id`, `name`, `version`, `CreateTime`) VALUES(1, '01', 0, now(3))
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`), 
 | 
				
			||||||
 | 
					`version` = `version` + 1", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou04`(`id`, `name`, `version`, `CreateTime`) VALUES(1, '011', 0, now(3))
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`), 
 | 
				
			||||||
 | 
					`version` = `version` + 1", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(2, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou04`(`id`, `name`, `version`, `CreateTime`) VALUES(2, '02', 0, now(3))
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`), 
 | 
				
			||||||
 | 
					`version` = `version` + 1", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "01" }, new tbiou04 { id = 2, name = "02" }, new tbiou04 { id = 3, name = "03" }, new tbiou04 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou04`(`id`, `name`, `version`, `CreateTime`) VALUES(1, '01', 0, now(3)), (2, '02', 0, now(3)), (3, '03', 0, now(3)), (4, '04', 0, now(3))
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`), 
 | 
				
			||||||
 | 
					`version` = `version` + 1", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(6, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "001" }, new tbiou04 { id = 2, name = "002" }, new tbiou04 { id = 3, name = "003" }, new tbiou04 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO `tbiou04`(`id`, `name`, `version`, `CreateTime`) VALUES(1, '001', 0, now(3)), (2, '002', 0, now(3)), (3, '003', 0, now(3)), (4, '004', 0, now(3))
 | 
				
			||||||
 | 
					ON DUPLICATE KEY UPDATE
 | 
				
			||||||
 | 
					`name` = VALUES(`name`), 
 | 
				
			||||||
 | 
					`version` = `version` + 1", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(8, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou04>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou04
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsVersion = true)]
 | 
				
			||||||
 | 
					            public int version { get; set; }
 | 
				
			||||||
 | 
					            [Column(CanUpdate = false, ServerTime = DateTimeKind.Local)]
 | 
				
			||||||
 | 
					            public DateTime CreateTime { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,323 @@
 | 
				
			|||||||
 | 
					using FreeSql.DataAnnotations;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Tests.Oracle
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class OracleInsertOrUpdateTest
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        IFreeSql fsql => g.oracle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnlyPrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou01>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 1 });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU01"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"") 
 | 
				
			||||||
 | 
					  values (t2.ID)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 1 });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU01"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"") 
 | 
				
			||||||
 | 
					  values (t2.ID)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(0, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 2 });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU01"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as ID FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"") 
 | 
				
			||||||
 | 
					  values (t2.ID)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new[] { new tbiou01 { id = 1 }, new tbiou01 { id = 2 }, new tbiou01 { id = 3 }, new tbiou01 { id = 4 } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU01"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2 FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3 FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4 FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"") 
 | 
				
			||||||
 | 
					  values (t2.ID)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(2, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new[] { new tbiou01 { id = 1 }, new tbiou01 { id = 2 }, new tbiou01 { id = 3 }, new tbiou01 { id = 4 } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU01"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2 FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3 FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4 FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"") 
 | 
				
			||||||
 | 
					  values (t2.ID)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(0, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou01
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou02>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU02"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '01' as NAME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU02"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '011' as NAME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU02"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as ID, '02' as NAME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "01" }, new tbiou02 { id = 2, name = "02" }, new tbiou02 { id = 3, name = "03" }, new tbiou02 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU02"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '01' as NAME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '02' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '03' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '04' FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "001" }, new tbiou02 { id = 2, name = "002" }, new tbiou02 { id = 3, name = "003" }, new tbiou02 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU02"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '001' as NAME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '002' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '003' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '004' FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou02>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou02
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_TwoPrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou03>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "01", name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU03"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID1, '01' as ID2, '01' as NAME FROM dual ) t2 ON (t1.""ID1"" = t2.ID1 AND t1.""ID2"" = t2.ID2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID1"", ""ID2"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID1, t2.ID2, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "02", name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU03"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID1, '02' as ID2, '011' as NAME FROM dual ) t2 ON (t1.""ID1"" = t2.ID1 AND t1.""ID2"" = t2.ID2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID1"", ""ID2"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID1, t2.ID2, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 2, id2 = "02", name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU03"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as ID1, '02' as ID2, '02' as NAME FROM dual ) t2 ON (t1.""ID1"" = t2.ID1 AND t1.""ID2"" = t2.ID2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID1"", ""ID2"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID1, t2.ID2, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "01" }, new tbiou03 { id1 = 2, id2 = "02", name = "02" }, new tbiou03 { id1 = 3, id2 = "03", name = "03" }, new tbiou03 { id1 = 4, id2 = "04", name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU03"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID1, '01' as ID2, '01' as NAME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '02', '02' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '03', '03' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '04', '04' FROM dual ) t2 ON (t1.""ID1"" = t2.ID1 AND t1.""ID2"" = t2.ID2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID1"", ""ID2"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID1, t2.ID2, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "001" }, new tbiou03 { id1 = 2, id2 = "02", name = "002" }, new tbiou03 { id1 = 3, id2 = "03", name = "003" }, new tbiou03 { id1 = 4, id2 = "04", name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU03"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID1, '01' as ID2, '001' as NAME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '02', '002' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '03', '003' FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '04', '004' FROM dual ) t2 ON (t1.""ID1"" = t2.ID1 AND t1.""ID2"" = t2.ID2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID1"", ""ID2"", ""NAME"") 
 | 
				
			||||||
 | 
					  values (t2.ID1, t2.ID2, t2.NAME)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou03>().Where(a => a.id1 == 1 && a.id2 == "01" || a.id1 == 2 && a.id2 == "02" || a.id1 == 3 && a.id2 == "03" || a.id1 == 4 && a.id2 == "04").ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id1).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou03
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public int id1 { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public string id2 { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimaryAndVersionAndCanUpdate()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou04>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU04"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '01' as NAME, 0 as VERSION, systimestamp as CREATETIME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME, ""VERSION"" = t1.""VERSION"" + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME, t2.VERSION, t2.CREATETIME)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU04"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '011' as NAME, 0 as VERSION, systimestamp as CREATETIME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME, ""VERSION"" = t1.""VERSION"" + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME, t2.VERSION, t2.CREATETIME)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU04"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as ID, '02' as NAME, 0 as VERSION, systimestamp as CREATETIME FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME, ""VERSION"" = t1.""VERSION"" + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME, t2.VERSION, t2.CREATETIME)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "01" }, new tbiou04 { id = 2, name = "02" }, new tbiou04 { id = 3, name = "03" }, new tbiou04 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU04"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '01' as NAME, 0 as VERSION, systimestamp as CREATETIME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '02', 0, systimestamp FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '03', 0, systimestamp FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '04', 0, systimestamp FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME, ""VERSION"" = t1.""VERSION"" + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME, t2.VERSION, t2.CREATETIME)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "001" }, new tbiou04 { id = 2, name = "002" }, new tbiou04 { id = 3, name = "003" }, new tbiou04 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO ""TBIOU04"" t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as ID, '001' as NAME, 0 as VERSION, systimestamp as CREATETIME FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, '002', 0, systimestamp FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, '003', 0, systimestamp FROM dual 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, '004', 0, systimestamp FROM dual ) t2 ON (t1.""ID"" = t2.ID) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set ""NAME"" = t2.NAME, ""VERSION"" = t1.""VERSION"" + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert (""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") 
 | 
				
			||||||
 | 
					  values (t2.ID, t2.NAME, t2.VERSION, t2.CREATETIME)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou04>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou04
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsVersion = true)]
 | 
				
			||||||
 | 
					            public int version { get; set; }
 | 
				
			||||||
 | 
					            [Column(CanUpdate = false, ServerTime = DateTimeKind.Local)]
 | 
				
			||||||
 | 
					            public DateTime CreateTime { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,205 @@
 | 
				
			|||||||
 | 
					using FreeSql.DataAnnotations;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Tests.PostgreSQL
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class PostgreSQLInsertOrUpdateTest
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        IFreeSql fsql => g.pgsql;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnlyPrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou01>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 1 });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou01""(""id"") VALUES(1)
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO NOTHING", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 1 });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou01""(""id"") VALUES(1)
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO NOTHING", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(0, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 2 });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou01""(""id"") VALUES(2)
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO NOTHING", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new[] { new tbiou01 { id = 1 }, new tbiou01 { id = 2 }, new tbiou01 { id = 3 }, new tbiou01 { id = 4 } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou01""(""id"") VALUES(1), (2), (3), (4)
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO NOTHING", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(2, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new[] { new tbiou01 { id = 1 }, new tbiou01 { id = 2 }, new tbiou01 { id = 3 }, new tbiou01 { id = 4 } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou01""(""id"") VALUES(1), (2), (3), (4)
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO NOTHING", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(0, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou01
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou02>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou02""(""id"", ""name"") VALUES(1, '01')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name""", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou02""(""id"", ""name"") VALUES(1, '011')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name""", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou02""(""id"", ""name"") VALUES(2, '02')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name""", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "01" }, new tbiou02 { id = 2, name = "02" }, new tbiou02 { id = 3, name = "03" }, new tbiou02 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou02""(""id"", ""name"") VALUES(1, '01'), (2, '02'), (3, '03'), (4, '04')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name""", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "001" }, new tbiou02 { id = 2, name = "002" }, new tbiou02 { id = 3, name = "003" }, new tbiou02 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou02""(""id"", ""name"") VALUES(1, '001'), (2, '002'), (3, '003'), (4, '004')
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name""", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou02>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou02
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_TwoPrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou03>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "01", name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou03""(""id1"", ""id2"", ""name"") VALUES(1, '01', '01')
 | 
				
			||||||
 | 
					ON CONFLICT(""id1"", ""id2"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name""", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "02", name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou03""(""id1"", ""id2"", ""name"") VALUES(1, '02', '011')
 | 
				
			||||||
 | 
					ON CONFLICT(""id1"", ""id2"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name""", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 2, id2 = "02", name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou03""(""id1"", ""id2"", ""name"") VALUES(2, '02', '02')
 | 
				
			||||||
 | 
					ON CONFLICT(""id1"", ""id2"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name""", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "01" }, new tbiou03 { id1 = 2, id2 = "02", name = "02" }, new tbiou03 { id1 = 3, id2 = "03", name = "03" }, new tbiou03 { id1 = 4, id2 = "04", name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou03""(""id1"", ""id2"", ""name"") VALUES(1, '01', '01'), (2, '02', '02'), (3, '03', '03'), (4, '04', '04')
 | 
				
			||||||
 | 
					ON CONFLICT(""id1"", ""id2"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name""", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "001" }, new tbiou03 { id1 = 2, id2 = "02", name = "002" }, new tbiou03 { id1 = 3, id2 = "03", name = "003" }, new tbiou03 { id1 = 4, id2 = "04", name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou03""(""id1"", ""id2"", ""name"") VALUES(1, '01', '001'), (2, '02', '002'), (3, '03', '003'), (4, '04', '004')
 | 
				
			||||||
 | 
					ON CONFLICT(""id1"", ""id2"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name""", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou03>().Where(a => a.id1 == 1 && a.id2 == "01" || a.id1 == 2 && a.id2 == "02" || a.id1 == 3 && a.id2 == "03" || a.id1 == 4 && a.id2 == "04").ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id1).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou03
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public int id1 { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public string id2 { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimaryAndVersionAndCanUpdate()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou04>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou04""(""id"", ""name"", ""version"", ""createtime"") VALUES(1, '01', 0, current_timestamp)
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name"", 
 | 
				
			||||||
 | 
					""version"" = ""tbiou04"".""version"" + 1", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou04""(""id"", ""name"", ""version"", ""createtime"") VALUES(1, '011', 0, current_timestamp)
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name"", 
 | 
				
			||||||
 | 
					""version"" = ""tbiou04"".""version"" + 1", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou04""(""id"", ""name"", ""version"", ""createtime"") VALUES(2, '02', 0, current_timestamp)
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name"", 
 | 
				
			||||||
 | 
					""version"" = ""tbiou04"".""version"" + 1", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "01" }, new tbiou04 { id = 2, name = "02" }, new tbiou04 { id = 3, name = "03" }, new tbiou04 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou04""(""id"", ""name"", ""version"", ""createtime"") VALUES(1, '01', 0, current_timestamp), (2, '02', 0, current_timestamp), (3, '03', 0, current_timestamp), (4, '04', 0, current_timestamp)
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name"", 
 | 
				
			||||||
 | 
					""version"" = ""tbiou04"".""version"" + 1", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "001" }, new tbiou04 { id = 2, name = "002" }, new tbiou04 { id = 3, name = "003" }, new tbiou04 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"INSERT INTO ""tbiou04""(""id"", ""name"", ""version"", ""createtime"") VALUES(1, '001', 0, current_timestamp), (2, '002', 0, current_timestamp), (3, '003', 0, current_timestamp), (4, '004', 0, current_timestamp)
 | 
				
			||||||
 | 
					ON CONFLICT(""id"") DO UPDATE SET
 | 
				
			||||||
 | 
					""name"" = EXCLUDED.""name"", 
 | 
				
			||||||
 | 
					""version"" = ""tbiou04"".""version"" + 1", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou04>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou04
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsVersion = true)]
 | 
				
			||||||
 | 
					            public int version { get; set; }
 | 
				
			||||||
 | 
					            [Column(CanUpdate = false, ServerTime = DateTimeKind.Local)]
 | 
				
			||||||
 | 
					            public DateTime CreateTime { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,325 @@
 | 
				
			|||||||
 | 
					using FreeSql.DataAnnotations;
 | 
				
			||||||
 | 
					using FreeSql.Tests.DataContext.SqlServer;
 | 
				
			||||||
 | 
					using SaleIDO.Entity.Storeage;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Tests.SqlServer
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class SqlServerInsertOrUpdateTest
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        IFreeSql fsql => g.sqlserver;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnlyPrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou01>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 1 });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou01] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id]) 
 | 
				
			||||||
 | 
					  values (t2.id);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 1 });
 | 
				
			||||||
 | 
					            sql = iou.ToSql(); 
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou01] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id]) 
 | 
				
			||||||
 | 
					  values (t2.id);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(0, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 2 });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou01] t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as id ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id]) 
 | 
				
			||||||
 | 
					  values (t2.id);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new[] { new tbiou01 { id = 1 }, new tbiou01 { id = 2 }, new tbiou01 { id = 3 }, new tbiou01 { id = 4 } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou01] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4 ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id]) 
 | 
				
			||||||
 | 
					  values (t2.id);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(2, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new[] { new tbiou01 { id = 1 }, new tbiou01 { id = 2 }, new tbiou01 { id = 3 }, new tbiou01 { id = 4 } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql(); 
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou01] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4 ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id]) 
 | 
				
			||||||
 | 
					  values (t2.id);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(0, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou01
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou02>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou02] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id, N'01' as name ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id], [name]) 
 | 
				
			||||||
 | 
					  values (t2.id, t2.name);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou02] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id, N'011' as name ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id], [name]) 
 | 
				
			||||||
 | 
					  values (t2.id, t2.name);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou02] t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as id, N'02' as name ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id], [name]) 
 | 
				
			||||||
 | 
					  values (t2.id, t2.name);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "01" }, new tbiou02 { id = 2, name = "02" }, new tbiou02 { id = 3, name = "03" }, new tbiou02 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou02] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id, N'01' as name 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, N'02' 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, N'03' 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, N'04' ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id], [name]) 
 | 
				
			||||||
 | 
					  values (t2.id, t2.name);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "001" }, new tbiou02 { id = 2, name = "002" }, new tbiou02 { id = 3, name = "003" }, new tbiou02 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou02] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id, N'001' as name 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, N'002' 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, N'003' 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, N'004' ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id], [name]) 
 | 
				
			||||||
 | 
					  values (t2.id, t2.name);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou02>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou02
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_TwoPrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou03>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "01", name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou03] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id1, N'01' as id2, N'01' as name ) t2 ON (t1.[id1] = t2.id1 AND t1.[id2] = t2.id2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id1], [id2], [name]) 
 | 
				
			||||||
 | 
					  values (t2.id1, t2.id2, t2.name);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "02", name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou03] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id1, N'02' as id2, N'011' as name ) t2 ON (t1.[id1] = t2.id1 AND t1.[id2] = t2.id2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id1], [id2], [name]) 
 | 
				
			||||||
 | 
					  values (t2.id1, t2.id2, t2.name);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 2, id2 = "02", name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou03] t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as id1, N'02' as id2, N'02' as name ) t2 ON (t1.[id1] = t2.id1 AND t1.[id2] = t2.id2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id1], [id2], [name]) 
 | 
				
			||||||
 | 
					  values (t2.id1, t2.id2, t2.name);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "01" }, new tbiou03 { id1 = 2, id2 = "02", name = "02" }, new tbiou03 { id1 = 3, id2 = "03", name = "03" }, new tbiou03 { id1 = 4, id2 = "04", name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou03] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id1, N'01' as id2, N'01' as name 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, N'02', N'02' 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, N'03', N'03' 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, N'04', N'04' ) t2 ON (t1.[id1] = t2.id1 AND t1.[id2] = t2.id2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id1], [id2], [name]) 
 | 
				
			||||||
 | 
					  values (t2.id1, t2.id2, t2.name);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "001" }, new tbiou03 { id1 = 2, id2 = "02", name = "002" }, new tbiou03 { id1 = 3, id2 = "03", name = "003" }, new tbiou03 { id1 = 4, id2 = "04", name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou03] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id1, N'01' as id2, N'001' as name 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, N'02', N'002' 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, N'03', N'003' 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, N'04', N'004' ) t2 ON (t1.[id1] = t2.id1 AND t1.[id2] = t2.id2) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id1], [id2], [name]) 
 | 
				
			||||||
 | 
					  values (t2.id1, t2.id2, t2.name);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou03>().Where(a => a.id1 == 1 && a.id2 == "01" || a.id1 == 2 && a.id2 == "02" || a.id1 == 3 && a.id2 == "03" || a.id1 == 4 && a.id2 == "04").ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id1).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou03
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public int id1 { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public string id2 { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimaryAndVersionAndCanUpdate()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou04>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou04] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id, N'01' as name, 0 as version, getdate() as CreateTime ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name, [version] = t1.[version] + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id], [name], [version], [CreateTime]) 
 | 
				
			||||||
 | 
					  values (t2.id, t2.name, t2.version, t2.CreateTime);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou04] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id, N'011' as name, 0 as version, getdate() as CreateTime ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name, [version] = t1.[version] + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id], [name], [version], [CreateTime]) 
 | 
				
			||||||
 | 
					  values (t2.id, t2.name, t2.version, t2.CreateTime);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou04] t1 
 | 
				
			||||||
 | 
					USING (SELECT 2 as id, N'02' as name, 0 as version, getdate() as CreateTime ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name, [version] = t1.[version] + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id], [name], [version], [CreateTime]) 
 | 
				
			||||||
 | 
					  values (t2.id, t2.name, t2.version, t2.CreateTime);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "01" }, new tbiou04 { id = 2, name = "02" }, new tbiou04 { id = 3, name = "03" }, new tbiou04 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou04] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id, N'01' as name, 0 as version, getdate() as CreateTime 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, N'02', 0, getdate() 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, N'03', 0, getdate() 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, N'04', 0, getdate() ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name, [version] = t1.[version] + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id], [name], [version], [CreateTime]) 
 | 
				
			||||||
 | 
					  values (t2.id, t2.name, t2.version, t2.CreateTime);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "001" }, new tbiou04 { id = 2, name = "002" }, new tbiou04 { id = 3, name = "003" }, new tbiou04 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"MERGE INTO [tbiou04] t1 
 | 
				
			||||||
 | 
					USING (SELECT 1 as id, N'001' as name, 0 as version, getdate() as CreateTime 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 2, N'002', 0, getdate() 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 3, N'003', 0, getdate() 
 | 
				
			||||||
 | 
					UNION ALL
 | 
				
			||||||
 | 
					 SELECT 4, N'004', 0, getdate() ) t2 ON (t1.[id] = t2.id) 
 | 
				
			||||||
 | 
					WHEN MATCHED THEN 
 | 
				
			||||||
 | 
					  update set [name] = t2.name, [version] = t1.[version] + 1 
 | 
				
			||||||
 | 
					WHEN NOT MATCHED THEN 
 | 
				
			||||||
 | 
					  insert ([id], [name], [version], [CreateTime]) 
 | 
				
			||||||
 | 
					  values (t2.id, t2.name, t2.version, t2.CreateTime);", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou04>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou04
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsVersion = true)]
 | 
				
			||||||
 | 
					            public int version { get; set; }
 | 
				
			||||||
 | 
					            [Column(CanUpdate = false, ServerTime = DateTimeKind.Local)]
 | 
				
			||||||
 | 
					            public DateTime CreateTime { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,165 @@
 | 
				
			|||||||
 | 
					using FreeSql.DataAnnotations;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Tests.Sqlite
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class SqliteInsertOrUpdateTest
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        IFreeSql fsql => g.sqlite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnlyPrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou01>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 1 });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"REPLACE INTO ""tbiou01""(""id"") VALUES(1)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 1 });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"REPLACE INTO ""tbiou01""(""id"") VALUES(1)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new tbiou01 { id = 2 });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"REPLACE INTO ""tbiou01""(""id"") VALUES(2)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new[] { new tbiou01 { id = 1 }, new tbiou01 { id = 2 }, new tbiou01 { id = 3 }, new tbiou01 { id = 4 } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"REPLACE INTO ""tbiou01""(""id"") VALUES(1), (2), (3), (4)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou01>().SetSource(new[] { new tbiou01 { id = 1 }, new tbiou01 { id = 2 }, new tbiou01 { id = 3 }, new tbiou01 { id = 4 } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"REPLACE INTO ""tbiou01""(""id"") VALUES(1), (2), (3), (4)", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou01
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou02>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"REPLACE INTO ""tbiou02""(""id"", ""name"") VALUES(1, '01')", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"REPLACE INTO ""tbiou02""(""id"", ""name"") VALUES(1, '011')", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new tbiou02 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"REPLACE INTO ""tbiou02""(""id"", ""name"") VALUES(2, '02')", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "01" }, new tbiou02 { id = 2, name = "02" }, new tbiou02 { id = 3, name = "03" }, new tbiou02 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"REPLACE INTO ""tbiou02""(""id"", ""name"") VALUES(1, '01'), (2, '02'), (3, '03'), (4, '04')", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou02>().SetSource(new[] { new tbiou02 { id = 1, name = "001" }, new tbiou02 { id = 2, name = "002" }, new tbiou02 { id = 3, name = "003" }, new tbiou02 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"REPLACE INTO ""tbiou02""(""id"", ""name"") VALUES(1, '001'), (2, '002'), (3, '003'), (4, '004')", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou02>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou02
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_TwoPrimary()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou03>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "01", name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"REPLACE INTO ""tbiou03""(""id1"", ""id2"", ""name"") VALUES(1, '01', '01')", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 1, id2 = "02", name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"REPLACE INTO ""tbiou03""(""id1"", ""id2"", ""name"") VALUES(1, '02', '011')", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new tbiou03 { id1 = 2, id2 = "02", name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"REPLACE INTO ""tbiou03""(""id1"", ""id2"", ""name"") VALUES(2, '02', '02')", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "01" }, new tbiou03 { id1 = 2, id2 = "02", name = "02" }, new tbiou03 { id1 = 3, id2 = "03", name = "03" }, new tbiou03 { id1 = 4, id2 = "04", name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"REPLACE INTO ""tbiou03""(""id1"", ""id2"", ""name"") VALUES(1, '01', '01'), (2, '02', '02'), (3, '03', '03'), (4, '04', '04')", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou03>().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "001" }, new tbiou03 { id1 = 2, id2 = "02", name = "002" }, new tbiou03 { id1 = 3, id2 = "03", name = "003" }, new tbiou03 { id1 = 4, id2 = "04", name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"REPLACE INTO ""tbiou03""(""id1"", ""id2"", ""name"") VALUES(1, '01', '001'), (2, '02', '002'), (3, '03', '003'), (4, '04', '004')", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou03>().Where(a => a.id1 == 1 && a.id2 == "01" || a.id1 == 2 && a.id2 == "02" || a.id1 == 3 && a.id2 == "03" || a.id1 == 4 && a.id2 == "04").ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id1).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou03
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public int id1 { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsPrimary = true)]
 | 
				
			||||||
 | 
					            public string id2 { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void InsertOrUpdate_OnePrimaryAndVersionAndCanUpdate()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fsql.Delete<tbiou04>().Where("1=1").ExecuteAffrows();
 | 
				
			||||||
 | 
					            var iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "01" });
 | 
				
			||||||
 | 
					            var sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"REPLACE INTO ""tbiou04""(""id"", ""name"", ""version"", ""CreateTime"") VALUES(1, '01', 0, datetime(current_timestamp,'localtime'))", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 1, name = "011" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"REPLACE INTO ""tbiou04""(""id"", ""name"", ""version"", ""CreateTime"") VALUES(1, '011', 0, datetime(current_timestamp,'localtime'))", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new tbiou04 { id = 2, name = "02" });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"REPLACE INTO ""tbiou04""(""id"", ""name"", ""version"", ""CreateTime"") VALUES(2, '02', 0, datetime(current_timestamp,'localtime'))", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(1, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "01" }, new tbiou04 { id = 2, name = "02" }, new tbiou04 { id = 3, name = "03" }, new tbiou04 { id = 4, name = "04" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"REPLACE INTO ""tbiou04""(""id"", ""name"", ""version"", ""CreateTime"") VALUES(1, '01', 0, datetime(current_timestamp,'localtime')), (2, '02', 0, datetime(current_timestamp,'localtime')), (3, '03', 0, datetime(current_timestamp,'localtime')), (4, '04', 0, datetime(current_timestamp,'localtime'))", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iou = fsql.InsertOrUpdate<tbiou04>().SetSource(new[] { new tbiou04 { id = 1, name = "001" }, new tbiou04 { id = 2, name = "002" }, new tbiou04 { id = 3, name = "003" }, new tbiou04 { id = 4, name = "004" } });
 | 
				
			||||||
 | 
					            sql = iou.ToSql();
 | 
				
			||||||
 | 
					            Assert.Equal(@"REPLACE INTO ""tbiou04""(""id"", ""name"", ""version"", ""CreateTime"") VALUES(1, '001', 0, datetime(current_timestamp,'localtime')), (2, '002', 0, datetime(current_timestamp,'localtime')), (3, '003', 0, datetime(current_timestamp,'localtime')), (4, '004', 0, datetime(current_timestamp,'localtime'))", sql);
 | 
				
			||||||
 | 
					            Assert.Equal(4, iou.ExecuteAffrows());
 | 
				
			||||||
 | 
					            var lst = fsql.Select<tbiou04>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
 | 
				
			||||||
 | 
					            Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class tbiou04
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public int id { get; set; }
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					            [Column(IsVersion = true)]
 | 
				
			||||||
 | 
					            public int version { get; set; }
 | 
				
			||||||
 | 
					            [Column(CanUpdate = false, ServerTime = DateTimeKind.Local)]
 | 
				
			||||||
 | 
					            public DateTime CreateTime { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1011,6 +1011,60 @@
 | 
				
			|||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IInsertOrUpdate`1.WithTransaction(System.Data.Common.DbTransaction)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            指定事务对象
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="transaction"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IInsertOrUpdate`1.WithConnection(System.Data.Common.DbConnection)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            指定事务对象
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="connection"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IInsertOrUpdate`1.SetSource(`0)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            添加或更新,设置实体
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="source">实体</param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IInsertOrUpdate`1.SetSource(System.Collections.Generic.IEnumerable{`0})">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            添加或更新,设置实体集合
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="source">实体集合</param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IInsertOrUpdate`1.AsTable(System.Func{System.String,System.String})">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            设置表名规则,可用于分库/分表,参数1:默认表名;返回值:新表名;
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="tableRule"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IInsertOrUpdate`1.AsType(System.Type)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            动态Type,在使用 Update<object> 后使用本方法,指定实体类型
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="entityType"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IInsertOrUpdate`1.ToSql">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            返回即将执行的SQL语句
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IInsertOrUpdate`1.ExecuteAffrows">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            执行SQL语句,返回影响的行数
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
        <member name="F:FreeSql.FieldAliasOptions.AsIndex">
 | 
					        <member name="F:FreeSql.FieldAliasOptions.AsIndex">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            自动产生 as1, as2, as3 .... 字段别名<para></para>
 | 
					            自动产生 as1, as2, as3 .... 字段别名<para></para>
 | 
				
			||||||
@@ -2337,137 +2391,6 @@
 | 
				
			|||||||
            <param name="parms"></param>
 | 
					            <param name="parms"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteReaderAsync(System.Func{System.Data.Common.DbDataReader,System.Threading.Tasks.Task},System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            查询,若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="readerHander"></param>
 | 
					 | 
				
			||||||
            <param name="cmdType"></param>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="cmdParms"></param>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteReaderAsync(System.Func{System.Data.Common.DbDataReader,System.Threading.Tasks.Task},System.String,System.Object)">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            查询,ExecuteReaderAsync(dr => {}, "select * from user where age > ?age", new { age = 25 })
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="parms"></param>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteArrayAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            查询
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="cmdParms"></param>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteArrayAsync(System.String,System.Object)">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            查询,ExecuteArrayAsync("select * from user where age > ?age", new { age = 25 })
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="parms"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteDataSetAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            查询
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="cmdParms"></param>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteDataSetAsync(System.String,System.Object)">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            查询,ExecuteDataSetAsync("select * from user where age > ?age; select 2", new { age = 25 })
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="parms"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteDataTableAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            查询
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="cmdParms"></param>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteDataTableAsync(System.String,System.Object)">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            查询,ExecuteDataTableAsync("select * from user where age > ?age", new { age = 25 })
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="parms"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteNonQueryAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            在【主库】执行
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="cmdType"></param>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="cmdParms"></param>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteNonQueryAsync(System.String,System.Object)">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            在【主库】执行,ExecuteNonQueryAsync("delete from user where age > ?age", new { age = 25 })
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="parms"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteScalarAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            在【主库】执行
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="cmdType"></param>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="cmdParms"></param>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteScalarAsync(System.String,System.Object)">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            在【主库】执行,ExecuteScalarAsync("select 1 from user where age > ?age", new { age = 25 })
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="parms"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.QueryAsync``1(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            执行SQL返回对象集合,QueryAsync<User>("select * from user where age > ?age", new SqlParameter { ParameterName = "age", Value = 25 })
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <typeparam name="T"></typeparam>
 | 
					 | 
				
			||||||
            <param name="cmdType"></param>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="cmdParms"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.QueryAsync``1(System.String,System.Object)">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            执行SQL返回对象集合,QueryAsync<User>("select * from user where age > ?age", new { age = 25 })
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <typeparam name="T"></typeparam>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="parms"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.QueryAsync``2(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            执行SQL返回对象集合,Query<User>("select * from user where age > ?age; select * from address", new SqlParameter { ParameterName = "age", Value = 25 })
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <typeparam name="T1"></typeparam>
 | 
					 | 
				
			||||||
            <param name="cmdType"></param>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="cmdParms"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.QueryAsync``2(System.String,System.Object)">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            执行SQL返回对象集合,Query<User>("select * from user where age > ?age; select * from address", new { age = 25 })
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <typeparam name="T1"></typeparam>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="parms"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="E:FreeSql.IAop.ParseExpression">
 | 
					        <member name="E:FreeSql.IAop.ParseExpression">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            可自定义解析表达式
 | 
					            可自定义解析表达式
 | 
				
			||||||
@@ -3063,12 +2986,6 @@
 | 
				
			|||||||
            <param name="timeout">超时</param>
 | 
					            <param name="timeout">超时</param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:FreeSql.Internal.ObjectPool.IObjectPool`1.GetAsync">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            获取资源
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.Internal.ObjectPool.IObjectPool`1.Return(FreeSql.Internal.ObjectPool.Object{`0},System.Boolean)">
 | 
					        <member name="M:FreeSql.Internal.ObjectPool.IObjectPool`1.Return(FreeSql.Internal.ObjectPool.Object{`0},System.Boolean)">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            使用完毕后,归还资源
 | 
					            使用完毕后,归还资源
 | 
				
			||||||
@@ -3139,12 +3056,6 @@
 | 
				
			|||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <param name="obj">资源对象</param>
 | 
					            <param name="obj">资源对象</param>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:FreeSql.Internal.ObjectPool.IPolicy`1.OnGetAsync(FreeSql.Internal.ObjectPool.Object{`0})">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            从对象池获取对象成功的时候触发,通过该方法统计或初始化对象
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="obj">资源对象</param>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.Internal.ObjectPool.IPolicy`1.OnReturn(FreeSql.Internal.ObjectPool.Object{`0})">
 | 
					        <member name="M:FreeSql.Internal.ObjectPool.IPolicy`1.OnReturn(FreeSql.Internal.ObjectPool.Object{`0})">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            归还对象给对象池的时候触发
 | 
					            归还对象给对象池的时候触发
 | 
				
			||||||
@@ -3685,6 +3596,19 @@
 | 
				
			|||||||
            <param name="source"></param>
 | 
					            <param name="source"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:IFreeSql.InsertOrUpdate``1">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            插入或更新数据<para></para>
 | 
				
			||||||
 | 
					            MySql: on duplicate key update<para></para>
 | 
				
			||||||
 | 
					            PostgreSQL: on conflict do update<para></para>
 | 
				
			||||||
 | 
					            SqlServer: merge into<para></para>
 | 
				
			||||||
 | 
					            Oracle: merge into<para></para>
 | 
				
			||||||
 | 
					            Sqlite: replace into<para></para>
 | 
				
			||||||
 | 
					            Dameng: merge into<para></para>
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <typeparam name="T1"></typeparam>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
        <member name="M:IFreeSql.Update``1">
 | 
					        <member name="M:IFreeSql.Update``1">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            修改数据
 | 
					            修改数据
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										66
									
								
								FreeSql/Interface/Curd/IInsertOrUpdate.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								FreeSql/Interface/Curd/IInsertOrUpdate.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Data.Common;
 | 
				
			||||||
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public interface IInsertOrUpdate<T1> where T1 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 指定事务对象
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="transaction"></param>
 | 
				
			||||||
 | 
					        /// <returns></returns>
 | 
				
			||||||
 | 
					        IInsertOrUpdate<T1> WithTransaction(DbTransaction transaction);
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 指定事务对象
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="connection"></param>
 | 
				
			||||||
 | 
					        /// <returns></returns>
 | 
				
			||||||
 | 
					        IInsertOrUpdate<T1> WithConnection(DbConnection connection);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 添加或更新,设置实体
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="source">实体</param>
 | 
				
			||||||
 | 
					        /// <returns></returns>
 | 
				
			||||||
 | 
					        IInsertOrUpdate<T1> SetSource(T1 source);
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 添加或更新,设置实体集合
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="source">实体集合</param>
 | 
				
			||||||
 | 
					        /// <returns></returns>
 | 
				
			||||||
 | 
					        IInsertOrUpdate<T1> SetSource(IEnumerable<T1> source);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 设置表名规则,可用于分库/分表,参数1:默认表名;返回值:新表名;
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="tableRule"></param>
 | 
				
			||||||
 | 
					        /// <returns></returns>
 | 
				
			||||||
 | 
					        IInsertOrUpdate<T1> AsTable(Func<string, string> tableRule);
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 动态Type,在使用 Update<object> 后使用本方法,指定实体类型
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="entityType"></param>
 | 
				
			||||||
 | 
					        /// <returns></returns>
 | 
				
			||||||
 | 
					        IInsertOrUpdate<T1> AsType(Type entityType);
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 返回即将执行的SQL语句
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <returns></returns>
 | 
				
			||||||
 | 
					        string ToSql();
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 执行SQL语句,返回影响的行数
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <returns></returns>
 | 
				
			||||||
 | 
					        int ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if net40
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        Task<int> ExecuteAffrowsAsync();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -201,7 +201,7 @@ namespace FreeSql.Aop
 | 
				
			|||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        public DbParameter[] DbParms { get; }
 | 
					        public DbParameter[] DbParms { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    public enum CurdType { Select, Delete, Update, Insert }
 | 
					    public enum CurdType { Select, Delete, Update, Insert, InsertOrUpdate }
 | 
				
			||||||
    public class CurdAfterEventArgs : CurdBeforeEventArgs
 | 
					    public class CurdAfterEventArgs : CurdBeforeEventArgs
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public CurdAfterEventArgs(CurdBeforeEventArgs before, Exception exception, object executeResult) :
 | 
					        public CurdAfterEventArgs(CurdBeforeEventArgs before, Exception exception, object executeResult) :
 | 
				
			||||||
@@ -324,7 +324,7 @@ namespace FreeSql.Aop
 | 
				
			|||||||
        private object _value;
 | 
					        private object _value;
 | 
				
			||||||
        public bool IsChanged { get; private set; }
 | 
					        public bool IsChanged { get; private set; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    public enum AuditValueType { Update, Insert }
 | 
					    public enum AuditValueType { Update, Insert, InsertOrUpdate }
 | 
				
			||||||
    #endregion
 | 
					    #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #region CommandBefore/After
 | 
					    #region CommandBefore/After
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,6 +44,19 @@ public interface IFreeSql : IDisposable
 | 
				
			|||||||
    /// <returns></returns>
 | 
					    /// <returns></returns>
 | 
				
			||||||
    IInsert<T1> Insert<T1>(IEnumerable<T1> source) where T1 : class;
 | 
					    IInsert<T1> Insert<T1>(IEnumerable<T1> source) where T1 : class;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 插入或更新数据<para></para>
 | 
				
			||||||
 | 
					    /// MySql: on duplicate key update<para></para>
 | 
				
			||||||
 | 
					    /// PostgreSQL: on conflict do update<para></para>
 | 
				
			||||||
 | 
					    /// SqlServer: merge into<para></para>
 | 
				
			||||||
 | 
					    /// Oracle: merge into<para></para>
 | 
				
			||||||
 | 
					    /// Sqlite: replace into<para></para>
 | 
				
			||||||
 | 
					    /// Dameng: merge into<para></para>
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <typeparam name="T1"></typeparam>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 修改数据
 | 
					    /// 修改数据
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										222
									
								
								FreeSql/Internal/CommonProvider/InsertOrUpdateProvider.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								FreeSql/Internal/CommonProvider/InsertOrUpdateProvider.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,222 @@
 | 
				
			|||||||
 | 
					using FreeSql.Extensions.EntityUtil;
 | 
				
			||||||
 | 
					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.Reflection;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Internal.CommonProvider
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public abstract partial class InsertOrUpdateProvider<T1> : IInsertOrUpdate<T1> where T1 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        protected IFreeSql _orm;
 | 
				
			||||||
 | 
					        protected CommonUtils _commonUtils;
 | 
				
			||||||
 | 
					        protected CommonExpression _commonExpression;
 | 
				
			||||||
 | 
					        protected List<T1> _source = new List<T1>();
 | 
				
			||||||
 | 
					        protected Dictionary<string, bool> _auditValueChangedDict = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
 | 
				
			||||||
 | 
					        protected TableInfo _table;
 | 
				
			||||||
 | 
					        protected Func<string, string> _tableRule;
 | 
				
			||||||
 | 
					        protected DbParameter[] _params;
 | 
				
			||||||
 | 
					        protected DbTransaction _transaction;
 | 
				
			||||||
 | 
					        protected DbConnection _connection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public InsertOrUpdateProvider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _orm = orm;
 | 
				
			||||||
 | 
					            _commonUtils = commonUtils;
 | 
				
			||||||
 | 
					            _commonExpression = commonExpression;
 | 
				
			||||||
 | 
					            _table = _commonUtils.GetTableByEntity(typeof(T1));
 | 
				
			||||||
 | 
					            if (_orm.CodeFirst.IsAutoSyncStructure && typeof(T1) != typeof(object)) _orm.CodeFirst.SyncStructure<T1>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected void ClearData()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _source.Clear();
 | 
				
			||||||
 | 
					            _auditValueChangedDict.Clear();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IInsertOrUpdate<T1> WithTransaction(DbTransaction transaction)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _transaction = transaction;
 | 
				
			||||||
 | 
					            _connection = _transaction?.Connection;
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public IInsertOrUpdate<T1> WithConnection(DbConnection connection)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (_transaction?.Connection != connection) _transaction = null;
 | 
				
			||||||
 | 
					            _connection = connection;
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static void AuditDataValue(object sender, IEnumerable<T1> data, IFreeSql orm, TableInfo table, Dictionary<string, bool> changedDict)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (data?.Any() != true) return;
 | 
				
			||||||
 | 
					            if (orm.Aop.AuditValueHandler == null) return;
 | 
				
			||||||
 | 
					            foreach (var d in data)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (d == null) continue;
 | 
				
			||||||
 | 
					                foreach (var col in table.Columns.Values)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    object val = col.GetMapValue(d);
 | 
				
			||||||
 | 
					                    var auditArgs = new Aop.AuditValueEventArgs(Aop.AuditValueType.InsertOrUpdate, col, table.Properties[col.CsName], val);
 | 
				
			||||||
 | 
					                    orm.Aop.AuditValueHandler(sender, auditArgs);
 | 
				
			||||||
 | 
					                    if (auditArgs.IsChanged)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        col.SetMapValue(d, val = auditArgs.Value);
 | 
				
			||||||
 | 
					                        if (changedDict != null && changedDict.ContainsKey(col.Attribute.Name) == false)
 | 
				
			||||||
 | 
					                            changedDict.Add(col.Attribute.Name, true);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public static void AuditDataValue(object sender, T1 data, IFreeSql orm, TableInfo table, Dictionary<string, bool> changedDict)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (orm.Aop.AuditValueHandler == null) return;
 | 
				
			||||||
 | 
					            if (data == null) return;
 | 
				
			||||||
 | 
					            if (typeof(T1) == typeof(object) && new[] { table.Type, table.TypeLazy }.Contains(data.GetType()) == false)
 | 
				
			||||||
 | 
					                throw new Exception($"操作的数据类型({data.GetType().DisplayCsharp()}) 与 AsType({table.Type.DisplayCsharp()}) 不一致,请检查。");
 | 
				
			||||||
 | 
					            foreach (var col in table.Columns.Values)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                object val = col.GetMapValue(data);
 | 
				
			||||||
 | 
					                var auditArgs = new Aop.AuditValueEventArgs(Aop.AuditValueType.InsertOrUpdate, col, table.Properties[col.CsName], val);
 | 
				
			||||||
 | 
					                orm.Aop.AuditValueHandler(sender, auditArgs);
 | 
				
			||||||
 | 
					                if (auditArgs.IsChanged)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    col.SetMapValue(data, val = auditArgs.Value);
 | 
				
			||||||
 | 
					                    if (changedDict != null && changedDict.ContainsKey(col.Attribute.Name) == false)
 | 
				
			||||||
 | 
					                        changedDict.Add(col.Attribute.Name, true);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IInsertOrUpdate<T1> SetSource(T1 source) => this.SetSource(new[] { source });
 | 
				
			||||||
 | 
					        public IInsertOrUpdate<T1> SetSource(IEnumerable<T1> source)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (source == null || source.Any() == false) return this;
 | 
				
			||||||
 | 
					            AuditDataValue(this, source, _orm, _table, _auditValueChangedDict);
 | 
				
			||||||
 | 
					            _source.AddRange(source.Where(a => a != null));
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected string TableRuleInvoke()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (_tableRule == null) return _table.DbName;
 | 
				
			||||||
 | 
					            var newname = _tableRule(_table.DbName);
 | 
				
			||||||
 | 
					            if (newname == _table.DbName) return _table.DbName;
 | 
				
			||||||
 | 
					            if (string.IsNullOrEmpty(newname)) return _table.DbName;
 | 
				
			||||||
 | 
					            if (_orm.CodeFirst.IsSyncStructureToLower) newname = newname.ToLower();
 | 
				
			||||||
 | 
					            if (_orm.CodeFirst.IsSyncStructureToUpper) newname = newname.ToUpper();
 | 
				
			||||||
 | 
					            if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(_table.Type, newname);
 | 
				
			||||||
 | 
					            return newname;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public IInsertOrUpdate<T1> AsTable(Func<string, string> tableRule)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _tableRule = tableRule;
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public IInsertOrUpdate<T1> AsType(Type entityType)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (entityType == typeof(object)) throw new Exception("IInsertOrUpdate.AsType 参数不支持指定为 object");
 | 
				
			||||||
 | 
					            if (entityType == _table.Type) return this;
 | 
				
			||||||
 | 
					            var newtb = _commonUtils.GetTableByEntity(entityType);
 | 
				
			||||||
 | 
					            _table = newtb ?? throw new Exception("IInsertOrUpdate.AsType 参数错误,请传入正确的实体类型");
 | 
				
			||||||
 | 
					            if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(entityType);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void WriteSourceSelectUnionAll(StringBuilder sb)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var specialParams = new List<DbParameter>();
 | 
				
			||||||
 | 
					            var didx = 0;
 | 
				
			||||||
 | 
					            foreach (var d in _source)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (didx > 0) sb.Append(" \r\nUNION ALL\r\n ");
 | 
				
			||||||
 | 
					                sb.Append("SELECT ");
 | 
				
			||||||
 | 
					                var colidx2 = 0;
 | 
				
			||||||
 | 
					                foreach (var col in _table.Columns.Values)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (colidx2 > 0) sb.Append(", ");
 | 
				
			||||||
 | 
					                    if (string.IsNullOrEmpty(col.DbInsertValue) == false)
 | 
				
			||||||
 | 
					                        sb.Append(col.DbInsertValue);
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        object val = col.GetMapValue(d);
 | 
				
			||||||
 | 
					                        sb.Append(_commonUtils.GetNoneParamaterSqlValue(specialParams, col.Attribute.MapType, val));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    if (didx == 0) sb.Append(" as ").Append(col.Attribute.Name);
 | 
				
			||||||
 | 
					                    ++colidx2;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                switch (_orm.Ado.DataType)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case DataType.OdbcOracle:
 | 
				
			||||||
 | 
					                    case DataType.Oracle:
 | 
				
			||||||
 | 
					                    case DataType.OdbcDameng:
 | 
				
			||||||
 | 
					                    case DataType.Dameng:
 | 
				
			||||||
 | 
					                        sb.Append(" FROM dual");
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                ++didx;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (specialParams.Any()) _params = specialParams.ToArray();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public abstract string ToSql();
 | 
				
			||||||
 | 
					        public int ExecuteAffrows()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var sql = this.ToSql();
 | 
				
			||||||
 | 
					            if (string.IsNullOrEmpty(sql)) return 0;
 | 
				
			||||||
 | 
					            var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.InsertOrUpdate, sql, _params);
 | 
				
			||||||
 | 
					            _orm.Aop.CurdBeforeHandler?.Invoke(this, before);
 | 
				
			||||||
 | 
					            var affrows = 0;
 | 
				
			||||||
 | 
					            Exception exception = null;
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                affrows = _orm.Ado.ExecuteNonQuery(_connection, _transaction, CommandType.Text, sql, _params);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception ex)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                exception = ex;
 | 
				
			||||||
 | 
					                throw ex;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            finally
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var after = new Aop.CurdAfterEventArgs(before, exception, affrows);
 | 
				
			||||||
 | 
					                _orm.Aop.CurdAfterHandler?.Invoke(this, after);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return affrows;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					#if net40
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        async public Task<int> ExecuteAffrowsAsync()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var sql = this.ToSql();
 | 
				
			||||||
 | 
					            if (string.IsNullOrEmpty(sql)) return 0;
 | 
				
			||||||
 | 
					            var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.InsertOrUpdate, sql, _params);
 | 
				
			||||||
 | 
					            _orm.Aop.CurdBeforeHandler?.Invoke(this, before);
 | 
				
			||||||
 | 
					            var affrows = 0;
 | 
				
			||||||
 | 
					            Exception exception = null;
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                affrows = await _orm.Ado.ExecuteNonQueryAsync(_connection, _transaction, CommandType.Text, sql, _params);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception ex)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                exception = ex;
 | 
				
			||||||
 | 
					                throw ex;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            finally
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var after = new Aop.CurdAfterEventArgs(before, exception, affrows);
 | 
				
			||||||
 | 
					                _orm.Aop.CurdAfterHandler?.Invoke(this, after);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return affrows;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -15,20 +15,20 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public abstract partial class InsertProvider<T1> : IInsert<T1> where T1 : class
 | 
					    public abstract partial class InsertProvider<T1> : IInsert<T1> where T1 : class
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        protected IFreeSql _orm;
 | 
					        public IFreeSql _orm;
 | 
				
			||||||
        protected CommonUtils _commonUtils;
 | 
					        public CommonUtils _commonUtils;
 | 
				
			||||||
        protected CommonExpression _commonExpression;
 | 
					        public CommonExpression _commonExpression;
 | 
				
			||||||
        protected List<T1> _source = new List<T1>();
 | 
					        public List<T1> _source = new List<T1>();
 | 
				
			||||||
        protected Dictionary<string, bool> _ignore = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
 | 
					        public Dictionary<string, bool> _ignore = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
 | 
				
			||||||
        protected Dictionary<string, bool> _auditValueChangedDict = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
 | 
					        public Dictionary<string, bool> _auditValueChangedDict = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
 | 
				
			||||||
        protected TableInfo _table;
 | 
					        public TableInfo _table;
 | 
				
			||||||
        protected Func<string, string> _tableRule;
 | 
					        public Func<string, string> _tableRule;
 | 
				
			||||||
        protected bool _noneParameter, _insertIdentity;
 | 
					        public bool _noneParameter, _insertIdentity;
 | 
				
			||||||
        protected int _batchValuesLimit, _batchParameterLimit;
 | 
					        public int _batchValuesLimit, _batchParameterLimit;
 | 
				
			||||||
        protected bool _batchAutoTransaction = true;
 | 
					        public bool _batchAutoTransaction = true;
 | 
				
			||||||
        protected DbParameter[] _params;
 | 
					        public DbParameter[] _params;
 | 
				
			||||||
        protected DbTransaction _transaction;
 | 
					        public DbTransaction _transaction;
 | 
				
			||||||
        protected DbConnection _connection;
 | 
					        public DbConnection _connection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public InsertProvider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
 | 
					        public InsertProvider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -509,7 +509,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
                ++colidx;
 | 
					                ++colidx;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            sb.Append(") ");
 | 
					            sb.Append(") ");
 | 
				
			||||||
            if (isValues) sb.Append(isValues ? "VALUES" : "SELECT ");
 | 
					            if (isValues) sb.Append("VALUES");
 | 
				
			||||||
            _params = _noneParameter ? new DbParameter[0] : new DbParameter[colidx * _source.Count];
 | 
					            _params = _noneParameter ? new DbParameter[0] : new DbParameter[colidx * _source.Count];
 | 
				
			||||||
            var specialParams = new List<DbParameter>();
 | 
					            var specialParams = new List<DbParameter>();
 | 
				
			||||||
            var didx = 0;
 | 
					            var didx = 0;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,25 +15,25 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public abstract partial class UpdateProvider<T1> : IUpdate<T1> where T1 : class
 | 
					    public abstract partial class UpdateProvider<T1> : IUpdate<T1> where T1 : class
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        protected IFreeSql _orm;
 | 
					        public IFreeSql _orm;
 | 
				
			||||||
        protected CommonUtils _commonUtils;
 | 
					        public CommonUtils _commonUtils;
 | 
				
			||||||
        protected CommonExpression _commonExpression;
 | 
					        public CommonExpression _commonExpression;
 | 
				
			||||||
        protected List<T1> _source = new List<T1>();
 | 
					        public List<T1> _source = new List<T1>();
 | 
				
			||||||
        protected Dictionary<string, bool> _ignore = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
 | 
					        public Dictionary<string, bool> _ignore = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
 | 
				
			||||||
        protected Dictionary<string, bool> _auditValueChangedDict = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
 | 
					        public Dictionary<string, bool> _auditValueChangedDict = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
 | 
				
			||||||
        protected TableInfo _table;
 | 
					        public TableInfo _table;
 | 
				
			||||||
        protected Func<string, string> _tableRule;
 | 
					        public Func<string, string> _tableRule;
 | 
				
			||||||
        protected StringBuilder _where = new StringBuilder();
 | 
					        public StringBuilder _where = new StringBuilder();
 | 
				
			||||||
        protected List<GlobalFilter.Item> _whereGlobalFilter;
 | 
					        public List<GlobalFilter.Item> _whereGlobalFilter;
 | 
				
			||||||
        protected StringBuilder _set = new StringBuilder();
 | 
					        public StringBuilder _set = new StringBuilder();
 | 
				
			||||||
        protected StringBuilder _setIncr = new StringBuilder();
 | 
					        public StringBuilder _setIncr = new StringBuilder();
 | 
				
			||||||
        protected List<DbParameter> _params = new List<DbParameter>();
 | 
					        public List<DbParameter> _params = new List<DbParameter>();
 | 
				
			||||||
        protected List<DbParameter> _paramsSource = new List<DbParameter>();
 | 
					        public List<DbParameter> _paramsSource = new List<DbParameter>();
 | 
				
			||||||
        protected bool _noneParameter;
 | 
					        public bool _noneParameter;
 | 
				
			||||||
        protected int _batchRowsLimit, _batchParameterLimit;
 | 
					        public int _batchRowsLimit, _batchParameterLimit;
 | 
				
			||||||
        protected bool _batchAutoTransaction = true;
 | 
					        public bool _batchAutoTransaction = true;
 | 
				
			||||||
        protected DbTransaction _transaction;
 | 
					        public DbTransaction _transaction;
 | 
				
			||||||
        protected DbConnection _connection;
 | 
					        public DbConnection _connection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public UpdateProvider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
 | 
					        public UpdateProvider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Dameng.Curd
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class DamengInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public DamengInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
 | 
				
			||||||
 | 
					            : base(orm, commonUtils, commonExpression)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override string ToSql()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (_source?.Any() != true) return null;
 | 
				
			||||||
 | 
					            if (_table.Primarys.Any() == false) throw new Exception($"InsertOrUpdate 功能要求实体类 {_table.CsName} 必须有主键");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var sb = new StringBuilder().Append("MERGE INTO ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(" t1 \r\n")
 | 
				
			||||||
 | 
					                .Append("USING (");
 | 
				
			||||||
 | 
					            WriteSourceSelectUnionAll(sb);
 | 
				
			||||||
 | 
					            sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _table.Primarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"))).Append(") \r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true);
 | 
				
			||||||
 | 
					            if (cols.Any())
 | 
				
			||||||
 | 
					                sb.Append("WHEN MATCHED THEN \r\n")
 | 
				
			||||||
 | 
					                    .Append("  update set ").Append(string.Join(", ", cols.Select(a =>
 | 
				
			||||||
 | 
					                        a.Attribute.IsVersion ?
 | 
				
			||||||
 | 
					                        $"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} + 1" :
 | 
				
			||||||
 | 
					                        $"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"
 | 
				
			||||||
 | 
					                        ))).Append(" \r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            cols = _table.Columns.Values;
 | 
				
			||||||
 | 
					            sb.Append("WHEN NOT MATCHED THEN \r\n")
 | 
				
			||||||
 | 
					                .Append("  insert (").Append(string.Join(", ", cols.Select(a => _commonUtils.QuoteSqlName(a.Attribute.Name)))).Append(") \r\n")
 | 
				
			||||||
 | 
					                .Append("  values (").Append(string.Join(", ", cols.Select(a => $"t2.{a.Attribute.Name}"))).Append(")");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return sb.ToString();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -24,6 +24,7 @@ namespace FreeSql.Dameng
 | 
				
			|||||||
        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new DamengUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new DamengUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>() where T1 : class => new DamengDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
					        public IDelete<T1> Delete<T1>() where T1 : class => new DamengDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new DamengDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new DamengDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
 | 
					        public IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class => new DamengInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IAdo Ado { get; }
 | 
					        public IAdo Ado { get; }
 | 
				
			||||||
        public IAop Aop { get; }
 | 
					        public IAop Aop { get; }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,7 @@ namespace FreeSql.MsAccess
 | 
				
			|||||||
        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new MsAccessUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new MsAccessUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>() where T1 : class => new MsAccessDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
					        public IDelete<T1> Delete<T1>() where T1 : class => new MsAccessDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new MsAccessDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new MsAccessDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
 | 
					        public IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class => throw new NotImplementedException();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IAdo Ado { get; }
 | 
					        public IAdo Ado { get; }
 | 
				
			||||||
        public IAop Aop { get; }
 | 
					        public IAop Aop { get; }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										29
									
								
								Providers/FreeSql.Provider.MySql/Curd/MySqlInsertOrUpdate.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								Providers/FreeSql.Provider.MySql/Curd/MySqlInsertOrUpdate.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.MySql.Curd
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class MySqlInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public MySqlInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
 | 
				
			||||||
 | 
					            : base(orm, commonUtils, commonExpression)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override string ToSql()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (_source?.Any() != true) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var insert = _orm.Insert<T1>()
 | 
				
			||||||
 | 
					                .AsTable(_tableRule).AsType(_table.Type)
 | 
				
			||||||
 | 
					                .WithConnection(_connection)
 | 
				
			||||||
 | 
					                .WithTransaction(_transaction)
 | 
				
			||||||
 | 
					                .NoneParameter(true) as Internal.CommonProvider.InsertProvider<T1>;
 | 
				
			||||||
 | 
					            insert._source = _source;
 | 
				
			||||||
 | 
					            var sql = new OnDuplicateKeyUpdate<T1>(insert).ToSql();
 | 
				
			||||||
 | 
					            _params = insert._params;
 | 
				
			||||||
 | 
					            return sql;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,11 +1,6 @@
 | 
				
			|||||||
using FreeSql.Aop;
 | 
					using FreeSql.Aop;
 | 
				
			||||||
using FreeSql.Internal;
 | 
					 | 
				
			||||||
using FreeSql.Internal.Model;
 | 
					 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
using System.Data.Common;
 | 
					 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
using System.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
using System.Text;
 | 
					using System.Text;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,6 +50,7 @@ namespace FreeSql.MySql
 | 
				
			|||||||
        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new MySqlUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new MySqlUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>() where T1 : class => new MySqlDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
					        public IDelete<T1> Delete<T1>() where T1 : class => new MySqlDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new MySqlDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new MySqlDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
 | 
					        public IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class => new MySqlInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IAdo Ado { get; }
 | 
					        public IAdo Ado { get; }
 | 
				
			||||||
        public IAop Aop { get; }
 | 
					        public IAop Aop { get; }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Odbc.Dameng
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class OdbcDamengInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public OdbcDamengInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
 | 
				
			||||||
 | 
					            : base(orm, commonUtils, commonExpression)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override string ToSql()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (_source?.Any() != true) return null;
 | 
				
			||||||
 | 
					            if (_table.Primarys.Any() == false) throw new Exception($"InsertOrUpdate 功能要求实体类 {_table.CsName} 必须有主键");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var sb = new StringBuilder().Append("MERGE INTO ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(" t1 \r\n")
 | 
				
			||||||
 | 
					                .Append("USING (");
 | 
				
			||||||
 | 
					            WriteSourceSelectUnionAll(sb);
 | 
				
			||||||
 | 
					            sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _table.Primarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"))).Append(") \r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true);
 | 
				
			||||||
 | 
					            if (cols.Any())
 | 
				
			||||||
 | 
					                sb.Append("WHEN MATCHED THEN \r\n")
 | 
				
			||||||
 | 
					                    .Append("  update set ").Append(string.Join(", ", cols.Select(a =>
 | 
				
			||||||
 | 
					                        a.Attribute.IsVersion ?
 | 
				
			||||||
 | 
					                        $"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} + 1" :
 | 
				
			||||||
 | 
					                        $"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"
 | 
				
			||||||
 | 
					                        ))).Append(" \r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            cols = _table.Columns.Values;
 | 
				
			||||||
 | 
					            sb.Append("WHEN NOT MATCHED THEN \r\n")
 | 
				
			||||||
 | 
					                .Append("  insert (").Append(string.Join(", ", cols.Select(a => _commonUtils.QuoteSqlName(a.Attribute.Name)))).Append(") \r\n")
 | 
				
			||||||
 | 
					                .Append("  values (").Append(string.Join(", ", cols.Select(a => $"t2.{a.Attribute.Name}"))).Append(")");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return sb.ToString();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -23,6 +23,7 @@ namespace FreeSql.Odbc.Dameng
 | 
				
			|||||||
        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OdbcDamengUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OdbcDamengUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>() where T1 : class => new OdbcDamengDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
					        public IDelete<T1> Delete<T1>() where T1 : class => new OdbcDamengDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OdbcDamengDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OdbcDamengDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
 | 
					        public IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class => new OdbcDamengInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IAdo Ado { get; }
 | 
					        public IAdo Ado { get; }
 | 
				
			||||||
        public IAop Aop { get; }
 | 
					        public IAop Aop { get; }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,6 +26,7 @@ namespace FreeSql.Odbc.Default
 | 
				
			|||||||
        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OdbcUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OdbcUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>() where T1 : class => new OdbcDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
					        public IDelete<T1> Delete<T1>() where T1 : class => new OdbcDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OdbcDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OdbcDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
 | 
					        public IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class => throw new NotImplementedException();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IAdo Ado { get; }
 | 
					        public IAdo Ado { get; }
 | 
				
			||||||
        public IAop Aop { get; }
 | 
					        public IAop Aop { get; }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
using FreeSql.Internal;
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
using FreeSql.Internal.ObjectPool;
 | 
					using FreeSql.Internal.ObjectPool;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
@@ -17,11 +18,30 @@ namespace FreeSql.Odbc.MySql
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        internal bool InternalIsIgnoreInto = false;
 | 
				
			||||||
 | 
					        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(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
					        public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
				
			||||||
        public override long ExecuteIdentity() => base.SplitExecuteIdentity(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
					        public override long ExecuteIdentity() => base.SplitExecuteIdentity(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
				
			||||||
        public override List<T1> ExecuteInserted() => base.SplitExecuteInserted(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
					        public override List<T1> ExecuteInserted() => base.SplitExecuteInserted(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override string ToSql()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (InternalIsIgnoreInto == false) return base.ToSqlValuesOrSelectUnionAll();
 | 
				
			||||||
 | 
					            var sql = base.ToSqlValuesOrSelectUnionAll();
 | 
				
			||||||
 | 
					            return $"INSERT IGNORE INTO {sql.Substring(12)}";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected override long RawExecuteIdentity()
 | 
					        protected override long RawExecuteIdentity()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var sql = this.ToSql();
 | 
					            var sql = this.ToSql();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Odbc.MySql
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class OdbcMySqlInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public OdbcMySqlInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
 | 
				
			||||||
 | 
					            : base(orm, commonUtils, commonExpression)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override string ToSql()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (_source?.Any() != true) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var insert = _orm.Insert<T1>()
 | 
				
			||||||
 | 
					                .AsTable(_tableRule).AsType(_table.Type)
 | 
				
			||||||
 | 
					                .WithConnection(_connection)
 | 
				
			||||||
 | 
					                .WithTransaction(_transaction)
 | 
				
			||||||
 | 
					                .NoneParameter(true) as Internal.CommonProvider.InsertProvider<T1>;
 | 
				
			||||||
 | 
					            insert._source = _source;
 | 
				
			||||||
 | 
					            var sql = new OdbcMySqlOnDuplicateKeyUpdate<T1>(insert).ToSql();
 | 
				
			||||||
 | 
					            _params = insert._params;
 | 
				
			||||||
 | 
					            return sql;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,166 @@
 | 
				
			|||||||
 | 
					using FreeSql.Aop;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Data;
 | 
				
			||||||
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Odbc.MySql
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class OdbcMySqlOnDuplicateKeyUpdate<T1> where T1 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        internal OdbcMySqlInsert<T1> _mysqlInsert;
 | 
				
			||||||
 | 
					        internal OdbcMySqlUpdate<T1> _mysqlUpdatePriv;
 | 
				
			||||||
 | 
					        internal OdbcMySqlUpdate<T1> _mysqlUpdate => _mysqlUpdatePriv ?? (_mysqlUpdatePriv = new OdbcMySqlUpdate<T1>(_mysqlInsert.InternalOrm, _mysqlInsert.InternalCommonUtils, _mysqlInsert.InternalCommonExpression, null).NoneParameter().SetSource(_mysqlInsert.InternalSource) as OdbcMySqlUpdate<T1>);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public OdbcMySqlOnDuplicateKeyUpdate(IInsert<T1> insert)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _mysqlInsert = insert as OdbcMySqlInsert<T1>;
 | 
				
			||||||
 | 
					            if (_mysqlInsert == null) throw new Exception("OnDuplicateKeyUpdate 是 FreeSql.Provider.Odbc/MySql 特有的功能");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected void ClearData()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _mysqlInsert.InternalClearData();
 | 
				
			||||||
 | 
					            _mysqlUpdatePriv = null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public OdbcMySqlOnDuplicateKeyUpdate<T1> IgnoreColumns(Expression<Func<T1, object>> columns)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _mysqlUpdate.IgnoreColumns(columns);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public OdbcMySqlOnDuplicateKeyUpdate<T1> UpdateColumns(Expression<Func<T1, object>> columns)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _mysqlUpdate.UpdateColumns(columns);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public OdbcMySqlOnDuplicateKeyUpdate<T1> IgnoreColumns(string[] columns)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _mysqlUpdate.IgnoreColumns(columns);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public OdbcMySqlOnDuplicateKeyUpdate<T1> UpdateColumns(string[] columns)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _mysqlUpdate.UpdateColumns(columns);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public OdbcMySqlOnDuplicateKeyUpdate<T1> Set<TMember>(Expression<Func<T1, TMember>> column, TMember value)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _mysqlUpdate.Set(column, value);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public OdbcMySqlOnDuplicateKeyUpdate<T1> Set<TMember>(Expression<Func<T1, TMember>> exp)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _mysqlUpdate.Set(exp);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public OdbcMySqlOnDuplicateKeyUpdate<T1> 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))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var caseWhen = _mysqlUpdate.InternalWhereCaseSource(col.CsName, sqlval => sqlval).Trim();
 | 
				
			||||||
 | 
					                        sb.Append(caseWhen);
 | 
				
			||||||
 | 
					                        if (caseWhen.EndsWith(" END")) _mysqlUpdate.InternalToSqlCaseWhenEnd(sb, col);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    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.CurdBeforeHandler?.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.CurdAfterHandler?.Invoke(_mysqlInsert, 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(_mysqlInsert.InternalTable.Type, _mysqlInsert.InternalTable, CurdType.Insert, sql, _mysqlInsert.InternalParams);
 | 
				
			||||||
 | 
					            _mysqlInsert.InternalOrm.Aop.CurdBeforeHandler?.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.CurdAfterHandler?.Invoke(_mysqlInsert, after);
 | 
				
			||||||
 | 
					                ClearData();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -18,10 +18,16 @@ namespace FreeSql.Odbc.MySql
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
					        public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
				
			||||||
        public override List<T1> ExecuteUpdated() => base.SplitExecuteUpdated(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
					        public override List<T1> ExecuteUpdated() => base.SplitExecuteUpdated(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected override List<T1> RawExecuteUpdated()
 | 
					        protected override List<T1> RawExecuteUpdated()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var sql = this.ToSql();
 | 
					            var sql = this.ToSql();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,6 +28,7 @@ namespace FreeSql.Odbc.MySql
 | 
				
			|||||||
        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OdbcMySqlUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OdbcMySqlUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>() where T1 : class => new OdbcMySqlDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
					        public IDelete<T1> Delete<T1>() where T1 : class => new OdbcMySqlDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OdbcMySqlDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OdbcMySqlDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
 | 
					        public IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class => new OdbcMySqlInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IAdo Ado { get; }
 | 
					        public IAdo Ado { get; }
 | 
				
			||||||
        public IAop Aop { get; }
 | 
					        public IAop Aop { get; }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Odbc.Oracle
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class OdbcOracleInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public OdbcOracleInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
 | 
				
			||||||
 | 
					            : base(orm, commonUtils, commonExpression)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override string ToSql()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (_source?.Any() != true) return null;
 | 
				
			||||||
 | 
					            if (_table.Primarys.Any() == false) throw new Exception($"InsertOrUpdate 功能要求实体类 {_table.CsName} 必须有主键");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var sb = new StringBuilder().Append("MERGE INTO ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(" t1 \r\n")
 | 
				
			||||||
 | 
					                .Append("USING (");
 | 
				
			||||||
 | 
					            WriteSourceSelectUnionAll(sb);
 | 
				
			||||||
 | 
					            sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _table.Primarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"))).Append(") \r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true);
 | 
				
			||||||
 | 
					            if (cols.Any())
 | 
				
			||||||
 | 
					                sb.Append("WHEN MATCHED THEN \r\n")
 | 
				
			||||||
 | 
					                    .Append("  update set ").Append(string.Join(", ", cols.Select(a =>
 | 
				
			||||||
 | 
					                        a.Attribute.IsVersion ?
 | 
				
			||||||
 | 
					                        $"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} + 1" :
 | 
				
			||||||
 | 
					                        $"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"
 | 
				
			||||||
 | 
					                        ))).Append(" \r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            cols = _table.Columns.Values;
 | 
				
			||||||
 | 
					            sb.Append("WHEN NOT MATCHED THEN \r\n")
 | 
				
			||||||
 | 
					                .Append("  insert (").Append(string.Join(", ", cols.Select(a => _commonUtils.QuoteSqlName(a.Attribute.Name)))).Append(") \r\n")
 | 
				
			||||||
 | 
					                .Append("  values (").Append(string.Join(", ", cols.Select(a => $"t2.{a.Attribute.Name}"))).Append(")");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return sb.ToString();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -23,6 +23,7 @@ namespace FreeSql.Odbc.Oracle
 | 
				
			|||||||
        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OdbcOracleUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OdbcOracleUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>() where T1 : class => new OdbcOracleDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
					        public IDelete<T1> Delete<T1>() where T1 : class => new OdbcOracleDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OdbcOracleDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OdbcOracleDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
 | 
					        public IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class => new OdbcOracleInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IAdo Ado { get; }
 | 
					        public IAdo Ado { get; }
 | 
				
			||||||
        public IAop Aop { get; }
 | 
					        public IAop Aop { get; }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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.Odbc.PostgreSQL
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
					        public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
				
			||||||
        public override long ExecuteIdentity() => base.SplitExecuteIdentity(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
					        public override long ExecuteIdentity() => base.SplitExecuteIdentity(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
				
			||||||
        public override List<T1> ExecuteInserted() => base.SplitExecuteInserted(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
					        public override List<T1> ExecuteInserted() => base.SplitExecuteInserted(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Odbc.PostgreSQL
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class OdbcPostgreSQLInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public OdbcPostgreSQLInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
 | 
				
			||||||
 | 
					            : base(orm, commonUtils, commonExpression)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override string ToSql()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (_source?.Any() != true) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var insert = _orm.Insert<T1>()
 | 
				
			||||||
 | 
					                .AsTable(_tableRule).AsType(_table.Type)
 | 
				
			||||||
 | 
					                .WithConnection(_connection)
 | 
				
			||||||
 | 
					                .WithTransaction(_transaction)
 | 
				
			||||||
 | 
					                .NoneParameter(true) as Internal.CommonProvider.InsertProvider<T1>;
 | 
				
			||||||
 | 
					            insert._source = _source;
 | 
				
			||||||
 | 
					            var ocdu = new OdbcPostgreSQLOnConflictDoUpdate<T1>(insert);
 | 
				
			||||||
 | 
					            ocdu.IgnoreColumns(_table.Columns.Values.Where(a => a.Attribute.CanUpdate == false).Select(a => a.Attribute.Name).ToArray());
 | 
				
			||||||
 | 
					            if (_table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true).Any() == false)
 | 
				
			||||||
 | 
					                ocdu.DoNothing();
 | 
				
			||||||
 | 
					            var sql = ocdu.ToSql();
 | 
				
			||||||
 | 
					            _params = insert._params;
 | 
				
			||||||
 | 
					            return sql;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,207 @@
 | 
				
			|||||||
 | 
					using FreeSql.Aop;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Data;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Odbc.PostgreSQL
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class OdbcPostgreSQLOnConflictDoUpdate<T1> where T1 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        internal OdbcPostgreSQLInsert<T1> _pgsqlInsert;
 | 
				
			||||||
 | 
					        internal OdbcPostgreSQLUpdate<T1> _pgsqlUpdatePriv;
 | 
				
			||||||
 | 
					        internal OdbcPostgreSQLUpdate<T1> _pgsqlUpdate => _pgsqlUpdatePriv ?? 
 | 
				
			||||||
 | 
					            (_pgsqlUpdatePriv = new OdbcPostgreSQLUpdate<T1>(_pgsqlInsert.InternalOrm, _pgsqlInsert.InternalCommonUtils, _pgsqlInsert.InternalCommonExpression, null) { InternalTableAlias = "EXCLUDED" }
 | 
				
			||||||
 | 
					                .NoneParameter().SetSource(_pgsqlInsert.InternalSource) as OdbcPostgreSQLUpdate<T1>);
 | 
				
			||||||
 | 
					        ColumnInfo[] _columns;
 | 
				
			||||||
 | 
					        bool _doNothing;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public OdbcPostgreSQLOnConflictDoUpdate(IInsert<T1> insert, Expression<Func<T1, object>> columns = null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _pgsqlInsert = insert as OdbcPostgreSQLInsert<T1>;
 | 
				
			||||||
 | 
					            if (_pgsqlInsert == null) throw new Exception("OnConflictDoUpdate 是 FreeSql.Provider.Odbc/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 OdbcPostgreSQLOnConflictDoUpdate<T1> IgnoreColumns(Expression<Func<T1, object>> columns)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _pgsqlUpdate.IgnoreColumns(columns);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public OdbcPostgreSQLOnConflictDoUpdate<T1> UpdateColumns(Expression<Func<T1, object>> columns)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _pgsqlUpdate.UpdateColumns(columns);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public OdbcPostgreSQLOnConflictDoUpdate<T1> IgnoreColumns(string[] columns)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _pgsqlUpdate.IgnoreColumns(columns);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public OdbcPostgreSQLOnConflictDoUpdate<T1> UpdateColumns(string[] columns)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _pgsqlUpdate.UpdateColumns(columns);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public OdbcPostgreSQLOnConflictDoUpdate<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 OdbcPostgreSQLOnConflictDoUpdate<T1> SetRaw(string sql)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _pgsqlUpdate.SetRaw(sql);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public OdbcPostgreSQLOnConflictDoUpdate<T1> DoNothing()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _doNothing = true;
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public string ToSql()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var sb = new StringBuilder();
 | 
				
			||||||
 | 
					            sb.Append(_pgsqlInsert.ToSql()).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));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (_doNothing)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                sb.Append(") DO NOTHING");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                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(" = ").Append(_pgsqlInsert.InternalCommonUtils.QuoteSqlName(_pgsqlInsert.InternalTable.DbName)).Append(".").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.CurdBeforeHandler?.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.CurdAfterHandler?.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.CurdBeforeHandler?.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.CurdAfterHandler?.Invoke(_pgsqlInsert, after);
 | 
				
			||||||
 | 
					                ClearData();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -18,6 +18,14 @@ namespace FreeSql.Odbc.PostgreSQL
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
					        public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
				
			||||||
        public override List<T1> ExecuteUpdated() => base.SplitExecuteUpdated(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
					        public override List<T1> ExecuteUpdated() => base.SplitExecuteUpdated(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -65,6 +73,7 @@ namespace FreeSql.Odbc.PostgreSQL
 | 
				
			|||||||
            if (_table.Primarys.Length == 1)
 | 
					            if (_table.Primarys.Length == 1)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var pk = _table.Primarys.First();
 | 
					                var pk = _table.Primarys.First();
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(InternalTableAlias) == false) caseWhen.Append(InternalTableAlias).Append(".");
 | 
				
			||||||
                caseWhen.Append(_commonUtils.QuoteReadColumn(pk.CsType, pk.Attribute.MapType, _commonUtils.QuoteSqlName(pk.Attribute.Name)));
 | 
					                caseWhen.Append(_commonUtils.QuoteReadColumn(pk.CsType, pk.Attribute.MapType, _commonUtils.QuoteSqlName(pk.Attribute.Name)));
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -73,6 +82,7 @@ namespace FreeSql.Odbc.PostgreSQL
 | 
				
			|||||||
            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.CsType, pk.Attribute.MapType, _commonUtils.QuoteSqlName(pk.Attribute.Name))).Append("::varchar");
 | 
					                caseWhen.Append(_commonUtils.QuoteReadColumn(pk.CsType, pk.Attribute.MapType, _commonUtils.QuoteSqlName(pk.Attribute.Name))).Append("::varchar");
 | 
				
			||||||
                ++pkidx;
 | 
					                ++pkidx;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,6 +27,7 @@ namespace FreeSql.Odbc.PostgreSQL
 | 
				
			|||||||
        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OdbcPostgreSQLUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OdbcPostgreSQLUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>() where T1 : class => new OdbcPostgreSQLDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
					        public IDelete<T1> Delete<T1>() where T1 : class => new OdbcPostgreSQLDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OdbcPostgreSQLDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OdbcPostgreSQLDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
 | 
					        public IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class => new OdbcPostgreSQLInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IAdo Ado { get; }
 | 
					        public IAdo Ado { get; }
 | 
				
			||||||
        public IAop Aop { get; }
 | 
					        public IAop Aop { get; }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,7 @@
 | 
				
			|||||||
using FreeSql.Internal;
 | 
					using FreeSql.Internal;
 | 
				
			||||||
using FreeSql.Internal.ObjectPool;
 | 
					 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
using System.Data.Common;
 | 
					 | 
				
			||||||
using System.Text;
 | 
					using System.Text;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Odbc.SqlServer
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class OdbcSqlServerInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public OdbcSqlServerInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
 | 
				
			||||||
 | 
					            : base(orm, commonUtils, commonExpression)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override string ToSql()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (_source?.Any() != true) return null;
 | 
				
			||||||
 | 
					            if (_table.Primarys.Any() == false) throw new Exception($"InsertOrUpdate 功能要求实体类 {_table.CsName} 必须有主键");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var sb = new StringBuilder().Append("MERGE INTO ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(" t1 \r\n")
 | 
				
			||||||
 | 
					                .Append("USING (");
 | 
				
			||||||
 | 
					            WriteSourceSelectUnionAll(sb);
 | 
				
			||||||
 | 
					            sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _table.Primarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"))).Append(") \r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true);
 | 
				
			||||||
 | 
					            if (cols.Any())
 | 
				
			||||||
 | 
					                sb.Append("WHEN MATCHED THEN \r\n")
 | 
				
			||||||
 | 
					                    .Append("  update set ").Append(string.Join(", ", cols.Select(a =>
 | 
				
			||||||
 | 
					                        a.Attribute.IsVersion ?
 | 
				
			||||||
 | 
					                        $"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} + 1" :
 | 
				
			||||||
 | 
					                        $"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"
 | 
				
			||||||
 | 
					                        ))).Append(" \r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            cols = _table.Columns.Values;
 | 
				
			||||||
 | 
					            sb.Append("WHEN NOT MATCHED THEN \r\n")
 | 
				
			||||||
 | 
					                .Append("  insert (").Append(string.Join(", ", cols.Select(a => _commonUtils.QuoteSqlName(a.Attribute.Name)))).Append(") \r\n")
 | 
				
			||||||
 | 
					                .Append("  values (").Append(string.Join(", ", cols.Select(a => $"t2.{a.Attribute.Name}"))).Append(");");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return sb.ToString();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -23,6 +23,7 @@ namespace FreeSql.Odbc.SqlServer
 | 
				
			|||||||
        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OdbcSqlServerUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OdbcSqlServerUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>() where T1 : class => new OdbcSqlServerDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
					        public IDelete<T1> Delete<T1>() where T1 : class => new OdbcSqlServerDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OdbcSqlServerDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OdbcSqlServerDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
 | 
					        public IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class => new OdbcSqlServerInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IAdo Ado { get; }
 | 
					        public IAdo Ado { get; }
 | 
				
			||||||
        public IAop Aop { get; }
 | 
					        public IAop Aop { get; }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Oracle.Curd
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class OracleInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public OracleInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
 | 
				
			||||||
 | 
					            : base(orm, commonUtils, commonExpression)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override string ToSql()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (_source?.Any() != true) return null;
 | 
				
			||||||
 | 
					            if (_table.Primarys.Any() == false) throw new Exception($"InsertOrUpdate 功能要求实体类 {_table.CsName} 必须有主键");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var sb = new StringBuilder().Append("MERGE INTO ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(" t1 \r\n")
 | 
				
			||||||
 | 
					                .Append("USING (");
 | 
				
			||||||
 | 
					            WriteSourceSelectUnionAll(sb);
 | 
				
			||||||
 | 
					            sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _table.Primarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"))).Append(") \r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true);
 | 
				
			||||||
 | 
					            if (cols.Any())
 | 
				
			||||||
 | 
					                sb.Append("WHEN MATCHED THEN \r\n")
 | 
				
			||||||
 | 
					                    .Append("  update set ").Append(string.Join(", ", cols.Select(a =>
 | 
				
			||||||
 | 
					                        a.Attribute.IsVersion ?
 | 
				
			||||||
 | 
					                        $"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} + 1" :
 | 
				
			||||||
 | 
					                        $"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"
 | 
				
			||||||
 | 
					                        ))).Append(" \r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            cols = _table.Columns.Values;
 | 
				
			||||||
 | 
					            sb.Append("WHEN NOT MATCHED THEN \r\n")
 | 
				
			||||||
 | 
					                .Append("  insert (").Append(string.Join(", ", cols.Select(a => _commonUtils.QuoteSqlName(a.Attribute.Name)))).Append(") \r\n")
 | 
				
			||||||
 | 
					                .Append("  values (").Append(string.Join(", ", cols.Select(a => $"t2.{a.Attribute.Name}"))).Append(")");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return sb.ToString();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -24,6 +24,7 @@ namespace FreeSql.Oracle
 | 
				
			|||||||
        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OracleUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OracleUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>() where T1 : class => new OracleDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
					        public IDelete<T1> Delete<T1>() where T1 : class => new OracleDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OracleDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OracleDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
 | 
					        public IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class => new OracleInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IAdo Ado { get; }
 | 
					        public IAdo Ado { get; }
 | 
				
			||||||
        public IAop Aop { get; }
 | 
					        public IAop Aop { get; }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,14 +1,11 @@
 | 
				
			|||||||
using FreeSql.Aop;
 | 
					using FreeSql.Aop;
 | 
				
			||||||
using FreeSql.Internal;
 | 
					 | 
				
			||||||
using FreeSql.Internal.Model;
 | 
					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.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
using System.Text;
 | 
					using System.Text;
 | 
				
			||||||
using System.Text.RegularExpressions;
 | 
					 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace FreeSql.PostgreSQL.Curd
 | 
					namespace FreeSql.PostgreSQL.Curd
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.PostgreSQL.Curd
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class PostgreSQLInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public PostgreSQLInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
 | 
				
			||||||
 | 
					            : base(orm, commonUtils, commonExpression)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override string ToSql()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (_source?.Any() != true) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var insert = _orm.Insert<T1>()
 | 
				
			||||||
 | 
					                .AsTable(_tableRule).AsType(_table.Type)
 | 
				
			||||||
 | 
					                .WithConnection(_connection)
 | 
				
			||||||
 | 
					                .WithTransaction(_transaction)
 | 
				
			||||||
 | 
					                .NoneParameter(true) as Internal.CommonProvider.InsertProvider<T1>;
 | 
				
			||||||
 | 
					            insert._source = _source;
 | 
				
			||||||
 | 
					            var ocdu = new OnConflictDoUpdate<T1>(insert);
 | 
				
			||||||
 | 
					            ocdu.IgnoreColumns(_table.Columns.Values.Where(a => a.Attribute.CanUpdate == false).Select(a => a.Attribute.Name).ToArray());
 | 
				
			||||||
 | 
					            if (_table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true).Any() == false)
 | 
				
			||||||
 | 
					                ocdu.DoNothing();
 | 
				
			||||||
 | 
					            var sql = ocdu.ToSql();
 | 
				
			||||||
 | 
					            _params = insert._params;
 | 
				
			||||||
 | 
					            return sql;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -77,6 +77,7 @@ namespace FreeSql.PostgreSQL
 | 
				
			|||||||
        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new PostgreSQLUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new PostgreSQLUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>() where T1 : class => new PostgreSQLDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
					        public IDelete<T1> Delete<T1>() where T1 : class => new PostgreSQLDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new PostgreSQLDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new PostgreSQLDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
 | 
					        public IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class => new PostgreSQLInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IAdo Ado { get; }
 | 
					        public IAdo Ado { get; }
 | 
				
			||||||
        public IAop Aop { get; }
 | 
					        public IAop Aop { get; }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,8 @@
 | 
				
			|||||||
using FreeSql.Internal;
 | 
					using FreeSql.Internal;
 | 
				
			||||||
using FreeSql.Internal.ObjectPool;
 | 
					 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
using System.Data.Common;
 | 
					using System.Data.Common;
 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
using System.Text;
 | 
					using System.Text;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.SqlServer.Curd
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class SqlServerInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public SqlServerInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
 | 
				
			||||||
 | 
					            : base(orm, commonUtils, commonExpression)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override string ToSql()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (_source?.Any() != true) return null;
 | 
				
			||||||
 | 
					            if (_table.Primarys.Any() == false) throw new Exception($"InsertOrUpdate 功能要求实体类 {_table.CsName} 必须有主键");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var sb = new StringBuilder().Append("MERGE INTO ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(" t1 \r\n")
 | 
				
			||||||
 | 
					                .Append("USING (");
 | 
				
			||||||
 | 
					            WriteSourceSelectUnionAll(sb);
 | 
				
			||||||
 | 
					            sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _table.Primarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"))).Append(") \r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true);
 | 
				
			||||||
 | 
					            if (cols.Any())
 | 
				
			||||||
 | 
					                sb.Append("WHEN MATCHED THEN \r\n")
 | 
				
			||||||
 | 
					                    .Append("  update set ").Append(string.Join(", ", cols.Select(a =>
 | 
				
			||||||
 | 
					                        a.Attribute.IsVersion ?
 | 
				
			||||||
 | 
					                        $"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} + 1" :
 | 
				
			||||||
 | 
					                        $"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{a.Attribute.Name}"
 | 
				
			||||||
 | 
					                        ))).Append(" \r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            cols = _table.Columns.Values;
 | 
				
			||||||
 | 
					            sb.Append("WHEN NOT MATCHED THEN \r\n")
 | 
				
			||||||
 | 
					                .Append("  insert (").Append(string.Join(", ", cols.Select(a => _commonUtils.QuoteSqlName(a.Attribute.Name)))).Append(") \r\n")
 | 
				
			||||||
 | 
					                .Append("  values (").Append(string.Join(", ", cols.Select(a => $"t2.{a.Attribute.Name}"))).Append(");");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return sb.ToString();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -24,6 +24,7 @@ namespace FreeSql.SqlServer
 | 
				
			|||||||
        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new SqlServerUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new SqlServerUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>() where T1 : class => new SqlServerDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
					        public IDelete<T1> Delete<T1>() where T1 : class => new SqlServerDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new SqlServerDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new SqlServerDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
 | 
					        public IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class => new SqlServerInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IAdo Ado { get; }
 | 
					        public IAdo Ado { get; }
 | 
				
			||||||
        public IAop Aop { get; }
 | 
					        public IAop Aop { get; }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Sqlite.Curd
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class SqliteInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public SqliteInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
 | 
				
			||||||
 | 
					            : base(orm, commonUtils, commonExpression)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override string ToSql()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (_source?.Any() != true) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var insert = _orm.Insert<T1>()
 | 
				
			||||||
 | 
					                .AsTable(_tableRule).AsType(_table.Type)
 | 
				
			||||||
 | 
					                .WithConnection(_connection)
 | 
				
			||||||
 | 
					                .WithTransaction(_transaction)
 | 
				
			||||||
 | 
					                .NoneParameter(true) as Internal.CommonProvider.InsertProvider<T1>;
 | 
				
			||||||
 | 
					            insert._source = _source;
 | 
				
			||||||
 | 
					            var sql = insert.ToSql();
 | 
				
			||||||
 | 
					            if (sql.StartsWith("INSERT INTO ") == false) return null;
 | 
				
			||||||
 | 
					            _params = insert._params;
 | 
				
			||||||
 | 
					            return $"REPLACE INTO {sql.Substring("INSERT INTO ".Length)}";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -24,6 +24,7 @@ namespace FreeSql.Sqlite
 | 
				
			|||||||
        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new SqliteUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new SqliteUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>() where T1 : class => new SqliteDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
					        public IDelete<T1> Delete<T1>() where T1 : class => new SqliteDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
				
			||||||
        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new SqliteDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new SqliteDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
 | 
					        public IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class => new SqliteInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IAdo Ado { get; }
 | 
					        public IAdo Ado { get; }
 | 
				
			||||||
        public IAop Aop { get; }
 | 
					        public IAop Aop { get; }
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user