mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 17:20:49 +08:00 
			
		
		
		
	## v0.3.24
- 增加 GroupBy 分页方法; - 修复 Insert 参数化命名 bug,当存在 Id Id2 时发生; - 优化 Insert/Delete/Update 对象执行完后清理数据,以备多次使用;
This commit is contained in:
		@@ -29,60 +29,74 @@ namespace dbcontext_01.Controllers
 | 
			
		||||
				using (var ctx = new SongContext()) {
 | 
			
		||||
 | 
			
		||||
					ctx.Songs.Select.Where(a => a.Id > 10).ToList();
 | 
			
		||||
					//查询结果,进入 states
 | 
			
		||||
 | 
			
		||||
					var song = new Song { };
 | 
			
		||||
					//可插入的 song
 | 
			
		||||
 | 
			
		||||
					ctx.Songs.Add(song);
 | 
			
		||||
					id = song.Id;
 | 
			
		||||
					//因有自增类型,立即开启事务执行SQL,返回自增值
 | 
			
		||||
 | 
			
		||||
					var adds = Enumerable.Range(0, 100)
 | 
			
		||||
						.Select(a => new Song { Create_time = DateTime.Now, Is_deleted = false, Title = "xxxx" + a, Url = "url222" })
 | 
			
		||||
						.ToList();
 | 
			
		||||
					//创建一堆无主键值
 | 
			
		||||
 | 
			
		||||
					ctx.Songs.AddRange(adds);
 | 
			
		||||
					//立即执行,将自增值赋给 adds 所有元素,因为有自增类型,如果其他类型,指定传入主键值,不会立即执行
 | 
			
		||||
 | 
			
		||||
					for (var a = 0; a < adds.Count; a++)
 | 
			
		||||
						adds[a].Title = "dkdkdkdk" + a;
 | 
			
		||||
 | 
			
		||||
					ctx.Songs.UpdateRange(adds);
 | 
			
		||||
					//批量修改,进入队列
 | 
			
		||||
 | 
			
		||||
					ctx.Songs.RemoveRange(adds.Skip(10).Take(20).ToList());
 | 
			
		||||
					//批量删除,进入队列,完成时 10-20 元素的主键值会被清除
 | 
			
		||||
 | 
			
		||||
					//ctx.Songs.Update(adds.First());
 | 
			
		||||
 | 
			
		||||
					adds.Last().Url = "skldfjlksdjglkjjcccc";
 | 
			
		||||
					ctx.Songs.Update(adds.Last());
 | 
			
		||||
					//单条修改 urls 的值,进入队列
 | 
			
		||||
 | 
			
		||||
					//throw new Exception("回滚");
 | 
			
		||||
 | 
			
		||||
					//ctx.Songs.Select.First();
 | 
			
		||||
					//这里做一个查询,会立即打包【执行队列】,避免没有提交的数据,影响查询结果
 | 
			
		||||
 | 
			
		||||
					ctx.SaveChanges();
 | 
			
		||||
					//打包【执行队列】,提交事务
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				using (var ctx = new SongContext()) {
 | 
			
		||||
				//using (var ctx = new SongContext()) {
 | 
			
		||||
 | 
			
		||||
					var song = new Song { };
 | 
			
		||||
					await ctx.Songs.AddAsync(song);
 | 
			
		||||
					id = song.Id;
 | 
			
		||||
				//	var song = new Song { };
 | 
			
		||||
				//	await ctx.Songs.AddAsync(song);
 | 
			
		||||
				//	id = song.Id;
 | 
			
		||||
 | 
			
		||||
					var adds = Enumerable.Range(0, 100)
 | 
			
		||||
						.Select(a => new Song { Create_time = DateTime.Now, Is_deleted = false, Title = "xxxx" + a, Url = "url222" })
 | 
			
		||||
						.ToList();
 | 
			
		||||
					await ctx.Songs.AddRangeAsync(adds);
 | 
			
		||||
				//	var adds = Enumerable.Range(0, 100)
 | 
			
		||||
				//		.Select(a => new Song { Create_time = DateTime.Now, Is_deleted = false, Title = "xxxx" + a, Url = "url222" })
 | 
			
		||||
				//		.ToList();
 | 
			
		||||
				//	await ctx.Songs.AddRangeAsync(adds);
 | 
			
		||||
 | 
			
		||||
					for (var a = 0; a < adds.Count; a++)
 | 
			
		||||
						adds[a].Title = "dkdkdkdk" + a;
 | 
			
		||||
				//	for (var a = 0; a < adds.Count; a++)
 | 
			
		||||
				//		adds[a].Title = "dkdkdkdk" + a;
 | 
			
		||||
 | 
			
		||||
					ctx.Songs.UpdateRange(adds);
 | 
			
		||||
				//	ctx.Songs.UpdateRange(adds);
 | 
			
		||||
 | 
			
		||||
					ctx.Songs.RemoveRange(adds.Skip(10).Take(20).ToList());
 | 
			
		||||
				//	ctx.Songs.RemoveRange(adds.Skip(10).Take(20).ToList());
 | 
			
		||||
 | 
			
		||||
					//ctx.Songs.Update(adds.First());
 | 
			
		||||
				//	//ctx.Songs.Update(adds.First());
 | 
			
		||||
 | 
			
		||||
					adds.Last().Url = "skldfjlksdjglkjjcccc";
 | 
			
		||||
					ctx.Songs.Update(adds.Last());
 | 
			
		||||
				//	adds.Last().Url = "skldfjlksdjglkjjcccc";
 | 
			
		||||
				//	ctx.Songs.Update(adds.Last());
 | 
			
		||||
 | 
			
		||||
					//throw new Exception("回滚");
 | 
			
		||||
				//	//throw new Exception("回滚");
 | 
			
		||||
 | 
			
		||||
					await ctx.SaveChangesAsync();
 | 
			
		||||
				}
 | 
			
		||||
				//	await ctx.SaveChangesAsync();
 | 
			
		||||
				//}
 | 
			
		||||
			} catch {
 | 
			
		||||
				var item = await _orm.Select<Song>().Where(a => a.Id == id).FirstAsync();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -20,12 +20,15 @@ namespace dbcontext_01
 | 
			
		||||
            Configuration = configuration;
 | 
			
		||||
 | 
			
		||||
			Fsql = new FreeSql.FreeSqlBuilder()
 | 
			
		||||
				.UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\document.db;Pooling=true;Max Pool Size=10")
 | 
			
		||||
				//.UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\document.db;Pooling=true;Max Pool Size=10")
 | 
			
		||||
				.UseConnectionString(FreeSql.DataType.SqlServer, "Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Max Pool Size=10")
 | 
			
		||||
				.UseLogger(loggerFactory.CreateLogger<IFreeSql>())
 | 
			
		||||
				.UseAutoSyncStructure(true)
 | 
			
		||||
				.UseLazyLoading(true)
 | 
			
		||||
 | 
			
		||||
				.UseMonitorCommand(cmd => Trace.WriteLine(cmd.CommandText))
 | 
			
		||||
				.UseMonitorCommand(cmd => Trace.WriteLine(cmd.CommandText),
 | 
			
		||||
					(cmd, log) => Trace.WriteLine(log)
 | 
			
		||||
				)
 | 
			
		||||
				.Build();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -47,12 +47,6 @@ namespace FreeSql {
 | 
			
		||||
 | 
			
		||||
		protected Dictionary<string, object> AllSets { get; } = new Dictionary<string, object>();
 | 
			
		||||
 | 
			
		||||
		public long SaveChanges() {
 | 
			
		||||
			ExecCommand();
 | 
			
		||||
			Commit();
 | 
			
		||||
			return _affrows;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal class ExecCommandInfo {
 | 
			
		||||
			public ExecCommandInfoType actionType { get; set; }
 | 
			
		||||
			public object dbSet { get; set; }
 | 
			
		||||
@@ -67,95 +61,6 @@ namespace FreeSql {
 | 
			
		||||
			_actions.Enqueue(new ExecCommandInfo { actionType = actionType, dbSet = dbSet, stateType = stateType, state = state });
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		static Dictionary<Type, Dictionary<string, Func<object, object[], int>>> _dicExecCommandDbContextBetch = new Dictionary<Type, Dictionary<string, Func<object, object[], int>>>();
 | 
			
		||||
		internal void ExecCommand() {
 | 
			
		||||
			ExecCommandInfo oldinfo = null;
 | 
			
		||||
			var states = new List<object>();
 | 
			
		||||
 | 
			
		||||
			Func<string, int> dbContextBetch = methodName => {
 | 
			
		||||
				if (_dicExecCommandDbContextBetch.TryGetValue(oldinfo.stateType, out var trydic) == false)
 | 
			
		||||
					trydic = new Dictionary<string, Func<object, object[], int>>();
 | 
			
		||||
				if (trydic.TryGetValue(methodName, out var tryfunc) == false) {
 | 
			
		||||
					var arrType = oldinfo.stateType.MakeArrayType();
 | 
			
		||||
					var dbsetType = oldinfo.dbSet.GetType().BaseType;
 | 
			
		||||
					var dbsetTypeMethod = dbsetType.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { arrType }, null);
 | 
			
		||||
 | 
			
		||||
					var returnTarget = Expression.Label(typeof(int));
 | 
			
		||||
					var parm1DbSet = Expression.Parameter(typeof(object));
 | 
			
		||||
					var parm2Vals = Expression.Parameter(typeof(object[]));
 | 
			
		||||
					var var1Vals = Expression.Variable(arrType);
 | 
			
		||||
					tryfunc = Expression.Lambda<Func<object, object[], int>>(Expression.Block(
 | 
			
		||||
						new[] { var1Vals },
 | 
			
		||||
						Expression.Assign(var1Vals, Expression.Convert(FreeSql.Internal.Utils.GetDataReaderValueBlockExpression(arrType, parm2Vals), arrType)),
 | 
			
		||||
						Expression.Return(returnTarget, Expression.Call(Expression.Convert(parm1DbSet, dbsetType), dbsetTypeMethod, var1Vals)),
 | 
			
		||||
						Expression.Label(returnTarget, Expression.Default(typeof(int)))
 | 
			
		||||
					), new[] { parm1DbSet, parm2Vals }).Compile();
 | 
			
		||||
					trydic.Add(methodName, tryfunc);
 | 
			
		||||
				}
 | 
			
		||||
				return tryfunc(oldinfo.dbSet, states.ToArray());
 | 
			
		||||
			};
 | 
			
		||||
			Action funcDelete = () => {
 | 
			
		||||
				_affrows += dbContextBetch("DbContextBetchRemove");
 | 
			
		||||
				states.Clear();
 | 
			
		||||
			};
 | 
			
		||||
			Action funcInsert = () => {
 | 
			
		||||
				_affrows += dbContextBetch("DbContextBetchAdd");
 | 
			
		||||
				states.Clear();
 | 
			
		||||
			};
 | 
			
		||||
			Action<bool> funcUpdate = isLiveUpdate => {
 | 
			
		||||
				var affrows = 0;
 | 
			
		||||
				if (isLiveUpdate) affrows = dbContextBetch("DbContextBetchUpdateNow");
 | 
			
		||||
				else affrows = dbContextBetch("DbContextBetchUpdate");
 | 
			
		||||
				if (affrows == -999) { //最后一个元素已被删除
 | 
			
		||||
					states.RemoveAt(states.Count - 1);
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
				if (affrows > 0) {
 | 
			
		||||
					_affrows += affrows;
 | 
			
		||||
					var islastNotUpdated = states.Count != affrows;
 | 
			
		||||
					states.Clear();
 | 
			
		||||
					if (islastNotUpdated) states.Add(oldinfo.state);
 | 
			
		||||
				}
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			while (_actions.Any() || states.Any()) {
 | 
			
		||||
				var info = _actions.Any() ? _actions.Dequeue() : null;
 | 
			
		||||
				if (oldinfo == null) oldinfo = info;
 | 
			
		||||
				var isLiveUpdate = false;
 | 
			
		||||
 | 
			
		||||
				if (_actions.Any() == false && states.Any() ||
 | 
			
		||||
					info != null && oldinfo.actionType != info.actionType ||
 | 
			
		||||
					info != null && oldinfo.stateType != info.stateType) {
 | 
			
		||||
 | 
			
		||||
					if (info != null && oldinfo.actionType == info.actionType && oldinfo.stateType == info.stateType) {
 | 
			
		||||
						//最后一个,合起来发送
 | 
			
		||||
						states.Add(info.state);
 | 
			
		||||
						info = null;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					switch (oldinfo.actionType) {
 | 
			
		||||
						case ExecCommandInfoType.Insert:
 | 
			
		||||
							funcInsert();
 | 
			
		||||
							break;
 | 
			
		||||
						case ExecCommandInfoType.Delete:
 | 
			
		||||
							funcDelete();
 | 
			
		||||
							break;
 | 
			
		||||
					}
 | 
			
		||||
					isLiveUpdate = true;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (isLiveUpdate || oldinfo.actionType == ExecCommandInfoType.Update) {
 | 
			
		||||
					if (states.Any())
 | 
			
		||||
						funcUpdate(isLiveUpdate);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (info != null) {
 | 
			
		||||
					states.Add(info.state);
 | 
			
		||||
					oldinfo = info;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void ReturnObject() {
 | 
			
		||||
			_fsql.Ado.MasterPool.Return(_conn);
 | 
			
		||||
			_tran = null;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,109 +1 @@
 | 
			
		||||
using SafeObjectPool;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Data.Common;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Linq.Expressions;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql {
 | 
			
		||||
	partial class DbContext {
 | 
			
		||||
 | 
			
		||||
		async public Task<long> SaveChangesAsync() {
 | 
			
		||||
			await ExecCommandAsync();
 | 
			
		||||
			Commit();
 | 
			
		||||
			return _affrows;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		static Dictionary<Type, Dictionary<string, Func<object, object[], Task<int>>>> _dicExecCommandAsyncDbContextBetch = new Dictionary<Type, Dictionary<string, Func<object, object[], Task<int>>>>();
 | 
			
		||||
		async internal Task ExecCommandAsync() {
 | 
			
		||||
			ExecCommandInfo oldinfo = null;
 | 
			
		||||
			var states = new List<object>();
 | 
			
		||||
 | 
			
		||||
			Func<string, Task<int>> dbContextBetch = methodName => {
 | 
			
		||||
				if (_dicExecCommandAsyncDbContextBetch.TryGetValue(oldinfo.stateType, out var trydic) == false)
 | 
			
		||||
					trydic = new Dictionary<string, Func<object, object[], Task<int>>>();
 | 
			
		||||
				if (trydic.TryGetValue(methodName, out var tryfunc) == false) {
 | 
			
		||||
					var arrType = oldinfo.stateType.MakeArrayType();
 | 
			
		||||
					var dbsetType = oldinfo.dbSet.GetType().BaseType;
 | 
			
		||||
					var dbsetTypeMethod = dbsetType.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { arrType }, null);
 | 
			
		||||
 | 
			
		||||
					var returnTarget = Expression.Label(typeof(Task<int>));
 | 
			
		||||
					var parm1DbSet = Expression.Parameter(typeof(object));
 | 
			
		||||
					var parm2Vals = Expression.Parameter(typeof(object[]));
 | 
			
		||||
					var var1Vals = Expression.Variable(arrType);
 | 
			
		||||
					tryfunc = Expression.Lambda<Func<object, object[], Task<int>>>(Expression.Block(
 | 
			
		||||
						new[] { var1Vals },
 | 
			
		||||
						Expression.Assign(var1Vals, Expression.Convert(FreeSql.Internal.Utils.GetDataReaderValueBlockExpression(arrType, parm2Vals), arrType)),
 | 
			
		||||
						Expression.Return(returnTarget, Expression.Call(Expression.Convert(parm1DbSet, dbsetType), dbsetTypeMethod, var1Vals)),
 | 
			
		||||
						Expression.Label(returnTarget, Expression.Default(typeof(Task<int>)))
 | 
			
		||||
					), new[] { parm1DbSet, parm2Vals }).Compile();
 | 
			
		||||
					trydic.Add(methodName, tryfunc);
 | 
			
		||||
				}
 | 
			
		||||
				return tryfunc(oldinfo.dbSet, states.ToArray());
 | 
			
		||||
			};
 | 
			
		||||
			Func<Task> funcDelete = async () => {
 | 
			
		||||
				_affrows += await dbContextBetch("DbContextBetchRemoveAsync");
 | 
			
		||||
				states.Clear();
 | 
			
		||||
			};
 | 
			
		||||
			Func<Task> funcInsert = async () => {
 | 
			
		||||
				_affrows += await dbContextBetch("DbContextBetchAddAsync");
 | 
			
		||||
				states.Clear();
 | 
			
		||||
			};
 | 
			
		||||
			Func<bool, Task> funcUpdate = async isLiveUpdate => {
 | 
			
		||||
				var affrows = 0;
 | 
			
		||||
				if (isLiveUpdate) affrows = await dbContextBetch("DbContextBetchUpdateNowAsync");
 | 
			
		||||
				else affrows = await dbContextBetch("DbContextBetchUpdateAsync");
 | 
			
		||||
				if (affrows == -999) { //最后一个元素已被删除
 | 
			
		||||
					states.RemoveAt(states.Count - 1);
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
				if (affrows > 0) {
 | 
			
		||||
					_affrows += affrows;
 | 
			
		||||
					var islastNotUpdated = states.Count != affrows;
 | 
			
		||||
					states.Clear();
 | 
			
		||||
					if (islastNotUpdated) states.Add(oldinfo.state);
 | 
			
		||||
				}
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			while (_actions.Any() || states.Any()) {
 | 
			
		||||
				var info = _actions.Any() ? _actions.Dequeue() : null;
 | 
			
		||||
				if (oldinfo == null) oldinfo = info;
 | 
			
		||||
				var isLiveUpdate = false;
 | 
			
		||||
 | 
			
		||||
				if (_actions.Any() == false && states.Any() ||
 | 
			
		||||
					info != null && oldinfo.actionType != info.actionType ||
 | 
			
		||||
					info != null && oldinfo.stateType != info.stateType) {
 | 
			
		||||
 | 
			
		||||
					if (info != null && oldinfo.actionType == info.actionType && oldinfo.stateType == info.stateType) {
 | 
			
		||||
						//最后一个,合起来发送
 | 
			
		||||
						states.Add(info.state);
 | 
			
		||||
						info = null;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					switch (oldinfo.actionType) {
 | 
			
		||||
						case ExecCommandInfoType.Insert:
 | 
			
		||||
							await funcInsert();
 | 
			
		||||
							break;
 | 
			
		||||
						case ExecCommandInfoType.Delete:
 | 
			
		||||
							await funcDelete();
 | 
			
		||||
							break;
 | 
			
		||||
					}
 | 
			
		||||
					isLiveUpdate = true;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (isLiveUpdate || oldinfo.actionType == ExecCommandInfoType.Update) {
 | 
			
		||||
					if (states.Any())
 | 
			
		||||
						await funcUpdate(isLiveUpdate);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (info != null) {
 | 
			
		||||
					states.Add(info.state);
 | 
			
		||||
					oldinfo = info;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										108
									
								
								FreeSql.DbContext/DbContextSync.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								FreeSql.DbContext/DbContextSync.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
			
		||||
using SafeObjectPool;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Data.Common;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Linq.Expressions;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql {
 | 
			
		||||
	partial class DbContext {
 | 
			
		||||
 | 
			
		||||
		public long SaveChanges() {
 | 
			
		||||
			ExecCommand();
 | 
			
		||||
			Commit();
 | 
			
		||||
			return _affrows;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		static Dictionary<Type, Dictionary<string, Func<object, object[], int>>> _dicExecCommandDbContextBetch = new Dictionary<Type, Dictionary<string, Func<object, object[], int>>>();
 | 
			
		||||
		internal void ExecCommand() {
 | 
			
		||||
			ExecCommandInfo oldinfo = null;
 | 
			
		||||
			var states = new List<object>();
 | 
			
		||||
 | 
			
		||||
			Func<string, int> dbContextBetch = methodName => {
 | 
			
		||||
				if (_dicExecCommandDbContextBetch.TryGetValue(oldinfo.stateType, out var trydic) == false)
 | 
			
		||||
					trydic = new Dictionary<string, Func<object, object[], int>>();
 | 
			
		||||
				if (trydic.TryGetValue(methodName, out var tryfunc) == false) {
 | 
			
		||||
					var arrType = oldinfo.stateType.MakeArrayType();
 | 
			
		||||
					var dbsetType = oldinfo.dbSet.GetType().BaseType;
 | 
			
		||||
					var dbsetTypeMethod = dbsetType.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { arrType }, null);
 | 
			
		||||
 | 
			
		||||
					var returnTarget = Expression.Label(typeof(int));
 | 
			
		||||
					var parm1DbSet = Expression.Parameter(typeof(object));
 | 
			
		||||
					var parm2Vals = Expression.Parameter(typeof(object[]));
 | 
			
		||||
					var var1Vals = Expression.Variable(arrType);
 | 
			
		||||
					tryfunc = Expression.Lambda<Func<object, object[], int>>(Expression.Block(
 | 
			
		||||
						new[] { var1Vals },
 | 
			
		||||
						Expression.Assign(var1Vals, Expression.Convert(FreeSql.Internal.Utils.GetDataReaderValueBlockExpression(arrType, parm2Vals), arrType)),
 | 
			
		||||
						Expression.Return(returnTarget, Expression.Call(Expression.Convert(parm1DbSet, dbsetType), dbsetTypeMethod, var1Vals)),
 | 
			
		||||
						Expression.Label(returnTarget, Expression.Default(typeof(int)))
 | 
			
		||||
					), new[] { parm1DbSet, parm2Vals }).Compile();
 | 
			
		||||
					trydic.Add(methodName, tryfunc);
 | 
			
		||||
				}
 | 
			
		||||
				return tryfunc(oldinfo.dbSet, states.ToArray());
 | 
			
		||||
			};
 | 
			
		||||
			Action funcDelete = () => {
 | 
			
		||||
				_affrows += dbContextBetch("DbContextBetchRemove");
 | 
			
		||||
				states.Clear();
 | 
			
		||||
			};
 | 
			
		||||
			Action funcInsert = () => {
 | 
			
		||||
				_affrows += dbContextBetch("DbContextBetchAdd");
 | 
			
		||||
				states.Clear();
 | 
			
		||||
			};
 | 
			
		||||
			Action<bool> funcUpdate = isLiveUpdate => {
 | 
			
		||||
				var affrows = 0;
 | 
			
		||||
				if (isLiveUpdate) affrows = dbContextBetch("DbContextBetchUpdateNow");
 | 
			
		||||
				else affrows = dbContextBetch("DbContextBetchUpdate");
 | 
			
		||||
				if (affrows == -999) { //最后一个元素已被删除
 | 
			
		||||
					states.RemoveAt(states.Count - 1);
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
				if (affrows > 0) {
 | 
			
		||||
					_affrows += affrows;
 | 
			
		||||
					var islastNotUpdated = states.Count != affrows;
 | 
			
		||||
					states.Clear();
 | 
			
		||||
					if (islastNotUpdated) states.Add(oldinfo.state);
 | 
			
		||||
				}
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			while (_actions.Any() || states.Any()) {
 | 
			
		||||
				var info = _actions.Any() ? _actions.Dequeue() : null;
 | 
			
		||||
				if (oldinfo == null) oldinfo = info;
 | 
			
		||||
				var isLiveUpdate = false;
 | 
			
		||||
 | 
			
		||||
				if (_actions.Any() == false && states.Any() ||
 | 
			
		||||
					info != null && oldinfo.actionType != info.actionType ||
 | 
			
		||||
					info != null && oldinfo.stateType != info.stateType) {
 | 
			
		||||
 | 
			
		||||
					if (info != null && oldinfo.actionType == info.actionType && oldinfo.stateType == info.stateType) {
 | 
			
		||||
						//最后一个,合起来发送
 | 
			
		||||
						states.Add(info.state);
 | 
			
		||||
						info = null;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					switch (oldinfo.actionType) {
 | 
			
		||||
						case ExecCommandInfoType.Insert:
 | 
			
		||||
							funcInsert();
 | 
			
		||||
							break;
 | 
			
		||||
						case ExecCommandInfoType.Delete:
 | 
			
		||||
							funcDelete();
 | 
			
		||||
							break;
 | 
			
		||||
					}
 | 
			
		||||
					isLiveUpdate = true;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (isLiveUpdate || oldinfo.actionType == ExecCommandInfoType.Update) {
 | 
			
		||||
					if (states.Any())
 | 
			
		||||
						funcUpdate(isLiveUpdate);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (info != null) {
 | 
			
		||||
					states.Add(info.state);
 | 
			
		||||
					oldinfo = info;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -24,9 +24,9 @@ namespace FreeSql {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		protected IInsert<TEntity> OrmInsert() => _fsql.Insert<TEntity>().WithTransaction(_ctx.GetOrBeginTransaction());
 | 
			
		||||
		protected IInsert<TEntity> OrmInsert(TEntity source) => _fsql.Insert<TEntity>(source).WithTransaction(_ctx.GetOrBeginTransaction());
 | 
			
		||||
		protected IInsert<TEntity> OrmInsert(TEntity[] source) => _fsql.Insert<TEntity>(source).WithTransaction(_ctx.GetOrBeginTransaction());
 | 
			
		||||
		protected IInsert<TEntity> OrmInsert(IEnumerable<TEntity> source) => _fsql.Insert<TEntity>(source).WithTransaction(_ctx.GetOrBeginTransaction());
 | 
			
		||||
		protected IInsert<TEntity> OrmInsert(TEntity data) => _fsql.Insert<TEntity>(data).WithTransaction(_ctx.GetOrBeginTransaction());
 | 
			
		||||
		protected IInsert<TEntity> OrmInsert(TEntity[] data) => _fsql.Insert<TEntity>(data).WithTransaction(_ctx.GetOrBeginTransaction());
 | 
			
		||||
		protected IInsert<TEntity> OrmInsert(IEnumerable<TEntity> data) => _fsql.Insert<TEntity>(data).WithTransaction(_ctx.GetOrBeginTransaction());
 | 
			
		||||
 | 
			
		||||
		protected IUpdate<TEntity> OrmUpdate(object dywhere) => _fsql.Update<TEntity>(dywhere).WithTransaction(_ctx.GetOrBeginTransaction());
 | 
			
		||||
		protected IDelete<TEntity> OrmDelete(object dywhere) => _fsql.Delete<TEntity>(dywhere).WithTransaction(_ctx.GetOrBeginTransaction());
 | 
			
		||||
@@ -35,7 +35,7 @@ namespace FreeSql {
 | 
			
		||||
		public ISelect<TEntity> Where(Expression<Func<TEntity, bool>> exp) => this.OrmSelect(null).Where(exp);
 | 
			
		||||
		public ISelect<TEntity> WhereIf(bool condition, Expression<Func<TEntity, bool>> exp) => this.OrmSelect(null).WhereIf(condition, exp);
 | 
			
		||||
 | 
			
		||||
		protected Dictionary<string, EntityState> _vals = new Dictionary<string, EntityState>();
 | 
			
		||||
		protected Dictionary<string, EntityState> _states = new Dictionary<string, EntityState>();
 | 
			
		||||
		TableInfo _tablePriv;
 | 
			
		||||
		protected TableInfo _table => _tablePriv ?? (_tablePriv = _fsql.CodeFirst.GetTableByEntity(_entityType));
 | 
			
		||||
		ColumnInfo[] _tableIdentitysPriv;
 | 
			
		||||
@@ -43,177 +43,167 @@ namespace FreeSql {
 | 
			
		||||
		protected Type _entityType = typeof(TEntity);
 | 
			
		||||
 | 
			
		||||
		public class EntityState {
 | 
			
		||||
			public EntityState(TEntity value, string key) {
 | 
			
		||||
				this.Value = value;
 | 
			
		||||
				this.Key = key;
 | 
			
		||||
				this.Time = DateTime.Now;
 | 
			
		||||
			}
 | 
			
		||||
			public TEntity Value { get; set; }
 | 
			
		||||
			public string Key { get; set; }
 | 
			
		||||
			public DateTime Time { get; set; }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		int DbContextBetcAdd(EntityState[] dels) {
 | 
			
		||||
			if (dels.Any() == false) return 0;
 | 
			
		||||
			var affrows = this.OrmInsert(dels.Select(a => a.Value)).ExecuteAffrows();
 | 
			
		||||
			return affrows;
 | 
			
		||||
		#region Utils
 | 
			
		||||
		protected EntityState CreateEntityState(TEntity data) {
 | 
			
		||||
			if (data == null) throw new ArgumentNullException(nameof(data));
 | 
			
		||||
			var key = _fsql.GetEntityKeyString(data);
 | 
			
		||||
			var state = new EntityState(Activator.CreateInstance<TEntity>(), key);
 | 
			
		||||
			_fsql.MapEntityValue(data, state.Value);
 | 
			
		||||
			return state;
 | 
			
		||||
		}
 | 
			
		||||
		public void Add(TEntity source) {
 | 
			
		||||
			if (source == null) throw new ArgumentNullException(nameof(source));
 | 
			
		||||
			var key = _fsql.GetEntityKeyString(source);
 | 
			
		||||
			EntityState state = new EntityState();
 | 
			
		||||
		protected bool ExistsInStates(TEntity data) {
 | 
			
		||||
			if (data == null) throw new ArgumentNullException(nameof(data));
 | 
			
		||||
			var key = _fsql.GetEntityKeyString(data);
 | 
			
		||||
			if (string.IsNullOrEmpty(key)) return false;
 | 
			
		||||
			return _states.ContainsKey(key);
 | 
			
		||||
		}
 | 
			
		||||
		protected bool CanAdd(TEntity[] data, bool isThrow) {
 | 
			
		||||
			if (data == null) {
 | 
			
		||||
				if (isThrow) throw new ArgumentNullException(nameof(data));
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			foreach (var s in data) if (CanAdd(s, isThrow) == false) return false;
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
		protected bool CanAdd(IEnumerable<TEntity> data, bool isThrow) {
 | 
			
		||||
			if (data == null) {
 | 
			
		||||
				if (isThrow) throw new ArgumentNullException(nameof(data));
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			foreach (var s in data) if (CanAdd(s, isThrow) == false) return false;
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
		protected bool CanAdd(TEntity data, bool isThrow) {
 | 
			
		||||
			if (data == null) {
 | 
			
		||||
				if (isThrow) throw new ArgumentNullException(nameof(data));
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			var key = _fsql.GetEntityKeyString(data);
 | 
			
		||||
			if (string.IsNullOrEmpty(key)) {
 | 
			
		||||
				switch(_fsql.Ado.DataType) {
 | 
			
		||||
				switch (_fsql.Ado.DataType) {
 | 
			
		||||
					case DataType.SqlServer:
 | 
			
		||||
					case DataType.PostgreSQL:
 | 
			
		||||
						if (_tableIdentitys.Length == 1 && _table.Primarys.Length == 1) {
 | 
			
		||||
							_ctx.ExecCommand();
 | 
			
		||||
							var idtval = this.OrmInsert(source).ExecuteIdentity();
 | 
			
		||||
							_ctx._affrows++;
 | 
			
		||||
							_fsql.SetEntityIdentityValue(source, idtval);
 | 
			
		||||
						} else {
 | 
			
		||||
							_ctx.ExecCommand();
 | 
			
		||||
							state.Value = this.OrmInsert(source).ExecuteInserted().First();
 | 
			
		||||
							_ctx._affrows++;
 | 
			
		||||
							_fsql.CopyEntityValue(source, state.Value);
 | 
			
		||||
						}
 | 
			
		||||
						break;
 | 
			
		||||
						return true;
 | 
			
		||||
					case DataType.MySql:
 | 
			
		||||
					case DataType.Oracle:
 | 
			
		||||
					case DataType.Sqlite:
 | 
			
		||||
						if (_tableIdentitys.Length == 1 && _table.Primarys.Length == 1) {
 | 
			
		||||
							_ctx.ExecCommand();
 | 
			
		||||
							var idtval = this.OrmInsert(source).ExecuteIdentity();
 | 
			
		||||
							_ctx._affrows++;
 | 
			
		||||
							_fsql.SetEntityIdentityValue(source, idtval);
 | 
			
		||||
						} else {
 | 
			
		||||
							throw new Exception($"DbSet.Add 失败,未设置主键的值,或者没有配置自增,或者自增列数不为1:{_fsql.GetEntityString(source)}");
 | 
			
		||||
							return true;
 | 
			
		||||
						}
 | 
			
		||||
						break;
 | 
			
		||||
						if (isThrow) throw new Exception($"不可添加,未设置主键的值:{_fsql.GetEntityString(data)}");
 | 
			
		||||
						return false;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				state.Key = key = _fsql.GetEntityKeyString(source);
 | 
			
		||||
				state.Time = DateTime.Now;
 | 
			
		||||
			} else {
 | 
			
		||||
				if (_vals.ContainsKey(key))
 | 
			
		||||
					throw new Exception($"DbSet.Add 失败,实体数据已存在,请勿重复添加:{_fsql.GetEntityString(source)}");
 | 
			
		||||
				_ctx.EnqueueAction(DbContext.ExecCommandInfoType.Insert, this, typeof(EntityState), state);
 | 
			
		||||
			}
 | 
			
		||||
			if (state.Value == null) {
 | 
			
		||||
				state.Value = Activator.CreateInstance<TEntity>();
 | 
			
		||||
				_fsql.CopyEntityValue(state.Value, source); //copy, 记录旧值版本
 | 
			
		||||
			}
 | 
			
		||||
			_vals.Add(key, state);
 | 
			
		||||
		}
 | 
			
		||||
		public void AddRange(TEntity[] source) {
 | 
			
		||||
			if (source == null) throw new ArgumentNullException(nameof(source));
 | 
			
		||||
			for (var a = 0; a < source.Length; a++)
 | 
			
		||||
				Add(source[a]);
 | 
			
		||||
		}
 | 
			
		||||
		public void AddRange(IEnumerable<TEntity> source) {
 | 
			
		||||
			if (source == null) throw new ArgumentNullException(nameof(source));
 | 
			
		||||
			foreach(var item in source)
 | 
			
		||||
				Add(item);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		int DbContextBetchUpdate(EntityState[] ups) => DbContextBetchUpdatePriv(ups, false);
 | 
			
		||||
		int DbContextBetchUpdateNow(EntityState[] ups) => DbContextBetchUpdatePriv(ups, true);
 | 
			
		||||
		int DbContextBetchUpdatePriv(EntityState[] ups, bool isLiveUpdate) {
 | 
			
		||||
			if (ups.Any() == false) return 0;
 | 
			
		||||
			var uplst1 = ups[ups.Length - 1];
 | 
			
		||||
			var uplst2 = ups.Length > 1 ? ups[ups.Length - 2] : null;
 | 
			
		||||
 | 
			
		||||
			if (_vals.TryGetValue(uplst1.Key, out var lstval1) == false) return -999;
 | 
			
		||||
			var lstval2 = default(EntityState);
 | 
			
		||||
			if (uplst2 != null && _vals.TryGetValue(uplst2.Key, out lstval2) == false) throw new Exception($"DbSet.Update 失败,实体应该先查询再修改:{_fsql.GetEntityString(uplst2.Value)}");
 | 
			
		||||
 | 
			
		||||
			var cuig1 = _fsql.CompareEntityValueReturnColumns(uplst1.Value, lstval1.Value, true);
 | 
			
		||||
			var cuig2 = uplst2 != null ? _fsql.CompareEntityValueReturnColumns(uplst2.Value, lstval2.Value, true) : null;
 | 
			
		||||
			if (uplst2 != null && string.Compare(string.Join(",", cuig1), string.Join(",", cuig2)) != 0) {
 | 
			
		||||
				//最后一个不保存
 | 
			
		||||
				var source = ups.ToList();
 | 
			
		||||
				source.RemoveAt(ups.Length - 1);
 | 
			
		||||
				var affrows = this.OrmUpdate(null).SetSource(source.Select(a => a.Value)).IgnoreColumns(cuig2).ExecuteAffrows();
 | 
			
		||||
				foreach (var newval in source) {
 | 
			
		||||
					if (_vals.TryGetValue(newval.Key, out var tryold))
 | 
			
		||||
						_fsql.CopyEntityValue(tryold.Value, newval.Value);
 | 
			
		||||
				if (_states.ContainsKey(key)) {
 | 
			
		||||
					if (isThrow) throw new Exception($"不可添加,已存在于状态管理:{_fsql.GetEntityString(data)}");
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
				return affrows;
 | 
			
		||||
			} else if (isLiveUpdate) {
 | 
			
		||||
				//立即保存
 | 
			
		||||
				var source = ups;
 | 
			
		||||
				var affrows = this.OrmUpdate(null).SetSource(source.Select(a => a.Value)).IgnoreColumns(cuig1).ExecuteAffrows();
 | 
			
		||||
				foreach (var newval in source) {
 | 
			
		||||
					if (_vals.TryGetValue(newval.Key, out var tryold))
 | 
			
		||||
						_fsql.CopyEntityValue(tryold.Value, newval.Value);
 | 
			
		||||
				var idval = _fsql.GetEntityIdentityValueWithPrimary(data);
 | 
			
		||||
				if (idval > 0) {
 | 
			
		||||
					if (isThrow) throw new Exception($"不可添加,自增属性有值:{_fsql.GetEntityString(data)}");
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
				return Math.Min(ups.Length, affrows);
 | 
			
		||||
			}
 | 
			
		||||
			//等待下次对比再保存
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		public void Update(TEntity source) {
 | 
			
		||||
			if (source == null) throw new ArgumentNullException(nameof(source));
 | 
			
		||||
			if (_table.Primarys.Any() == false) throw new Exception($"DbSet.Update 失败,实体没有主键:{_fsql.GetEntityString(source)}");
 | 
			
		||||
			var key = _fsql.GetEntityKeyString(source);
 | 
			
		||||
			if (string.IsNullOrEmpty(key)) throw new Exception($"DbSet.Update 失败,未设置主键的值:{_fsql.GetEntityString(source)}");
 | 
			
		||||
			if (_vals.TryGetValue(key, out var tryval) == false) throw new Exception($"DbSet.Update 失败,实体未被跟踪,更新前应该先做查询:{_fsql.GetEntityString(source)}");
 | 
			
		||||
 | 
			
		||||
			var snap = Activator.CreateInstance<TEntity>();
 | 
			
		||||
			_fsql.CopyEntityValue(snap, source); //copy,避免SaveChanges前对象再次被修改
 | 
			
		||||
			_ctx.EnqueueAction(DbContext.ExecCommandInfoType.Update, this, typeof(EntityState), new EntityState { Value = snap, Key = key, Time = DateTime.Now });
 | 
			
		||||
		}
 | 
			
		||||
		public void UpdateRange(TEntity[] source) {
 | 
			
		||||
			if (source == null) throw new ArgumentNullException(nameof(source));
 | 
			
		||||
			for (var a = 0; a < source.Length; a++)
 | 
			
		||||
				Update(source[a]);
 | 
			
		||||
		}
 | 
			
		||||
		public void UpdateRange(IEnumerable<TEntity> source) {
 | 
			
		||||
			if (source == null) throw new ArgumentNullException(nameof(source));
 | 
			
		||||
			foreach (var item in source)
 | 
			
		||||
				Update(item);
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		int DbContextBetchRemove(EntityState[] dels) {
 | 
			
		||||
			if (dels.Any() == false) return 0;
 | 
			
		||||
			var affrows = this.OrmDelete(dels.Select(a => a.Value)).ExecuteAffrows();
 | 
			
		||||
			//foreach (var del in dels)
 | 
			
		||||
			//	_vals.Remove(del.Key);
 | 
			
		||||
			return affrows;
 | 
			
		||||
		protected bool CanUpdate(TEntity[] data, bool isThrow) {
 | 
			
		||||
			if (data == null) {
 | 
			
		||||
				if (isThrow) throw new ArgumentNullException(nameof(data));
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			foreach (var s in data) if (CanUpdate(s, isThrow) == false) return false;
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
		protected bool CanUpdate(IEnumerable<TEntity> data, bool isThrow) {
 | 
			
		||||
			if (data == null) {
 | 
			
		||||
				if (isThrow) throw new ArgumentNullException(nameof(data));
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			foreach (var s in data) if (CanUpdate(s, isThrow) == false) return false;
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
		protected bool CanUpdate(TEntity data, bool isThrow) {
 | 
			
		||||
			if (data == null) {
 | 
			
		||||
				if (isThrow) throw new ArgumentNullException(nameof(data));
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			if (_table.Primarys.Any() == false) {
 | 
			
		||||
				if (isThrow) throw new Exception($"不可更新,实体没有主键:{_fsql.GetEntityString(data)}");
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			var key = _fsql.GetEntityKeyString(data);
 | 
			
		||||
			if (string.IsNullOrEmpty(key)) {
 | 
			
		||||
				if (isThrow) throw new Exception($"不可更新,未设置主键的值:{_fsql.GetEntityString(data)}");
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			if (_states.TryGetValue(key, out var tryval) == false) {
 | 
			
		||||
				if (isThrow) throw new Exception($"不可更新,数据未被跟踪,应该先查询:{_fsql.GetEntityString(data)}");
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
		public void Remove(TEntity source) {
 | 
			
		||||
			if (source == null) throw new ArgumentNullException(nameof(source));
 | 
			
		||||
			if (_table.Primarys.Any() == false) throw new Exception($"DbSet.Remove 失败,实体没有主键:{_fsql.GetEntityString(source)}");
 | 
			
		||||
			var key = _fsql.GetEntityKeyString(source);
 | 
			
		||||
			if (string.IsNullOrEmpty(key)) throw new Exception($"DbSet.Remove 失败,未设置主键的值:{_fsql.GetEntityString(source)}");
 | 
			
		||||
			if (_vals.TryGetValue(key, out var tryval) == false) throw new Exception($"DbSet.Remove 失败,实体未被跟踪,删除前应该先做查询:{_fsql.GetEntityString(source)}");
 | 
			
		||||
 | 
			
		||||
			var snap = Activator.CreateInstance<TEntity>();
 | 
			
		||||
			_fsql.CopyEntityValue(snap, source); //copy,避免SaveChanges前对象再次被修改
 | 
			
		||||
			_ctx.EnqueueAction(DbContext.ExecCommandInfoType.Delete, this, typeof(EntityState), new EntityState { Value = snap, Key = key, Time = DateTime.Now });
 | 
			
		||||
 | 
			
		||||
			_vals.Remove(key);
 | 
			
		||||
			_fsql.ClearEntityPrimaryValueWithIdentityAndGuid(source);
 | 
			
		||||
		protected bool CanRemove(TEntity[] data, bool isThrow) {
 | 
			
		||||
			if (data == null) {
 | 
			
		||||
				if (isThrow) throw new ArgumentNullException(nameof(data));
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			foreach (var s in data) if (CanRemove(s, isThrow) == false) return false;
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
		public void RemoveRange(TEntity[] source) {
 | 
			
		||||
			if (source == null) throw new ArgumentNullException(nameof(source));
 | 
			
		||||
			for (var a = 0; a < source.Length; a++)
 | 
			
		||||
				Remove(source[a]);
 | 
			
		||||
		protected bool CanRemove(IEnumerable<TEntity> data, bool isThrow) {
 | 
			
		||||
			if (data == null) {
 | 
			
		||||
				if (isThrow) throw new ArgumentNullException(nameof(data));
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			foreach (var s in data) if (CanRemove(s, isThrow) == false) return false;
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
		public void RemoveRange(IEnumerable<TEntity> source) {
 | 
			
		||||
			if (source == null) throw new ArgumentNullException(nameof(source));
 | 
			
		||||
			foreach (var item in source)
 | 
			
		||||
				Remove(item);
 | 
			
		||||
		protected bool CanRemove(TEntity data, bool isThrow) {
 | 
			
		||||
			if (data == null) {
 | 
			
		||||
				if (isThrow) throw new ArgumentNullException(nameof(data));
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			if (_table.Primarys.Any() == false) {
 | 
			
		||||
				if (isThrow) throw new Exception($"不可删除,实体没有主键:{_fsql.GetEntityString(data)}");
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			var key = _fsql.GetEntityKeyString(data);
 | 
			
		||||
			if (string.IsNullOrEmpty(key)) {
 | 
			
		||||
				if (isThrow) throw new Exception($"不可删除,未设置主键的值:{_fsql.GetEntityString(data)}");
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			if (_states.TryGetValue(key, out var tryval) == false) {
 | 
			
		||||
				if (isThrow) throw new Exception($"不可更新,数据未被跟踪,应该先查询:{_fsql.GetEntityString(data)}");
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
		#endregion
 | 
			
		||||
		
 | 
			
		||||
		void TrackToList(object list) {
 | 
			
		||||
			if (list == null) return;
 | 
			
		||||
			var ls = list as IList<TEntity>;
 | 
			
		||||
			if (ls == null) return;
 | 
			
		||||
 | 
			
		||||
			foreach (var item in ls) {
 | 
			
		||||
				var key = _fsql.GetEntityKeyString(item);
 | 
			
		||||
				if (_vals.ContainsKey(key)) {
 | 
			
		||||
					_fsql.CopyEntityValue(_vals[key].Value, item);
 | 
			
		||||
					_vals[key].Time = DateTime.Now;
 | 
			
		||||
				if (_states.ContainsKey(key)) {
 | 
			
		||||
					_fsql.MapEntityValue(item, _states[key].Value);
 | 
			
		||||
					_states[key].Time = DateTime.Now;
 | 
			
		||||
				} else {
 | 
			
		||||
					var snap = Activator.CreateInstance<TEntity>();
 | 
			
		||||
					_fsql.CopyEntityValue(snap, item);
 | 
			
		||||
					_vals.Add(key, new EntityState { Value = snap, Key = key, Time = DateTime.Now });
 | 
			
		||||
					_states.Add(key, CreateEntityState(item));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,125 +1 @@
 | 
			
		||||
using FreeSql.Internal.Model;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Data;
 | 
			
		||||
using System.Data.Common;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Linq.Expressions;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using FreeSql.Extensions;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql {
 | 
			
		||||
	abstract partial class DbSet<TEntity> {
 | 
			
		||||
 | 
			
		||||
		async Task<int> DbContextBetcAddAsync(EntityState[] dels) {
 | 
			
		||||
			if (dels.Any() == false) return 0;
 | 
			
		||||
			var affrows = await this.OrmInsert(dels.Select(a => a.Value)).ExecuteAffrowsAsync();
 | 
			
		||||
			return affrows;
 | 
			
		||||
		}
 | 
			
		||||
		async public Task AddAsync(TEntity source) {
 | 
			
		||||
			if (source == null) throw new ArgumentNullException(nameof(source));
 | 
			
		||||
			var key = _fsql.GetEntityKeyString(source);
 | 
			
		||||
			EntityState state = new EntityState();
 | 
			
		||||
			if (string.IsNullOrEmpty(key)) {
 | 
			
		||||
				switch (_fsql.Ado.DataType) {
 | 
			
		||||
					case DataType.SqlServer:
 | 
			
		||||
					case DataType.PostgreSQL:
 | 
			
		||||
						if (_tableIdentitys.Length == 1 && _table.Primarys.Length == 1) {
 | 
			
		||||
							_ctx.ExecCommand();
 | 
			
		||||
							var idtval = await this.OrmInsert(source).ExecuteIdentityAsync();
 | 
			
		||||
							_ctx._affrows++;
 | 
			
		||||
							_fsql.SetEntityIdentityValue(source, idtval);
 | 
			
		||||
						} else {
 | 
			
		||||
							_ctx.ExecCommand();
 | 
			
		||||
							state.Value = (await this.OrmInsert(source).ExecuteInsertedAsync()).First();
 | 
			
		||||
							_ctx._affrows++;
 | 
			
		||||
							_fsql.CopyEntityValue(source, state.Value);
 | 
			
		||||
						}
 | 
			
		||||
						break;
 | 
			
		||||
					case DataType.MySql:
 | 
			
		||||
					case DataType.Oracle:
 | 
			
		||||
					case DataType.Sqlite:
 | 
			
		||||
						if (_tableIdentitys.Length == 1 && _table.Primarys.Length == 1) {
 | 
			
		||||
							_ctx.ExecCommand();
 | 
			
		||||
							var idtval = await this.OrmInsert(source).ExecuteIdentityAsync();
 | 
			
		||||
							_ctx._affrows++;
 | 
			
		||||
							_fsql.SetEntityIdentityValue(source, idtval);
 | 
			
		||||
						} else {
 | 
			
		||||
							throw new Exception($"DbSet.Add 失败,未设置主键的值,或者没有配置自增,或者自增列数不为1:{_fsql.GetEntityString(source)}");
 | 
			
		||||
						}
 | 
			
		||||
						break;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				state.Key = key = _fsql.GetEntityKeyString(source);
 | 
			
		||||
				state.Time = DateTime.Now;
 | 
			
		||||
			} else {
 | 
			
		||||
				if (_vals.ContainsKey(key))
 | 
			
		||||
					throw new Exception($"DbSet.Add 失败,实体数据已存在,请勿重复添加:{_fsql.GetEntityString(source)}");
 | 
			
		||||
				_ctx.EnqueueAction(DbContext.ExecCommandInfoType.Insert, this, typeof(EntityState), state);
 | 
			
		||||
			}
 | 
			
		||||
			if (state.Value == null) {
 | 
			
		||||
				state.Value = Activator.CreateInstance<TEntity>();
 | 
			
		||||
				_fsql.CopyEntityValue(state.Value, source); //copy, 记录旧值版本
 | 
			
		||||
			}
 | 
			
		||||
			_vals.Add(key, state);
 | 
			
		||||
		}
 | 
			
		||||
		async public Task AddRangeAsync(TEntity[] source) {
 | 
			
		||||
			if (source == null) throw new ArgumentNullException(nameof(source));
 | 
			
		||||
			for (var a = 0; a < source.Length; a++)
 | 
			
		||||
				await AddAsync(source[a]);
 | 
			
		||||
		}
 | 
			
		||||
		async public Task AddRangeAsync(IEnumerable<TEntity> source) {
 | 
			
		||||
			if (source == null) throw new ArgumentNullException(nameof(source));
 | 
			
		||||
			foreach (var item in source)
 | 
			
		||||
				await AddAsync(item);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		Task<int> DbContextBetchUpdateAsync(EntityState[] ups) => DbContextBetchUpdatePrivAsync(ups, false);
 | 
			
		||||
		Task<int> DbContextBetchUpdateNowAsync(EntityState[] ups) => DbContextBetchUpdatePrivAsync(ups, true);
 | 
			
		||||
		async Task<int> DbContextBetchUpdatePrivAsync(EntityState[] ups, bool isLiveUpdate) {
 | 
			
		||||
			if (ups.Any() == false) return 0;
 | 
			
		||||
			var uplst1 = ups[ups.Length - 1];
 | 
			
		||||
			var uplst2 = ups.Length > 1 ? ups[ups.Length - 2] : null;
 | 
			
		||||
 | 
			
		||||
			if (_vals.TryGetValue(uplst1.Key, out var lstval1) == false) return -999;
 | 
			
		||||
			var lstval2 = default(EntityState);
 | 
			
		||||
			if (uplst2 != null && _vals.TryGetValue(uplst2.Key, out lstval2) == false) throw new Exception($"DbSet.Update 失败,实体应该先查询再修改:{_fsql.GetEntityString(uplst2.Value)}");
 | 
			
		||||
 | 
			
		||||
			var cuig1 = _fsql.CompareEntityValueReturnColumns(uplst1.Value, lstval1.Value, true);
 | 
			
		||||
			var cuig2 = uplst2 != null ? _fsql.CompareEntityValueReturnColumns(uplst2.Value, lstval2.Value, true) : null;
 | 
			
		||||
			if (uplst2 != null && string.Compare(string.Join(",", cuig1), string.Join(",", cuig2)) != 0) {
 | 
			
		||||
				//最后一个不保存
 | 
			
		||||
				var source = ups.ToList();
 | 
			
		||||
				source.RemoveAt(ups.Length - 1);
 | 
			
		||||
				var affrows = await this.OrmUpdate(null).SetSource(source.Select(a => a.Value)).IgnoreColumns(cuig2).ExecuteAffrowsAsync();
 | 
			
		||||
				foreach (var newval in source) {
 | 
			
		||||
					if (_vals.TryGetValue(newval.Key, out var tryold))
 | 
			
		||||
						_fsql.CopyEntityValue(tryold.Value, newval.Value);
 | 
			
		||||
				}
 | 
			
		||||
				return affrows;
 | 
			
		||||
			} else if (isLiveUpdate) {
 | 
			
		||||
				//立即保存
 | 
			
		||||
				var source = ups;
 | 
			
		||||
				var affrows = await this.OrmUpdate(null).SetSource(source.Select(a => a.Value)).IgnoreColumns(cuig1).ExecuteAffrowsAsync();
 | 
			
		||||
				foreach (var newval in source) {
 | 
			
		||||
					if (_vals.TryGetValue(newval.Key, out var tryold))
 | 
			
		||||
						_fsql.CopyEntityValue(tryold.Value, newval.Value);
 | 
			
		||||
				}
 | 
			
		||||
				return Math.Min(ups.Length, affrows);
 | 
			
		||||
			}
 | 
			
		||||
			//等待下次对比再保存
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		async Task<int> DbContextBetchRemoveAsync(EntityState[] dels) {
 | 
			
		||||
			if (dels.Any() == false) return 0;
 | 
			
		||||
			var affrows = await this.OrmDelete(dels.Select(a => a.Value)).ExecuteAffrowsAsync();
 | 
			
		||||
			//foreach (var del in dels)
 | 
			
		||||
			//	_vals.Remove(del.Key);
 | 
			
		||||
			return affrows;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										216
									
								
								FreeSql.DbContext/DbSetSync.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								FreeSql.DbContext/DbSetSync.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,216 @@
 | 
			
		||||
using FreeSql.Internal.Model;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Data;
 | 
			
		||||
using System.Data.Common;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Linq.Expressions;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using FreeSql.Extensions;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql {
 | 
			
		||||
	partial class DbSet<TEntity> {
 | 
			
		||||
 | 
			
		||||
		int DbContextBetchAdd(EntityState[] adds) {
 | 
			
		||||
			if (adds.Any() == false) return 0;
 | 
			
		||||
			var affrows = this.OrmInsert(adds.Select(a => a.Value)).ExecuteAffrows();
 | 
			
		||||
			return affrows;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		#region Add
 | 
			
		||||
		void AddPriv(TEntity source, bool isCheck) {
 | 
			
		||||
			if (isCheck && CanAdd(source, true) == false) return;
 | 
			
		||||
			if (_tableIdentitys.Length > 0) {
 | 
			
		||||
				//有自增,马上执行
 | 
			
		||||
				switch (_fsql.Ado.DataType) {
 | 
			
		||||
					case DataType.SqlServer:
 | 
			
		||||
					case DataType.PostgreSQL:
 | 
			
		||||
						if (_tableIdentitys.Length == 1 && _table.Primarys.Length == 1) {
 | 
			
		||||
							_ctx.ExecCommand();
 | 
			
		||||
							var idtval = this.OrmInsert(source).ExecuteIdentity();
 | 
			
		||||
							_ctx._affrows++;
 | 
			
		||||
							_fsql.SetEntityIdentityValueWithPrimary(source, idtval);
 | 
			
		||||
							var state = CreateEntityState(source);
 | 
			
		||||
							_states.Add(state.Key, state);
 | 
			
		||||
						} else {
 | 
			
		||||
							_ctx.ExecCommand();
 | 
			
		||||
							var newval = this.OrmInsert(source).ExecuteInserted().First();
 | 
			
		||||
							_ctx._affrows++;
 | 
			
		||||
							_fsql.MapEntityValue(newval, source);
 | 
			
		||||
							var state = CreateEntityState(newval);
 | 
			
		||||
							_states.Add(state.Key, state);
 | 
			
		||||
						}
 | 
			
		||||
						return;
 | 
			
		||||
					case DataType.MySql:
 | 
			
		||||
					case DataType.Oracle:
 | 
			
		||||
					case DataType.Sqlite:
 | 
			
		||||
						if (_tableIdentitys.Length == 1 && _table.Primarys.Length == 1) {
 | 
			
		||||
							_ctx.ExecCommand();
 | 
			
		||||
							var idtval = this.OrmInsert(source).ExecuteIdentity();
 | 
			
		||||
							_ctx._affrows++;
 | 
			
		||||
							_fsql.SetEntityIdentityValueWithPrimary(source, idtval);
 | 
			
		||||
							var state = CreateEntityState(source);
 | 
			
		||||
							_states.Add(state.Key, state);
 | 
			
		||||
						}
 | 
			
		||||
						return;
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				//进入队列,等待 SaveChanges 时执行
 | 
			
		||||
				_ctx.EnqueueAction(DbContext.ExecCommandInfoType.Insert, this, typeof(EntityState), CreateEntityState(source));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		public void Add(TEntity source) => AddPriv(source, true);
 | 
			
		||||
		#endregion
 | 
			
		||||
 | 
			
		||||
		#region AddRange
 | 
			
		||||
		public void AddRange(TEntity[] data) {
 | 
			
		||||
			if (CanAdd(data, true) == false) return;
 | 
			
		||||
			if (data.Length == 1) {
 | 
			
		||||
				Add(data.First());
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			if (_tableIdentitys.Length > 0) {
 | 
			
		||||
				//有自增,马上执行
 | 
			
		||||
				switch (_fsql.Ado.DataType) {
 | 
			
		||||
					case DataType.SqlServer:
 | 
			
		||||
					case DataType.PostgreSQL:
 | 
			
		||||
						_ctx.ExecCommand();
 | 
			
		||||
						var rets = this.OrmInsert(data).ExecuteInserted();
 | 
			
		||||
						if (rets.Count != data.Count()) throw new Exception($"特别错误:批量添加失败,{_fsql.Ado.DataType} 的返回数据,与添加的数目不匹配");
 | 
			
		||||
						var idx = 0;
 | 
			
		||||
						foreach (var s in data)
 | 
			
		||||
							_fsql.MapEntityValue(rets[idx++], s);
 | 
			
		||||
						_ctx._affrows += rets.Count;
 | 
			
		||||
						TrackToList(rets);
 | 
			
		||||
						return;
 | 
			
		||||
					case DataType.MySql:
 | 
			
		||||
					case DataType.Oracle:
 | 
			
		||||
					case DataType.Sqlite:
 | 
			
		||||
						foreach (var s in data)
 | 
			
		||||
							AddPriv(s, false);
 | 
			
		||||
						return;
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				//进入队列,等待 SaveChanges 时执行
 | 
			
		||||
				foreach (var s in data)
 | 
			
		||||
					_ctx.EnqueueAction(DbContext.ExecCommandInfoType.Insert, this, typeof(EntityState), CreateEntityState(s));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		public void AddRange(IEnumerable<TEntity> data) {
 | 
			
		||||
			if (CanAdd(data, true) == false) return;
 | 
			
		||||
			if (data.ElementAtOrDefault(1) == default(TEntity)) {
 | 
			
		||||
				Add(data.First());
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			if (_tableIdentitys.Length > 0) {
 | 
			
		||||
				//有自增,马上执行
 | 
			
		||||
				switch (_fsql.Ado.DataType) {
 | 
			
		||||
					case DataType.SqlServer:
 | 
			
		||||
					case DataType.PostgreSQL:
 | 
			
		||||
						_ctx.ExecCommand();
 | 
			
		||||
						var rets = this.OrmInsert(data).ExecuteInserted();
 | 
			
		||||
						if (rets.Count != data.Count()) throw new Exception($"特别错误:批量添加失败,{_fsql.Ado.DataType} 的返回数据,与添加的数目不匹配");
 | 
			
		||||
						var idx = 0;
 | 
			
		||||
						foreach(var s in data)
 | 
			
		||||
							_fsql.MapEntityValue(rets[idx++], s);
 | 
			
		||||
						_ctx._affrows += rets.Count;
 | 
			
		||||
						TrackToList(rets);
 | 
			
		||||
						return;
 | 
			
		||||
					case DataType.MySql:
 | 
			
		||||
					case DataType.Oracle:
 | 
			
		||||
					case DataType.Sqlite:
 | 
			
		||||
						foreach (var s in data)
 | 
			
		||||
							AddPriv(s, false);
 | 
			
		||||
						return;
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				//进入队列,等待 SaveChanges 时执行
 | 
			
		||||
				foreach (var s in data) 
 | 
			
		||||
					_ctx.EnqueueAction(DbContext.ExecCommandInfoType.Insert, this, typeof(EntityState), CreateEntityState(s));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		#endregion
 | 
			
		||||
 | 
			
		||||
		int DbContextBetchUpdate(EntityState[] ups) => DbContextBetchUpdatePriv(ups, false);
 | 
			
		||||
		int DbContextBetchUpdateNow(EntityState[] ups) => DbContextBetchUpdatePriv(ups, true);
 | 
			
		||||
		int DbContextBetchUpdatePriv(EntityState[] ups, bool isLiveUpdate) {
 | 
			
		||||
			if (ups.Any() == false) return 0;
 | 
			
		||||
			var uplst1 = ups[ups.Length - 1];
 | 
			
		||||
			var uplst2 = ups.Length > 1 ? ups[ups.Length - 2] : null;
 | 
			
		||||
 | 
			
		||||
			if (_states.TryGetValue(uplst1.Key, out var lstval1) == false) return -999;
 | 
			
		||||
			var lstval2 = default(EntityState);
 | 
			
		||||
			if (uplst2 != null && _states.TryGetValue(uplst2.Key, out lstval2) == false) throw new Exception($"特别错误:更新失败,数据未被跟踪:{_fsql.GetEntityString(uplst2.Value)}");
 | 
			
		||||
 | 
			
		||||
			var cuig1 = _fsql.CompareEntityValueReturnColumns(uplst1.Value, lstval1.Value, true);
 | 
			
		||||
			var cuig2 = uplst2 != null ? _fsql.CompareEntityValueReturnColumns(uplst2.Value, lstval2.Value, true) : null;
 | 
			
		||||
			if (uplst2 != null && string.Compare(string.Join(",", cuig1), string.Join(",", cuig2)) != 0) {
 | 
			
		||||
				//最后一个不保存
 | 
			
		||||
				var data = ups.ToList();
 | 
			
		||||
				data.RemoveAt(ups.Length - 1);
 | 
			
		||||
				var affrows = this.OrmUpdate(null).SetSource(data.Select(a => a.Value)).IgnoreColumns(cuig2).ExecuteAffrows();
 | 
			
		||||
				foreach (var newval in data) {
 | 
			
		||||
					if (_states.TryGetValue(newval.Key, out var tryold))
 | 
			
		||||
						_fsql.MapEntityValue(newval.Value, tryold.Value);
 | 
			
		||||
				}
 | 
			
		||||
				return affrows;
 | 
			
		||||
			} else if (isLiveUpdate) {
 | 
			
		||||
				//立即保存
 | 
			
		||||
				var data = ups;
 | 
			
		||||
				var affrows = this.OrmUpdate(null).SetSource(data.Select(a => a.Value)).IgnoreColumns(cuig1).ExecuteAffrows();
 | 
			
		||||
				foreach (var newval in data) {
 | 
			
		||||
					if (_states.TryGetValue(newval.Key, out var tryold))
 | 
			
		||||
						_fsql.MapEntityValue(newval.Value, tryold.Value);
 | 
			
		||||
				}
 | 
			
		||||
				return Math.Min(ups.Length, affrows);
 | 
			
		||||
			}
 | 
			
		||||
			//等待下次对比再保存
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void UpdatePriv(TEntity data, bool isCheck) {
 | 
			
		||||
			if (isCheck && CanUpdate(data, true) == false) return;
 | 
			
		||||
			_ctx.EnqueueAction(DbContext.ExecCommandInfoType.Update, this, typeof(EntityState), CreateEntityState(data));
 | 
			
		||||
		}
 | 
			
		||||
		public void Update(TEntity data) => UpdatePriv(data, true);
 | 
			
		||||
		public void UpdateRange(TEntity[] data) {
 | 
			
		||||
			if (CanUpdate(data, true) == false) return;
 | 
			
		||||
			foreach (var item in data)
 | 
			
		||||
				UpdatePriv(item, false);
 | 
			
		||||
		}
 | 
			
		||||
		public void UpdateRange(IEnumerable<TEntity> data) {
 | 
			
		||||
			if (CanUpdate(data, true) == false) return;
 | 
			
		||||
			foreach (var item in data)
 | 
			
		||||
				UpdatePriv(item, false);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		int DbContextBetchRemove(EntityState[] dels) {
 | 
			
		||||
			if (dels.Any() == false) return 0;
 | 
			
		||||
			var affrows = this.OrmDelete(dels.Select(a => a.Value)).ExecuteAffrows();
 | 
			
		||||
			return affrows;
 | 
			
		||||
		}
 | 
			
		||||
		void RemovePriv(TEntity data, bool isCheck) {
 | 
			
		||||
			if (isCheck && CanRemove(data, true) == false) return;
 | 
			
		||||
			var state = CreateEntityState(data);
 | 
			
		||||
			_ctx.EnqueueAction(DbContext.ExecCommandInfoType.Delete, this, typeof(EntityState), state);
 | 
			
		||||
 | 
			
		||||
			_states.Remove(state.Key);
 | 
			
		||||
			_fsql.ClearEntityPrimaryValueWithIdentityAndGuid(data);
 | 
			
		||||
		}
 | 
			
		||||
		public void Remove(TEntity data) => RemovePriv(data, true);
 | 
			
		||||
		public void RemoveRange(TEntity[] data) {
 | 
			
		||||
			if (CanRemove(data, true) == false) return;
 | 
			
		||||
			foreach (var item in data)
 | 
			
		||||
				RemovePriv(item, false);
 | 
			
		||||
		}
 | 
			
		||||
		public void RemoveRange(IEnumerable<TEntity> data) {
 | 
			
		||||
			if (CanRemove(data, true) == false) return;
 | 
			
		||||
			foreach (var item in data)
 | 
			
		||||
				RemovePriv(item, false);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +1,4 @@
 | 
			
		||||
using FreeSql.Internal.Model;
 | 
			
		||||
using System;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
@@ -17,7 +16,7 @@ namespace FreeSql.Extensions {
 | 
			
		||||
 | 
			
		||||
		static ConcurrentDictionary<DataType, ConcurrentDictionary<Type, Func<object, string>>> _dicGetEntityKeyString = new ConcurrentDictionary<DataType, ConcurrentDictionary<Type, Func<object, string>>>();
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// 获取实体的主键值,以 "*|_,[,_|*" 分割
 | 
			
		||||
		/// 获取实体的主键值,以 "*|_,[,_|*" 分割,当任意一个主键属性无值,返回 null
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		/// <typeparam name="TEntity"></typeparam>
 | 
			
		||||
		/// <param name="_table"></param>
 | 
			
		||||
@@ -40,7 +39,7 @@ namespace FreeSql.Extensions {
 | 
			
		||||
				for (var a = 0; a < pks.Length; a++) {
 | 
			
		||||
					exps.Add(
 | 
			
		||||
						Expression.IfThen(
 | 
			
		||||
							Expression.Equal(var3IsNull, Expression.Constant(false)),
 | 
			
		||||
							Expression.IsFalse(var3IsNull),
 | 
			
		||||
							Expression.IfThenElse(
 | 
			
		||||
								Expression.Equal(Expression.MakeMemberAccess(var1Parm, _table.Properties[pks[a].CsName]), Expression.Default(pks[a].CsType)),
 | 
			
		||||
								Expression.Assign(var3IsNull, Expression.Constant(true)),
 | 
			
		||||
@@ -58,7 +57,7 @@ namespace FreeSql.Extensions {
 | 
			
		||||
				}
 | 
			
		||||
				exps.Add(
 | 
			
		||||
					Expression.IfThen(
 | 
			
		||||
						Expression.Equal(var3IsNull, Expression.Constant(false)),
 | 
			
		||||
						Expression.IsFalse(var3IsNull),
 | 
			
		||||
						Expression.Return(returnTarget, Expression.Call(var2Sb, MethodStringBuilderToString))
 | 
			
		||||
					)
 | 
			
		||||
				);
 | 
			
		||||
@@ -83,43 +82,31 @@ namespace FreeSql.Extensions {
 | 
			
		||||
				var parm1 = Expression.Parameter(typeof(object));
 | 
			
		||||
				var var1Parm = Expression.Variable(t);
 | 
			
		||||
				var var2Sb = Expression.Variable(typeof(StringBuilder));
 | 
			
		||||
				var var3IsNull = Expression.Variable(typeof(bool));
 | 
			
		||||
				var exps = new List<Expression>(new Expression[] {
 | 
			
		||||
					Expression.Assign(var1Parm, Expression.TypeAs(parm1, t)),
 | 
			
		||||
					Expression.Assign(var2Sb, Expression.New(typeof(StringBuilder))),
 | 
			
		||||
					Expression.Assign(var3IsNull, Expression.Constant(false)),
 | 
			
		||||
					Expression.Call(var2Sb, MethodStringBuilderAppend, Expression.Constant("(" ))
 | 
			
		||||
				});
 | 
			
		||||
				var a = 0;
 | 
			
		||||
				foreach (var col in cols.Values) {
 | 
			
		||||
					exps.Add(
 | 
			
		||||
						Expression.IfThen(
 | 
			
		||||
							Expression.Equal(var3IsNull, Expression.Constant(false)),
 | 
			
		||||
							Expression.IfThenElse(
 | 
			
		||||
								Expression.Equal(Expression.MakeMemberAccess(var1Parm, _table.Properties[col.CsName]), Expression.Default(col.CsType)),
 | 
			
		||||
								Expression.Assign(var3IsNull, Expression.Constant(true)),
 | 
			
		||||
								Expression.Block(
 | 
			
		||||
									new Expression[]{
 | 
			
		||||
										a > 0 ? Expression.Call(var2Sb, MethodStringBuilderAppend, Expression.Constant(", " )) : null,
 | 
			
		||||
										Expression.Call(var2Sb, MethodStringBuilderAppend,
 | 
			
		||||
											Expression.Convert(Expression.MakeMemberAccess(var1Parm, _table.Properties[col.CsName]), typeof(object))
 | 
			
		||||
										)
 | 
			
		||||
									}.Where(c => c != null).ToArray()
 | 
			
		||||
						Expression.Block(
 | 
			
		||||
							new Expression[]{
 | 
			
		||||
								a > 0 ? Expression.Call(var2Sb, MethodStringBuilderAppend, Expression.Constant(", " )) : null,
 | 
			
		||||
								Expression.Call(var2Sb, MethodStringBuilderAppend,
 | 
			
		||||
									Expression.Convert(Expression.MakeMemberAccess(var1Parm, _table.Properties[col.CsName]), typeof(object))
 | 
			
		||||
								)
 | 
			
		||||
							)
 | 
			
		||||
							}.Where(c => c != null).ToArray()
 | 
			
		||||
						)
 | 
			
		||||
					);
 | 
			
		||||
					a++;
 | 
			
		||||
				}
 | 
			
		||||
				exps.AddRange(new Expression[] {
 | 
			
		||||
					Expression.Call(var2Sb, MethodStringBuilderAppend, Expression.Constant(")" )),
 | 
			
		||||
					Expression.IfThen(
 | 
			
		||||
						Expression.Equal(var3IsNull, Expression.Constant(false)),
 | 
			
		||||
						Expression.Return(returnTarget, Expression.Call(var2Sb, MethodStringBuilderToString))
 | 
			
		||||
					)
 | 
			
		||||
					Expression.Return(returnTarget, Expression.Call(var2Sb, MethodStringBuilderToString)),
 | 
			
		||||
					Expression.Label(returnTarget, Expression.Default(typeof(string)))
 | 
			
		||||
				});
 | 
			
		||||
				exps.Add(Expression.Label(returnTarget, Expression.Default(typeof(string))));
 | 
			
		||||
				return Expression.Lambda<Func<object, string>>(Expression.Block(new[] { var1Parm, var2Sb, var3IsNull }, exps), new[] { parm1 }).Compile();
 | 
			
		||||
				return Expression.Lambda<Func<object, string>>(Expression.Block(new[] { var1Parm, var2Sb }, exps), new[] { parm1 }).Compile();
 | 
			
		||||
			});
 | 
			
		||||
			return func(item);
 | 
			
		||||
		}
 | 
			
		||||
@@ -128,7 +115,7 @@ namespace FreeSql.Extensions {
 | 
			
		||||
		/// 使用新实体的值,复盖旧实体的值
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		static ConcurrentDictionary<DataType, ConcurrentDictionary<Type, Action<object, object>>> _dicCopyNewValueToEntity = new ConcurrentDictionary<DataType, ConcurrentDictionary<Type, Action<object, object>>>();
 | 
			
		||||
		public static void CopyEntityValue<TEntity>(this IFreeSql orm, TEntity oldValue, TEntity newValue) {
 | 
			
		||||
		public static void MapEntityValue<TEntity>(this IFreeSql orm, TEntity from, TEntity to) {
 | 
			
		||||
			var func = _dicCopyNewValueToEntity.GetOrAdd(orm.Ado.DataType, dt => new ConcurrentDictionary<Type, Action<object, object>>()).GetOrAdd(typeof(TEntity), t => {
 | 
			
		||||
				var _table = orm.CodeFirst.GetTableByEntity(t);
 | 
			
		||||
				var parm1 = Expression.Parameter(typeof(object));
 | 
			
		||||
@@ -143,14 +130,14 @@ namespace FreeSql.Extensions {
 | 
			
		||||
					if (_table.ColumnsByCs.ContainsKey(prop.Name)) {
 | 
			
		||||
						exps.Add(
 | 
			
		||||
							Expression.Assign(
 | 
			
		||||
								Expression.MakeMemberAccess(var1Parm, prop),
 | 
			
		||||
								Expression.MakeMemberAccess(var2Parm, prop)
 | 
			
		||||
								Expression.MakeMemberAccess(var2Parm, prop),
 | 
			
		||||
								Expression.MakeMemberAccess(var1Parm, prop)
 | 
			
		||||
							)
 | 
			
		||||
						);
 | 
			
		||||
					} else {
 | 
			
		||||
						exps.Add(
 | 
			
		||||
							Expression.Assign(
 | 
			
		||||
								Expression.MakeMemberAccess(var1Parm, prop),
 | 
			
		||||
								Expression.MakeMemberAccess(var2Parm, prop),
 | 
			
		||||
								Expression.Default(prop.PropertyType)
 | 
			
		||||
							)
 | 
			
		||||
						);
 | 
			
		||||
@@ -158,19 +145,19 @@ namespace FreeSql.Extensions {
 | 
			
		||||
				}
 | 
			
		||||
				return Expression.Lambda<Action<object, object>>(Expression.Block(new[] { var1Parm, var2Parm }, exps), new[] { parm1, parm2 }).Compile();
 | 
			
		||||
			});
 | 
			
		||||
			func(oldValue, newValue);
 | 
			
		||||
			func(from, to);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		static ConcurrentDictionary<DataType, ConcurrentDictionary<Type, Action<object, long>>> _dicSetEntityIdentityValue = new ConcurrentDictionary<DataType, ConcurrentDictionary<Type, Action<object, long>>>();
 | 
			
		||||
		static ConcurrentDictionary<DataType, ConcurrentDictionary<Type, Action<object, long>>> _dicSetEntityIdentityValueWithPrimary = new ConcurrentDictionary<DataType, ConcurrentDictionary<Type, Action<object, long>>>();
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// 设置实体的自增字段值(若存在)
 | 
			
		||||
		/// 设置实体中主键内的自增字段值(若存在)
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		/// <typeparam name="TEntity"></typeparam>
 | 
			
		||||
		/// <param name="orm"></param>
 | 
			
		||||
		/// <param name="item"></param>
 | 
			
		||||
		/// <param name="idtval"></param>
 | 
			
		||||
		public static void SetEntityIdentityValue<TEntity>(this IFreeSql orm, TEntity item, long idtval) {
 | 
			
		||||
			var func = _dicSetEntityIdentityValue.GetOrAdd(orm.Ado.DataType, dt => new ConcurrentDictionary<Type, Action<object, long>>()).GetOrAdd(typeof(TEntity), t => {
 | 
			
		||||
		public static void SetEntityIdentityValueWithPrimary<TEntity>(this IFreeSql orm, TEntity item, long idtval) {
 | 
			
		||||
			var func = _dicSetEntityIdentityValueWithPrimary.GetOrAdd(orm.Ado.DataType, dt => new ConcurrentDictionary<Type, Action<object, long>>()).GetOrAdd(typeof(TEntity), t => {
 | 
			
		||||
				var _table = orm.CodeFirst.GetTableByEntity(t);
 | 
			
		||||
				var identitys = _table.Primarys.Where(a => a.Attribute.IsIdentity);
 | 
			
		||||
				var parm1 = Expression.Parameter(typeof(object));
 | 
			
		||||
@@ -179,11 +166,12 @@ namespace FreeSql.Extensions {
 | 
			
		||||
				var exps = new List<Expression>(new Expression[] {
 | 
			
		||||
					Expression.Assign(var1Parm, Expression.TypeAs(parm1, t))
 | 
			
		||||
				});
 | 
			
		||||
				foreach (var pk in identitys) {
 | 
			
		||||
				if (identitys.Any()) {
 | 
			
		||||
					var idts0 = identitys.First();
 | 
			
		||||
					exps.Add(
 | 
			
		||||
						Expression.Assign(
 | 
			
		||||
							Expression.MakeMemberAccess(var1Parm, _table.Properties[pk.CsName]),
 | 
			
		||||
							Expression.Convert(FreeSql.Internal.Utils.GetDataReaderValueBlockExpression(pk.CsType, Expression.Convert(parm2, typeof(object))), pk.CsType)
 | 
			
		||||
							Expression.MakeMemberAccess(var1Parm, _table.Properties[idts0.CsName]),
 | 
			
		||||
							Expression.Convert(FreeSql.Internal.Utils.GetDataReaderValueBlockExpression(idts0.CsType, Expression.Convert(parm2, typeof(object))), idts0.CsType)
 | 
			
		||||
						)
 | 
			
		||||
					);
 | 
			
		||||
				}
 | 
			
		||||
@@ -191,6 +179,49 @@ namespace FreeSql.Extensions {
 | 
			
		||||
			});
 | 
			
		||||
			func(item, idtval);
 | 
			
		||||
		}
 | 
			
		||||
		static ConcurrentDictionary<DataType, ConcurrentDictionary<Type, Func<object, long>>> _dicGetEntityIdentityValueWithPrimary = new ConcurrentDictionary<DataType, ConcurrentDictionary<Type, Func<object, long>>>();
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// 获取实体中主键内的自增字段值(若存在)
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		/// <typeparam name="TEntity"></typeparam>
 | 
			
		||||
		/// <param name="orm"></param>
 | 
			
		||||
		/// <param name="item"></param>
 | 
			
		||||
		public static long GetEntityIdentityValueWithPrimary<TEntity>(this IFreeSql orm, TEntity item) {
 | 
			
		||||
			var func = _dicGetEntityIdentityValueWithPrimary.GetOrAdd(orm.Ado.DataType, dt => new ConcurrentDictionary<Type, Func<object, long>>()).GetOrAdd(typeof(TEntity), t => {
 | 
			
		||||
				var _table = orm.CodeFirst.GetTableByEntity(t);
 | 
			
		||||
				var identitys = _table.Primarys.Where(a => a.Attribute.IsIdentity);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
				var returnTarget = Expression.Label(typeof(long));
 | 
			
		||||
				var parm1 = Expression.Parameter(typeof(object));
 | 
			
		||||
				var var1Parm = Expression.Variable(t);
 | 
			
		||||
				var exps = new List<Expression>(new Expression[] {
 | 
			
		||||
					Expression.Assign(var1Parm, Expression.TypeAs(parm1, t))
 | 
			
		||||
				});
 | 
			
		||||
				if (identitys.Any()) {
 | 
			
		||||
					var idts0 = identitys.First();
 | 
			
		||||
					exps.Add(
 | 
			
		||||
						Expression.IfThen(
 | 
			
		||||
							Expression.NotEqual(
 | 
			
		||||
								Expression.MakeMemberAccess(var1Parm, _table.Properties[idts0.CsName]),
 | 
			
		||||
								Expression.Default(idts0.CsType)
 | 
			
		||||
							),
 | 
			
		||||
							Expression.Return(
 | 
			
		||||
								returnTarget, 
 | 
			
		||||
								FreeSql.Internal.Utils.GetDataReaderValueBlockExpression(
 | 
			
		||||
									typeof(long), 
 | 
			
		||||
									Expression.Convert(Expression.MakeMemberAccess(var1Parm, _table.Properties[idts0.CsName]), typeof(object))
 | 
			
		||||
								)
 | 
			
		||||
							)
 | 
			
		||||
						)
 | 
			
		||||
					);
 | 
			
		||||
				}
 | 
			
		||||
				exps.Add(Expression.Label(returnTarget, Expression.Default(typeof(long))));
 | 
			
		||||
				return Expression.Lambda<Func<object, long>>(Expression.Block(new[] { var1Parm }, exps), new[] { parm1 }).Compile();
 | 
			
		||||
			});
 | 
			
		||||
			return func(item);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		static ConcurrentDictionary<DataType, ConcurrentDictionary<Type, Action<object>>> _dicClearEntityPrimaryValueWithIdentityAndGuid = new ConcurrentDictionary<DataType, ConcurrentDictionary<Type, Action<object>>>();
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// 清除实体的主键值,将自增、Guid类型的主键值清除
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
	<PropertyGroup>
 | 
			
		||||
		<TargetFramework>netstandard2.0</TargetFramework>
 | 
			
		||||
		<Version>0.3.23</Version>
 | 
			
		||||
		<Version>0.3.24</Version>
 | 
			
		||||
		<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
 | 
			
		||||
		<Authors>YeXiangQin</Authors>
 | 
			
		||||
		<Description>FreeSql is the most convenient ORM in dotnet. It supports Mysql, Postgresql, SqlServer, Oracle and Sqlite.</Description>
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
	<PropertyGroup>
 | 
			
		||||
		<TargetFramework>netstandard2.0</TargetFramework>
 | 
			
		||||
		<Version>0.3.23</Version>
 | 
			
		||||
		<Version>0.3.24</Version>
 | 
			
		||||
		<Authors>YeXiangQin</Authors>
 | 
			
		||||
		<Description>FreeSql Implementation of General Repository, Support MySql/SqlServer/PostgreSQL/Oracle/Sqlite, and read/write separation、and split table.</Description>
 | 
			
		||||
		<PackageProjectUrl>https://github.com/2881099/FreeSql/wiki/Repository</PackageProjectUrl>
 | 
			
		||||
 
 | 
			
		||||
@@ -25,16 +25,16 @@ namespace FreeSql.Tests.MySql {
 | 
			
		||||
			for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 });
 | 
			
		||||
 | 
			
		||||
			var sql = insert.AppendData(items.First()).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO `tb_topic`(`Clicks`, `Title`, `CreateTime`) VALUES(?Clicks0, ?Title0, ?CreateTime0)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO `tb_topic`(`Clicks`, `Title`, `CreateTime`) VALUES(?Clicks_0, ?Title_0, ?CreateTime_0)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO `tb_topic`(`Clicks`, `Title`, `CreateTime`) VALUES(?Clicks0, ?Title0, ?CreateTime0), (?Clicks1, ?Title1, ?CreateTime1), (?Clicks2, ?Title2, ?CreateTime2), (?Clicks3, ?Title3, ?CreateTime3), (?Clicks4, ?Title4, ?CreateTime4), (?Clicks5, ?Title5, ?CreateTime5), (?Clicks6, ?Title6, ?CreateTime6), (?Clicks7, ?Title7, ?CreateTime7), (?Clicks8, ?Title8, ?CreateTime8), (?Clicks9, ?Title9, ?CreateTime9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO `tb_topic`(`Clicks`, `Title`, `CreateTime`) VALUES(?Clicks_0, ?Title_0, ?CreateTime_0), (?Clicks_1, ?Title_1, ?CreateTime_1), (?Clicks_2, ?Title_2, ?CreateTime_2), (?Clicks_3, ?Title_3, ?CreateTime_3), (?Clicks_4, ?Title_4, ?CreateTime_4), (?Clicks_5, ?Title_5, ?CreateTime_5), (?Clicks_6, ?Title_6, ?CreateTime_6), (?Clicks_7, ?Title_7, ?CreateTime_7), (?Clicks_8, ?Title_8, ?CreateTime_8), (?Clicks_9, ?Title_9, ?CreateTime_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).InsertColumns(a => a.Title).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO `tb_topic`(`Title`) VALUES(?Title0), (?Title1), (?Title2), (?Title3), (?Title4), (?Title5), (?Title6), (?Title7), (?Title8), (?Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO `tb_topic`(`Title`) VALUES(?Title_0), (?Title_1), (?Title_2), (?Title_3), (?Title_4), (?Title_5), (?Title_6), (?Title_7), (?Title_8), (?Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO `tb_topic`(`Clicks`, `Title`) VALUES(?Clicks0, ?Title0), (?Clicks1, ?Title1), (?Clicks2, ?Title2), (?Clicks3, ?Title3), (?Clicks4, ?Title4), (?Clicks5, ?Title5), (?Clicks6, ?Title6), (?Clicks7, ?Title7), (?Clicks8, ?Title8), (?Clicks9, ?Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO `tb_topic`(`Clicks`, `Title`) VALUES(?Clicks_0, ?Title_0), (?Clicks_1, ?Title_1), (?Clicks_2, ?Title_2), (?Clicks_3, ?Title_3), (?Clicks_4, ?Title_4), (?Clicks_5, ?Title_5), (?Clicks_6, ?Title_6), (?Clicks_7, ?Title_7), (?Clicks_8, ?Title_8), (?Clicks_9, ?Title_9)", sql);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[Fact]
 | 
			
		||||
@@ -43,10 +43,10 @@ namespace FreeSql.Tests.MySql {
 | 
			
		||||
			for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 });
 | 
			
		||||
 | 
			
		||||
			var sql = insert.AppendData(items).InsertColumns(a => a.Title).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO `tb_topic`(`Title`) VALUES(?Title0), (?Title1), (?Title2), (?Title3), (?Title4), (?Title5), (?Title6), (?Title7), (?Title8), (?Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO `tb_topic`(`Title`) VALUES(?Title_0), (?Title_1), (?Title_2), (?Title_3), (?Title_4), (?Title_5), (?Title_6), (?Title_7), (?Title_8), (?Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).InsertColumns(a =>new { a.Title, a.Clicks }).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO `tb_topic`(`Clicks`, `Title`) VALUES(?Clicks0, ?Title0), (?Clicks1, ?Title1), (?Clicks2, ?Title2), (?Clicks3, ?Title3), (?Clicks4, ?Title4), (?Clicks5, ?Title5), (?Clicks6, ?Title6), (?Clicks7, ?Title7), (?Clicks8, ?Title8), (?Clicks9, ?Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO `tb_topic`(`Clicks`, `Title`) VALUES(?Clicks_0, ?Title_0), (?Clicks_1, ?Title_1), (?Clicks_2, ?Title_2), (?Clicks_3, ?Title_3), (?Clicks_4, ?Title_4), (?Clicks_5, ?Title_5), (?Clicks_6, ?Title_6), (?Clicks_7, ?Title_7), (?Clicks_8, ?Title_8), (?Clicks_9, ?Title_9)", sql);
 | 
			
		||||
		}
 | 
			
		||||
		[Fact]
 | 
			
		||||
		public void IgnoreColumns() {
 | 
			
		||||
@@ -54,10 +54,10 @@ namespace FreeSql.Tests.MySql {
 | 
			
		||||
			for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 });
 | 
			
		||||
 | 
			
		||||
			var sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO `tb_topic`(`Clicks`, `Title`) VALUES(?Clicks0, ?Title0), (?Clicks1, ?Title1), (?Clicks2, ?Title2), (?Clicks3, ?Title3), (?Clicks4, ?Title4), (?Clicks5, ?Title5), (?Clicks6, ?Title6), (?Clicks7, ?Title7), (?Clicks8, ?Title8), (?Clicks9, ?Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO `tb_topic`(`Clicks`, `Title`) VALUES(?Clicks_0, ?Title_0), (?Clicks_1, ?Title_1), (?Clicks_2, ?Title_2), (?Clicks_3, ?Title_3), (?Clicks_4, ?Title_4), (?Clicks_5, ?Title_5), (?Clicks_6, ?Title_6), (?Clicks_7, ?Title_7), (?Clicks_8, ?Title_8), (?Clicks_9, ?Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).IgnoreColumns(a => new { a.Title, a.CreateTime }).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO `tb_topic`(`Clicks`) VALUES(?Clicks0), (?Clicks1), (?Clicks2), (?Clicks3), (?Clicks4), (?Clicks5), (?Clicks6), (?Clicks7), (?Clicks8), (?Clicks9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO `tb_topic`(`Clicks`) VALUES(?Clicks_0), (?Clicks_1), (?Clicks_2), (?Clicks_3), (?Clicks_4), (?Clicks_5), (?Clicks_6), (?Clicks_7), (?Clicks_8), (?Clicks_9)", sql);
 | 
			
		||||
		}
 | 
			
		||||
		[Fact]
 | 
			
		||||
		public void ExecuteAffrows() {
 | 
			
		||||
@@ -88,28 +88,28 @@ namespace FreeSql.Tests.MySql {
 | 
			
		||||
			for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newTitle{a}", Clicks = a * 100 });
 | 
			
		||||
 | 
			
		||||
			var sql = insert.AppendData(items.First()).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO `Topic_InsertAsTable`(`Clicks`, `Title`, `CreateTime`) VALUES(?Clicks0, ?Title0, ?CreateTime0)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO `Topic_InsertAsTable`(`Clicks`, `Title`, `CreateTime`) VALUES(?Clicks_0, ?Title_0, ?CreateTime_0)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO `Topic_InsertAsTable`(`Clicks`, `Title`, `CreateTime`) VALUES(?Clicks0, ?Title0, ?CreateTime0), (?Clicks1, ?Title1, ?CreateTime1), (?Clicks2, ?Title2, ?CreateTime2), (?Clicks3, ?Title3, ?CreateTime3), (?Clicks4, ?Title4, ?CreateTime4), (?Clicks5, ?Title5, ?CreateTime5), (?Clicks6, ?Title6, ?CreateTime6), (?Clicks7, ?Title7, ?CreateTime7), (?Clicks8, ?Title8, ?CreateTime8), (?Clicks9, ?Title9, ?CreateTime9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO `Topic_InsertAsTable`(`Clicks`, `Title`, `CreateTime`) VALUES(?Clicks_0, ?Title_0, ?CreateTime_0), (?Clicks_1, ?Title_1, ?CreateTime_1), (?Clicks_2, ?Title_2, ?CreateTime_2), (?Clicks_3, ?Title_3, ?CreateTime_3), (?Clicks_4, ?Title_4, ?CreateTime_4), (?Clicks_5, ?Title_5, ?CreateTime_5), (?Clicks_6, ?Title_6, ?CreateTime_6), (?Clicks_7, ?Title_7, ?CreateTime_7), (?Clicks_8, ?Title_8, ?CreateTime_8), (?Clicks_9, ?Title_9, ?CreateTime_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).InsertColumns(a => a.Title).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO `Topic_InsertAsTable`(`Title`) VALUES(?Title0), (?Title1), (?Title2), (?Title3), (?Title4), (?Title5), (?Title6), (?Title7), (?Title8), (?Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO `Topic_InsertAsTable`(`Title`) VALUES(?Title_0), (?Title_1), (?Title_2), (?Title_3), (?Title_4), (?Title_5), (?Title_6), (?Title_7), (?Title_8), (?Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO `Topic_InsertAsTable`(`Clicks`, `Title`) VALUES(?Clicks0, ?Title0), (?Clicks1, ?Title1), (?Clicks2, ?Title2), (?Clicks3, ?Title3), (?Clicks4, ?Title4), (?Clicks5, ?Title5), (?Clicks6, ?Title6), (?Clicks7, ?Title7), (?Clicks8, ?Title8), (?Clicks9, ?Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO `Topic_InsertAsTable`(`Clicks`, `Title`) VALUES(?Clicks_0, ?Title_0), (?Clicks_1, ?Title_1), (?Clicks_2, ?Title_2), (?Clicks_3, ?Title_3), (?Clicks_4, ?Title_4), (?Clicks_5, ?Title_5), (?Clicks_6, ?Title_6), (?Clicks_7, ?Title_7), (?Clicks_8, ?Title_8), (?Clicks_9, ?Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).InsertColumns(a => a.Title).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO `Topic_InsertAsTable`(`Title`) VALUES(?Title0), (?Title1), (?Title2), (?Title3), (?Title4), (?Title5), (?Title6), (?Title7), (?Title8), (?Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO `Topic_InsertAsTable`(`Title`) VALUES(?Title_0), (?Title_1), (?Title_2), (?Title_3), (?Title_4), (?Title_5), (?Title_6), (?Title_7), (?Title_8), (?Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).InsertColumns(a => new { a.Title, a.Clicks }).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO `Topic_InsertAsTable`(`Clicks`, `Title`) VALUES(?Clicks0, ?Title0), (?Clicks1, ?Title1), (?Clicks2, ?Title2), (?Clicks3, ?Title3), (?Clicks4, ?Title4), (?Clicks5, ?Title5), (?Clicks6, ?Title6), (?Clicks7, ?Title7), (?Clicks8, ?Title8), (?Clicks9, ?Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO `Topic_InsertAsTable`(`Clicks`, `Title`) VALUES(?Clicks_0, ?Title_0), (?Clicks_1, ?Title_1), (?Clicks_2, ?Title_2), (?Clicks_3, ?Title_3), (?Clicks_4, ?Title_4), (?Clicks_5, ?Title_5), (?Clicks_6, ?Title_6), (?Clicks_7, ?Title_7), (?Clicks_8, ?Title_8), (?Clicks_9, ?Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO `Topic_InsertAsTable`(`Clicks`, `Title`) VALUES(?Clicks0, ?Title0), (?Clicks1, ?Title1), (?Clicks2, ?Title2), (?Clicks3, ?Title3), (?Clicks4, ?Title4), (?Clicks5, ?Title5), (?Clicks6, ?Title6), (?Clicks7, ?Title7), (?Clicks8, ?Title8), (?Clicks9, ?Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO `Topic_InsertAsTable`(`Clicks`, `Title`) VALUES(?Clicks_0, ?Title_0), (?Clicks_1, ?Title_1), (?Clicks_2, ?Title_2), (?Clicks_3, ?Title_3), (?Clicks_4, ?Title_4), (?Clicks_5, ?Title_5), (?Clicks_6, ?Title_6), (?Clicks_7, ?Title_7), (?Clicks_8, ?Title_8), (?Clicks_9, ?Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).IgnoreColumns(a => new { a.Title, a.CreateTime }).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO `Topic_InsertAsTable`(`Clicks`) VALUES(?Clicks0), (?Clicks1), (?Clicks2), (?Clicks3), (?Clicks4), (?Clicks5), (?Clicks6), (?Clicks7), (?Clicks8), (?Clicks9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO `Topic_InsertAsTable`(`Clicks`) VALUES(?Clicks_0), (?Clicks_1), (?Clicks_2), (?Clicks_3), (?Clicks_4), (?Clicks_5), (?Clicks_6), (?Clicks_7), (?Clicks_8), (?Clicks_9)", sql);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -665,6 +665,8 @@ namespace FreeSql.Tests.MySql {
 | 
			
		||||
			.Having(a => a.Count() < 300 || a.Avg(a.Key.mod4) < 100)
 | 
			
		||||
			.OrderBy(a => a.Key.tt2)
 | 
			
		||||
			.OrderByDescending(a => a.Count())
 | 
			
		||||
			.Offset(10)
 | 
			
		||||
			.Limit(2)
 | 
			
		||||
			.ToList(a => new {
 | 
			
		||||
				a.Key.tt2,
 | 
			
		||||
				cou1 = a.Count(),
 | 
			
		||||
 
 | 
			
		||||
@@ -26,51 +26,51 @@ namespace FreeSql.Tests.Oracle {
 | 
			
		||||
 | 
			
		||||
			var data = new List<object>();
 | 
			
		||||
			var sql = insert.AppendData(items.First()).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"TB_TOPIC_INSERT\"(\"CLICKS\", \"TITLE\", \"CREATETIME\") VALUES(:Clicks0, :Title0, :CreateTime0)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"TB_TOPIC_INSERT\"(\"CLICKS\", \"TITLE\", \"CREATETIME\") VALUES(:Clicks_0, :Title_0, :CreateTime_0)", sql);
 | 
			
		||||
			data.Add(insert.AppendData(items.First()).ExecuteIdentity());
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).ToSql();
 | 
			
		||||
			Assert.Equal(@"INSERT ALL
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks0, :Title0, :CreateTime0)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks1, :Title1, :CreateTime1)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks2, :Title2, :CreateTime2)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks3, :Title3, :CreateTime3)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks4, :Title4, :CreateTime4)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks5, :Title5, :CreateTime5)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks6, :Title6, :CreateTime6)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks7, :Title7, :CreateTime7)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks8, :Title8, :CreateTime8)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks9, :Title9, :CreateTime9)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks_0, :Title_0, :CreateTime_0)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks_1, :Title_1, :CreateTime_1)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks_2, :Title_2, :CreateTime_2)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks_3, :Title_3, :CreateTime_3)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks_4, :Title_4, :CreateTime_4)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks_5, :Title_5, :CreateTime_5)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks_6, :Title_6, :CreateTime_6)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks_7, :Title_7, :CreateTime_7)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks_8, :Title_8, :CreateTime_8)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks_9, :Title_9, :CreateTime_9)
 | 
			
		||||
 SELECT 1 FROM DUAL", sql);
 | 
			
		||||
			data.Add(insert.AppendData(items.First()).ExecuteIdentity());
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).InsertColumns(a => a.Title).ToSql();
 | 
			
		||||
			Assert.Equal(@"INSERT ALL
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title0)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title1)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title2)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title3)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title4)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title5)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title6)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title7)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title8)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title9)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title_0)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title_1)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title_2)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title_3)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title_4)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title_5)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title_6)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title_7)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title_8)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title_9)
 | 
			
		||||
 SELECT 1 FROM DUAL", sql);
 | 
			
		||||
			data.Add(insert.AppendData(items.First()).ExecuteIdentity());
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).ToSql();
 | 
			
		||||
			Assert.Equal(@"INSERT ALL
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks0, :Title0)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks1, :Title1)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks2, :Title2)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks3, :Title3)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks4, :Title4)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks5, :Title5)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks6, :Title6)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks7, :Title7)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks8, :Title8)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks9, :Title9)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_0, :Title_0)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_1, :Title_1)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_2, :Title_2)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_3, :Title_3)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_4, :Title_4)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_5, :Title_5)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_6, :Title_6)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_7, :Title_7)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_8, :Title_8)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_9, :Title_9)
 | 
			
		||||
 SELECT 1 FROM DUAL", sql);
 | 
			
		||||
			data.Add(insert.AppendData(items.First()).ExecuteIdentity());
 | 
			
		||||
		}
 | 
			
		||||
@@ -83,31 +83,31 @@ INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks9, :Title9)
 | 
			
		||||
			var data = new List<object>();
 | 
			
		||||
			var sql = insert.AppendData(items).InsertColumns(a => a.Title).ToSql();
 | 
			
		||||
			Assert.Equal(@"INSERT ALL
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title0)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title1)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title2)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title3)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title4)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title5)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title6)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title7)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title8)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title9)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title_0)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title_1)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title_2)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title_3)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title_4)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title_5)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title_6)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title_7)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title_8)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""TITLE"") VALUES(:Title_9)
 | 
			
		||||
 SELECT 1 FROM DUAL", sql);
 | 
			
		||||
			data.Add(insert.AppendData(items.First()).ExecuteIdentity());
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).InsertColumns(a =>new { a.Title, a.Clicks }).ToSql();
 | 
			
		||||
			Assert.Equal(@"INSERT ALL
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks0, :Title0)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks1, :Title1)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks2, :Title2)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks3, :Title3)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks4, :Title4)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks5, :Title5)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks6, :Title6)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks7, :Title7)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks8, :Title8)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks9, :Title9)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_0, :Title_0)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_1, :Title_1)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_2, :Title_2)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_3, :Title_3)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_4, :Title_4)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_5, :Title_5)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_6, :Title_6)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_7, :Title_7)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_8, :Title_8)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_9, :Title_9)
 | 
			
		||||
 SELECT 1 FROM DUAL", sql);
 | 
			
		||||
			data.Add(insert.AppendData(items.First()).ExecuteIdentity());
 | 
			
		||||
		}
 | 
			
		||||
@@ -119,31 +119,31 @@ INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks9, :Title9)
 | 
			
		||||
			var data = new List<object>();
 | 
			
		||||
			var sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).ToSql();
 | 
			
		||||
			Assert.Equal(@"INSERT ALL
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks0, :Title0)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks1, :Title1)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks2, :Title2)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks3, :Title3)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks4, :Title4)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks5, :Title5)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks6, :Title6)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks7, :Title7)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks8, :Title8)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks9, :Title9)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_0, :Title_0)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_1, :Title_1)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_2, :Title_2)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_3, :Title_3)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_4, :Title_4)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_5, :Title_5)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_6, :Title_6)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_7, :Title_7)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_8, :Title_8)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"", ""TITLE"") VALUES(:Clicks_9, :Title_9)
 | 
			
		||||
 SELECT 1 FROM DUAL", sql);
 | 
			
		||||
			data.Add(insert.AppendData(items.First()).ExecuteIdentity());
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).IgnoreColumns(a => new { a.Title, a.CreateTime }).ToSql();
 | 
			
		||||
			Assert.Equal(@"INSERT ALL
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"") VALUES(:Clicks0)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"") VALUES(:Clicks1)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"") VALUES(:Clicks2)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"") VALUES(:Clicks3)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"") VALUES(:Clicks4)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"") VALUES(:Clicks5)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"") VALUES(:Clicks6)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"") VALUES(:Clicks7)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"") VALUES(:Clicks8)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"") VALUES(:Clicks9)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"") VALUES(:Clicks_0)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"") VALUES(:Clicks_1)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"") VALUES(:Clicks_2)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"") VALUES(:Clicks_3)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"") VALUES(:Clicks_4)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"") VALUES(:Clicks_5)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"") VALUES(:Clicks_6)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"") VALUES(:Clicks_7)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"") VALUES(:Clicks_8)
 | 
			
		||||
INTO ""TB_TOPIC_INSERT""(""CLICKS"") VALUES(:Clicks_9)
 | 
			
		||||
 SELECT 1 FROM DUAL", sql);
 | 
			
		||||
			data.Add(insert.AppendData(items.First()).ExecuteIdentity());
 | 
			
		||||
		}
 | 
			
		||||
@@ -176,104 +176,104 @@ INTO ""TB_TOPIC_INSERT""(""CLICKS"") VALUES(:Clicks9)
 | 
			
		||||
			for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newTitle{a}", Clicks = a * 100 });
 | 
			
		||||
 | 
			
		||||
			var sql = insert.AppendData(items.First()).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"CLICKS\", \"TITLE\", \"CREATETIME\") VALUES(:Clicks0, :Title0, :CreateTime0)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"CLICKS\", \"TITLE\", \"CREATETIME\") VALUES(:Clicks_0, :Title_0, :CreateTime_0)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal(@"INSERT ALL
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks0, :Title0, :CreateTime0)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks1, :Title1, :CreateTime1)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks2, :Title2, :CreateTime2)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks3, :Title3, :CreateTime3)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks4, :Title4, :CreateTime4)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks5, :Title5, :CreateTime5)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks6, :Title6, :CreateTime6)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks7, :Title7, :CreateTime7)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks8, :Title8, :CreateTime8)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks9, :Title9, :CreateTime9)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks_0, :Title_0, :CreateTime_0)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks_1, :Title_1, :CreateTime_1)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks_2, :Title_2, :CreateTime_2)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks_3, :Title_3, :CreateTime_3)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks_4, :Title_4, :CreateTime_4)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks_5, :Title_5, :CreateTime_5)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks_6, :Title_6, :CreateTime_6)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks_7, :Title_7, :CreateTime_7)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks_8, :Title_8, :CreateTime_8)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"", ""CREATETIME"") VALUES(:Clicks_9, :Title_9, :CreateTime_9)
 | 
			
		||||
 SELECT 1 FROM DUAL", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).InsertColumns(a => a.Title).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal(@"INSERT ALL
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title0)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title1)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title2)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title3)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title4)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title5)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title6)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title7)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title8)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title9)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title_0)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title_1)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title_2)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title_3)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title_4)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title_5)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title_6)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title_7)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title_8)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title_9)
 | 
			
		||||
 SELECT 1 FROM DUAL", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal(@"INSERT ALL
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks0, :Title0)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks1, :Title1)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks2, :Title2)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks3, :Title3)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks4, :Title4)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks5, :Title5)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks6, :Title6)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks7, :Title7)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks8, :Title8)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks9, :Title9)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_0, :Title_0)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_1, :Title_1)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_2, :Title_2)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_3, :Title_3)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_4, :Title_4)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_5, :Title_5)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_6, :Title_6)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_7, :Title_7)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_8, :Title_8)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_9, :Title_9)
 | 
			
		||||
 SELECT 1 FROM DUAL", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).InsertColumns(a => a.Title).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal(@"INSERT ALL
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title0)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title1)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title2)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title3)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title4)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title5)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title6)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title7)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title8)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title9)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title_0)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title_1)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title_2)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title_3)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title_4)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title_5)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title_6)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title_7)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title_8)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""TITLE"") VALUES(:Title_9)
 | 
			
		||||
 SELECT 1 FROM DUAL", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).InsertColumns(a => new { a.Title, a.Clicks }).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal(@"INSERT ALL
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks0, :Title0)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks1, :Title1)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks2, :Title2)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks3, :Title3)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks4, :Title4)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks5, :Title5)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks6, :Title6)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks7, :Title7)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks8, :Title8)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks9, :Title9)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_0, :Title_0)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_1, :Title_1)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_2, :Title_2)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_3, :Title_3)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_4, :Title_4)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_5, :Title_5)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_6, :Title_6)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_7, :Title_7)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_8, :Title_8)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_9, :Title_9)
 | 
			
		||||
 SELECT 1 FROM DUAL", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal(@"INSERT ALL
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks0, :Title0)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks1, :Title1)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks2, :Title2)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks3, :Title3)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks4, :Title4)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks5, :Title5)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks6, :Title6)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks7, :Title7)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks8, :Title8)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks9, :Title9)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_0, :Title_0)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_1, :Title_1)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_2, :Title_2)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_3, :Title_3)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_4, :Title_4)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_5, :Title_5)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_6, :Title_6)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_7, :Title_7)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_8, :Title_8)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"", ""TITLE"") VALUES(:Clicks_9, :Title_9)
 | 
			
		||||
 SELECT 1 FROM DUAL", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).IgnoreColumns(a => new { a.Title, a.CreateTime }).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal(@"INSERT ALL
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"") VALUES(:Clicks0)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"") VALUES(:Clicks1)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"") VALUES(:Clicks2)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"") VALUES(:Clicks3)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"") VALUES(:Clicks4)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"") VALUES(:Clicks5)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"") VALUES(:Clicks6)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"") VALUES(:Clicks7)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"") VALUES(:Clicks8)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"") VALUES(:Clicks9)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"") VALUES(:Clicks_0)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"") VALUES(:Clicks_1)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"") VALUES(:Clicks_2)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"") VALUES(:Clicks_3)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"") VALUES(:Clicks_4)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"") VALUES(:Clicks_5)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"") VALUES(:Clicks_6)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"") VALUES(:Clicks_7)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"") VALUES(:Clicks_8)
 | 
			
		||||
INTO ""Topic_InsertAsTable""(""CLICKS"") VALUES(:Clicks_9)
 | 
			
		||||
 SELECT 1 FROM DUAL", sql);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -577,6 +577,8 @@ namespace FreeSql.Tests.Oracle {
 | 
			
		||||
			.Having(a => a.Count() < 300 || a.Avg(a.Key.mod4) < 100)
 | 
			
		||||
			.OrderBy(a => a.Key.tt2)
 | 
			
		||||
			.OrderByDescending(a => a.Count())
 | 
			
		||||
			.Offset(10)
 | 
			
		||||
			.Limit(2)
 | 
			
		||||
			.ToList(a => new {
 | 
			
		||||
				a.Key.tt2,
 | 
			
		||||
				cou1 = a.Count(),
 | 
			
		||||
 
 | 
			
		||||
@@ -25,16 +25,16 @@ namespace FreeSql.Tests.PostgreSQL {
 | 
			
		||||
			for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 });
 | 
			
		||||
 | 
			
		||||
			var sql = insert.AppendData(items.First()).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"clicks\", \"title\", \"createtime\") VALUES(@clicks0, @title0, @createtime0)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"clicks\", \"title\", \"createtime\") VALUES(@clicks_0, @title_0, @createtime_0)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"clicks\", \"title\", \"createtime\") VALUES(@clicks0, @title0, @createtime0), (@clicks1, @title1, @createtime1), (@clicks2, @title2, @createtime2), (@clicks3, @title3, @createtime3), (@clicks4, @title4, @createtime4), (@clicks5, @title5, @createtime5), (@clicks6, @title6, @createtime6), (@clicks7, @title7, @createtime7), (@clicks8, @title8, @createtime8), (@clicks9, @title9, @createtime9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"clicks\", \"title\", \"createtime\") VALUES(@clicks_0, @title_0, @createtime_0), (@clicks_1, @title_1, @createtime_1), (@clicks_2, @title_2, @createtime_2), (@clicks_3, @title_3, @createtime_3), (@clicks_4, @title_4, @createtime_4), (@clicks_5, @title_5, @createtime_5), (@clicks_6, @title_6, @createtime_6), (@clicks_7, @title_7, @createtime_7), (@clicks_8, @title_8, @createtime_8), (@clicks_9, @title_9, @createtime_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).InsertColumns(a => a.Title).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"title\") VALUES(@title0), (@title1), (@title2), (@title3), (@title4), (@title5), (@title6), (@title7), (@title8), (@title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"title\") VALUES(@title_0), (@title_1), (@title_2), (@title_3), (@title_4), (@title_5), (@title_6), (@title_7), (@title_8), (@title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"clicks\", \"title\") VALUES(@clicks0, @title0), (@clicks1, @title1), (@clicks2, @title2), (@clicks3, @title3), (@clicks4, @title4), (@clicks5, @title5), (@clicks6, @title6), (@clicks7, @title7), (@clicks8, @title8), (@clicks9, @title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"clicks\", \"title\") VALUES(@clicks_0, @title_0), (@clicks_1, @title_1), (@clicks_2, @title_2), (@clicks_3, @title_3), (@clicks_4, @title_4), (@clicks_5, @title_5), (@clicks_6, @title_6), (@clicks_7, @title_7), (@clicks_8, @title_8), (@clicks_9, @title_9)", sql);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[Fact]
 | 
			
		||||
@@ -43,10 +43,10 @@ namespace FreeSql.Tests.PostgreSQL {
 | 
			
		||||
			for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 });
 | 
			
		||||
 | 
			
		||||
			var sql = insert.AppendData(items).InsertColumns(a => a.Title).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"title\") VALUES(@title0), (@title1), (@title2), (@title3), (@title4), (@title5), (@title6), (@title7), (@title8), (@title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"title\") VALUES(@title_0), (@title_1), (@title_2), (@title_3), (@title_4), (@title_5), (@title_6), (@title_7), (@title_8), (@title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).InsertColumns(a =>new { a.Title, a.Clicks }).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"clicks\", \"title\") VALUES(@clicks0, @title0), (@clicks1, @title1), (@clicks2, @title2), (@clicks3, @title3), (@clicks4, @title4), (@clicks5, @title5), (@clicks6, @title6), (@clicks7, @title7), (@clicks8, @title8), (@clicks9, @title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"clicks\", \"title\") VALUES(@clicks_0, @title_0), (@clicks_1, @title_1), (@clicks_2, @title_2), (@clicks_3, @title_3), (@clicks_4, @title_4), (@clicks_5, @title_5), (@clicks_6, @title_6), (@clicks_7, @title_7), (@clicks_8, @title_8), (@clicks_9, @title_9)", sql);
 | 
			
		||||
		}
 | 
			
		||||
		[Fact]
 | 
			
		||||
		public void IgnoreColumns() {
 | 
			
		||||
@@ -54,10 +54,10 @@ namespace FreeSql.Tests.PostgreSQL {
 | 
			
		||||
			for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 });
 | 
			
		||||
 | 
			
		||||
			var sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"clicks\", \"title\") VALUES(@clicks0, @title0), (@clicks1, @title1), (@clicks2, @title2), (@clicks3, @title3), (@clicks4, @title4), (@clicks5, @title5), (@clicks6, @title6), (@clicks7, @title7), (@clicks8, @title8), (@clicks9, @title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"clicks\", \"title\") VALUES(@clicks_0, @title_0), (@clicks_1, @title_1), (@clicks_2, @title_2), (@clicks_3, @title_3), (@clicks_4, @title_4), (@clicks_5, @title_5), (@clicks_6, @title_6), (@clicks_7, @title_7), (@clicks_8, @title_8), (@clicks_9, @title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).IgnoreColumns(a => new { a.Title, a.CreateTime }).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"clicks\") VALUES(@clicks0), (@clicks1), (@clicks2), (@clicks3), (@clicks4), (@clicks5), (@clicks6), (@clicks7), (@clicks8), (@clicks9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"clicks\") VALUES(@clicks_0), (@clicks_1), (@clicks_2), (@clicks_3), (@clicks_4), (@clicks_5), (@clicks_6), (@clicks_7), (@clicks_8), (@clicks_9)", sql);
 | 
			
		||||
		}
 | 
			
		||||
		[Fact]
 | 
			
		||||
		public void ExecuteAffrows() {
 | 
			
		||||
@@ -88,28 +88,28 @@ namespace FreeSql.Tests.PostgreSQL {
 | 
			
		||||
			for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newTitle{a}", Clicks = a * 100 });
 | 
			
		||||
 | 
			
		||||
			var sql = insert.AppendData(items.First()).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"clicks\", \"title\", \"createtime\") VALUES(@clicks0, @title0, @createtime0)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"clicks\", \"title\", \"createtime\") VALUES(@clicks_0, @title_0, @createtime_0)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"clicks\", \"title\", \"createtime\") VALUES(@clicks0, @title0, @createtime0), (@clicks1, @title1, @createtime1), (@clicks2, @title2, @createtime2), (@clicks3, @title3, @createtime3), (@clicks4, @title4, @createtime4), (@clicks5, @title5, @createtime5), (@clicks6, @title6, @createtime6), (@clicks7, @title7, @createtime7), (@clicks8, @title8, @createtime8), (@clicks9, @title9, @createtime9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"clicks\", \"title\", \"createtime\") VALUES(@clicks_0, @title_0, @createtime_0), (@clicks_1, @title_1, @createtime_1), (@clicks_2, @title_2, @createtime_2), (@clicks_3, @title_3, @createtime_3), (@clicks_4, @title_4, @createtime_4), (@clicks_5, @title_5, @createtime_5), (@clicks_6, @title_6, @createtime_6), (@clicks_7, @title_7, @createtime_7), (@clicks_8, @title_8, @createtime_8), (@clicks_9, @title_9, @createtime_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).InsertColumns(a => a.Title).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"title\") VALUES(@title0), (@title1), (@title2), (@title3), (@title4), (@title5), (@title6), (@title7), (@title8), (@title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"title\") VALUES(@title_0), (@title_1), (@title_2), (@title_3), (@title_4), (@title_5), (@title_6), (@title_7), (@title_8), (@title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"clicks\", \"title\") VALUES(@clicks0, @title0), (@clicks1, @title1), (@clicks2, @title2), (@clicks3, @title3), (@clicks4, @title4), (@clicks5, @title5), (@clicks6, @title6), (@clicks7, @title7), (@clicks8, @title8), (@clicks9, @title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"clicks\", \"title\") VALUES(@clicks_0, @title_0), (@clicks_1, @title_1), (@clicks_2, @title_2), (@clicks_3, @title_3), (@clicks_4, @title_4), (@clicks_5, @title_5), (@clicks_6, @title_6), (@clicks_7, @title_7), (@clicks_8, @title_8), (@clicks_9, @title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).InsertColumns(a => a.Title).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"title\") VALUES(@title0), (@title1), (@title2), (@title3), (@title4), (@title5), (@title6), (@title7), (@title8), (@title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"title\") VALUES(@title_0), (@title_1), (@title_2), (@title_3), (@title_4), (@title_5), (@title_6), (@title_7), (@title_8), (@title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).InsertColumns(a => new { a.Title, a.Clicks }).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"clicks\", \"title\") VALUES(@clicks0, @title0), (@clicks1, @title1), (@clicks2, @title2), (@clicks3, @title3), (@clicks4, @title4), (@clicks5, @title5), (@clicks6, @title6), (@clicks7, @title7), (@clicks8, @title8), (@clicks9, @title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"clicks\", \"title\") VALUES(@clicks_0, @title_0), (@clicks_1, @title_1), (@clicks_2, @title_2), (@clicks_3, @title_3), (@clicks_4, @title_4), (@clicks_5, @title_5), (@clicks_6, @title_6), (@clicks_7, @title_7), (@clicks_8, @title_8), (@clicks_9, @title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"clicks\", \"title\") VALUES(@clicks0, @title0), (@clicks1, @title1), (@clicks2, @title2), (@clicks3, @title3), (@clicks4, @title4), (@clicks5, @title5), (@clicks6, @title6), (@clicks7, @title7), (@clicks8, @title8), (@clicks9, @title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"clicks\", \"title\") VALUES(@clicks_0, @title_0), (@clicks_1, @title_1), (@clicks_2, @title_2), (@clicks_3, @title_3), (@clicks_4, @title_4), (@clicks_5, @title_5), (@clicks_6, @title_6), (@clicks_7, @title_7), (@clicks_8, @title_8), (@clicks_9, @title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).IgnoreColumns(a => new { a.Title, a.CreateTime }).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"clicks\") VALUES(@clicks0), (@clicks1), (@clicks2), (@clicks3), (@clicks4), (@clicks5), (@clicks6), (@clicks7), (@clicks8), (@clicks9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"clicks\") VALUES(@clicks_0), (@clicks_1), (@clicks_2), (@clicks_3), (@clicks_4), (@clicks_5), (@clicks_6), (@clicks_7), (@clicks_8), (@clicks_9)", sql);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -645,6 +645,8 @@ namespace FreeSql.Tests.PostgreSQL {
 | 
			
		||||
			.Having(a => a.Count() < 300 || a.Avg(a.Key.mod4) < 100)
 | 
			
		||||
			.OrderBy(a => a.Key.tt2)
 | 
			
		||||
			.OrderByDescending(a => a.Count())
 | 
			
		||||
			.Offset(10)
 | 
			
		||||
			.Limit(2)
 | 
			
		||||
			.ToList(a => new {
 | 
			
		||||
				a.Key.tt2,
 | 
			
		||||
				cou1 = a.Count(),
 | 
			
		||||
 
 | 
			
		||||
@@ -35,16 +35,16 @@ namespace FreeSql.Tests.SqlServer {
 | 
			
		||||
			for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100, CreateTime = DateTime.Now });
 | 
			
		||||
 | 
			
		||||
			var sql = insert.IgnoreColumns(a => a.TypeGuid).AppendData(items.First()).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topic]([Clicks], [Title], [CreateTime]) VALUES(@Clicks0, @Title0, @CreateTime0)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topic]([Clicks], [Title], [CreateTime]) VALUES(@Clicks_0, @Title_0, @CreateTime_0)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.IgnoreColumns(a => a.TypeGuid).AppendData(items).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topic]([Clicks], [Title], [CreateTime]) VALUES(@Clicks0, @Title0, @CreateTime0), (@Clicks1, @Title1, @CreateTime1), (@Clicks2, @Title2, @CreateTime2), (@Clicks3, @Title3, @CreateTime3), (@Clicks4, @Title4, @CreateTime4), (@Clicks5, @Title5, @CreateTime5), (@Clicks6, @Title6, @CreateTime6), (@Clicks7, @Title7, @CreateTime7), (@Clicks8, @Title8, @CreateTime8), (@Clicks9, @Title9, @CreateTime9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topic]([Clicks], [Title], [CreateTime]) VALUES(@Clicks_0, @Title_0, @CreateTime_0), (@Clicks_1, @Title_1, @CreateTime_1), (@Clicks_2, @Title_2, @CreateTime_2), (@Clicks_3, @Title_3, @CreateTime_3), (@Clicks_4, @Title_4, @CreateTime_4), (@Clicks_5, @Title_5, @CreateTime_5), (@Clicks_6, @Title_6, @CreateTime_6), (@Clicks_7, @Title_7, @CreateTime_7), (@Clicks_8, @Title_8, @CreateTime_8), (@Clicks_9, @Title_9, @CreateTime_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).InsertColumns(a => a.Title).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topic]([Title]) VALUES(@Title0), (@Title1), (@Title2), (@Title3), (@Title4), (@Title5), (@Title6), (@Title7), (@Title8), (@Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topic]([Title]) VALUES(@Title_0), (@Title_1), (@Title_2), (@Title_3), (@Title_4), (@Title_5), (@Title_6), (@Title_7), (@Title_8), (@Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.IgnoreColumns(a => new { a.CreateTime, a.TypeGuid }).AppendData(items).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topic]([Clicks], [Title]) VALUES(@Clicks0, @Title0), (@Clicks1, @Title1), (@Clicks2, @Title2), (@Clicks3, @Title3), (@Clicks4, @Title4), (@Clicks5, @Title5), (@Clicks6, @Title6), (@Clicks7, @Title7), (@Clicks8, @Title8), (@Clicks9, @Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topic]([Clicks], [Title]) VALUES(@Clicks_0, @Title_0), (@Clicks_1, @Title_1), (@Clicks_2, @Title_2), (@Clicks_3, @Title_3), (@Clicks_4, @Title_4), (@Clicks_5, @Title_5), (@Clicks_6, @Title_6), (@Clicks_7, @Title_7), (@Clicks_8, @Title_8), (@Clicks_9, @Title_9)", sql);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[Fact]
 | 
			
		||||
@@ -53,10 +53,10 @@ namespace FreeSql.Tests.SqlServer {
 | 
			
		||||
			for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100, CreateTime = DateTime.Now });
 | 
			
		||||
 | 
			
		||||
			var sql = insert.AppendData(items).InsertColumns(a => a.Title).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topic]([Title]) VALUES(@Title0), (@Title1), (@Title2), (@Title3), (@Title4), (@Title5), (@Title6), (@Title7), (@Title8), (@Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topic]([Title]) VALUES(@Title_0), (@Title_1), (@Title_2), (@Title_3), (@Title_4), (@Title_5), (@Title_6), (@Title_7), (@Title_8), (@Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).InsertColumns(a =>new { a.Title, a.Clicks }).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topic]([Clicks], [Title]) VALUES(@Clicks0, @Title0), (@Clicks1, @Title1), (@Clicks2, @Title2), (@Clicks3, @Title3), (@Clicks4, @Title4), (@Clicks5, @Title5), (@Clicks6, @Title6), (@Clicks7, @Title7), (@Clicks8, @Title8), (@Clicks9, @Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topic]([Clicks], [Title]) VALUES(@Clicks_0, @Title_0), (@Clicks_1, @Title_1), (@Clicks_2, @Title_2), (@Clicks_3, @Title_3), (@Clicks_4, @Title_4), (@Clicks_5, @Title_5), (@Clicks_6, @Title_6), (@Clicks_7, @Title_7), (@Clicks_8, @Title_8), (@Clicks_9, @Title_9)", sql);
 | 
			
		||||
		}
 | 
			
		||||
		[Fact]
 | 
			
		||||
		public void IgnoreColumns() {
 | 
			
		||||
@@ -64,10 +64,10 @@ namespace FreeSql.Tests.SqlServer {
 | 
			
		||||
			for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100, CreateTime = DateTime.Now });
 | 
			
		||||
 | 
			
		||||
			var sql = insert.AppendData(items).IgnoreColumns(a => new { a.CreateTime, a.TypeGuid }).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topic]([Clicks], [Title]) VALUES(@Clicks0, @Title0), (@Clicks1, @Title1), (@Clicks2, @Title2), (@Clicks3, @Title3), (@Clicks4, @Title4), (@Clicks5, @Title5), (@Clicks6, @Title6), (@Clicks7, @Title7), (@Clicks8, @Title8), (@Clicks9, @Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topic]([Clicks], [Title]) VALUES(@Clicks_0, @Title_0), (@Clicks_1, @Title_1), (@Clicks_2, @Title_2), (@Clicks_3, @Title_3), (@Clicks_4, @Title_4), (@Clicks_5, @Title_5), (@Clicks_6, @Title_6), (@Clicks_7, @Title_7), (@Clicks_8, @Title_8), (@Clicks_9, @Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).IgnoreColumns(a => new { a.Title, a.CreateTime, a.TypeGuid }).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topic]([Clicks]) VALUES(@Clicks0), (@Clicks1), (@Clicks2), (@Clicks3), (@Clicks4), (@Clicks5), (@Clicks6), (@Clicks7), (@Clicks8), (@Clicks9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topic]([Clicks]) VALUES(@Clicks_0), (@Clicks_1), (@Clicks_2), (@Clicks_3), (@Clicks_4), (@Clicks_5), (@Clicks_6), (@Clicks_7), (@Clicks_8), (@Clicks_9)", sql);
 | 
			
		||||
		}
 | 
			
		||||
		[Fact]
 | 
			
		||||
		public void ExecuteAffrows() {
 | 
			
		||||
@@ -111,28 +111,28 @@ namespace FreeSql.Tests.SqlServer {
 | 
			
		||||
			for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100, CreateTime = DateTime.Now });
 | 
			
		||||
 | 
			
		||||
			var sql = insert.IgnoreColumns(a => a.TypeGuid).AppendData(items.First()).AsTable(a => "tb_topicAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topicAsTable]([Clicks], [Title], [CreateTime]) VALUES(@Clicks0, @Title0, @CreateTime0)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topicAsTable]([Clicks], [Title], [CreateTime]) VALUES(@Clicks_0, @Title_0, @CreateTime_0)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.IgnoreColumns(a => a.TypeGuid).AppendData(items).AsTable(a => "tb_topicAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topicAsTable]([Clicks], [Title], [CreateTime]) VALUES(@Clicks0, @Title0, @CreateTime0), (@Clicks1, @Title1, @CreateTime1), (@Clicks2, @Title2, @CreateTime2), (@Clicks3, @Title3, @CreateTime3), (@Clicks4, @Title4, @CreateTime4), (@Clicks5, @Title5, @CreateTime5), (@Clicks6, @Title6, @CreateTime6), (@Clicks7, @Title7, @CreateTime7), (@Clicks8, @Title8, @CreateTime8), (@Clicks9, @Title9, @CreateTime9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topicAsTable]([Clicks], [Title], [CreateTime]) VALUES(@Clicks_0, @Title_0, @CreateTime_0), (@Clicks_1, @Title_1, @CreateTime_1), (@Clicks_2, @Title_2, @CreateTime_2), (@Clicks_3, @Title_3, @CreateTime_3), (@Clicks_4, @Title_4, @CreateTime_4), (@Clicks_5, @Title_5, @CreateTime_5), (@Clicks_6, @Title_6, @CreateTime_6), (@Clicks_7, @Title_7, @CreateTime_7), (@Clicks_8, @Title_8, @CreateTime_8), (@Clicks_9, @Title_9, @CreateTime_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.IgnoreColumns(a => a.TypeGuid).AppendData(items).InsertColumns(a => a.Title).AsTable(a => "tb_topicAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topicAsTable]([Title]) VALUES(@Title0), (@Title1), (@Title2), (@Title3), (@Title4), (@Title5), (@Title6), (@Title7), (@Title8), (@Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topicAsTable]([Title]) VALUES(@Title_0), (@Title_1), (@Title_2), (@Title_3), (@Title_4), (@Title_5), (@Title_6), (@Title_7), (@Title_8), (@Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.IgnoreColumns(a => new { a.CreateTime, a.TypeGuid }).AppendData(items).AsTable(a => "tb_topicAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topicAsTable]([Clicks], [Title]) VALUES(@Clicks0, @Title0), (@Clicks1, @Title1), (@Clicks2, @Title2), (@Clicks3, @Title3), (@Clicks4, @Title4), (@Clicks5, @Title5), (@Clicks6, @Title6), (@Clicks7, @Title7), (@Clicks8, @Title8), (@Clicks9, @Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topicAsTable]([Clicks], [Title]) VALUES(@Clicks_0, @Title_0), (@Clicks_1, @Title_1), (@Clicks_2, @Title_2), (@Clicks_3, @Title_3), (@Clicks_4, @Title_4), (@Clicks_5, @Title_5), (@Clicks_6, @Title_6), (@Clicks_7, @Title_7), (@Clicks_8, @Title_8), (@Clicks_9, @Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.IgnoreColumns(a => new { a.Title, a.TypeGuid }).InsertColumns(a => a.Title).AppendData(items).AsTable(a => "tb_topicAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topicAsTable]([Title]) VALUES(@Title0), (@Title1), (@Title2), (@Title3), (@Title4), (@Title5), (@Title6), (@Title7), (@Title8), (@Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topicAsTable]([Title]) VALUES(@Title_0), (@Title_1), (@Title_2), (@Title_3), (@Title_4), (@Title_5), (@Title_6), (@Title_7), (@Title_8), (@Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.IgnoreColumns(a => a.TypeGuid).AppendData(items).InsertColumns(a => new { a.Title, a.Clicks }).AsTable(a => "tb_topicAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topicAsTable]([Clicks], [Title]) VALUES(@Clicks0, @Title0), (@Clicks1, @Title1), (@Clicks2, @Title2), (@Clicks3, @Title3), (@Clicks4, @Title4), (@Clicks5, @Title5), (@Clicks6, @Title6), (@Clicks7, @Title7), (@Clicks8, @Title8), (@Clicks9, @Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topicAsTable]([Clicks], [Title]) VALUES(@Clicks_0, @Title_0), (@Clicks_1, @Title_1), (@Clicks_2, @Title_2), (@Clicks_3, @Title_3), (@Clicks_4, @Title_4), (@Clicks_5, @Title_5), (@Clicks_6, @Title_6), (@Clicks_7, @Title_7), (@Clicks_8, @Title_8), (@Clicks_9, @Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.IgnoreColumns(a => new { a.CreateTime, a.TypeGuid }).AppendData(items).AsTable(a => "tb_topicAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topicAsTable]([Clicks], [Title]) VALUES(@Clicks0, @Title0), (@Clicks1, @Title1), (@Clicks2, @Title2), (@Clicks3, @Title3), (@Clicks4, @Title4), (@Clicks5, @Title5), (@Clicks6, @Title6), (@Clicks7, @Title7), (@Clicks8, @Title8), (@Clicks9, @Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topicAsTable]([Clicks], [Title]) VALUES(@Clicks_0, @Title_0), (@Clicks_1, @Title_1), (@Clicks_2, @Title_2), (@Clicks_3, @Title_3), (@Clicks_4, @Title_4), (@Clicks_5, @Title_5), (@Clicks_6, @Title_6), (@Clicks_7, @Title_7), (@Clicks_8, @Title_8), (@Clicks_9, @Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.IgnoreColumns(a => new { a.CreateTime, a.Title, a.TypeGuid }).AppendData(items).AsTable(a => "tb_topicAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topicAsTable]([Clicks]) VALUES(@Clicks0), (@Clicks1), (@Clicks2), (@Clicks3), (@Clicks4), (@Clicks5), (@Clicks6), (@Clicks7), (@Clicks8), (@Clicks9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO [tb_topicAsTable]([Clicks]) VALUES(@Clicks_0), (@Clicks_1), (@Clicks_2), (@Clicks_3), (@Clicks_4), (@Clicks_5), (@Clicks_6), (@Clicks_7), (@Clicks_8), (@Clicks_9)", sql);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -579,6 +579,8 @@ namespace FreeSql.Tests.SqlServer {
 | 
			
		||||
			.Having(a => a.Count() < 300 || a.Avg(a.Key.mod4) < 100)
 | 
			
		||||
			.OrderBy(a => a.Key.tt2)
 | 
			
		||||
			.OrderByDescending(a => a.Count())
 | 
			
		||||
			.Offset(10)
 | 
			
		||||
			.Limit(2)
 | 
			
		||||
			.ToList(a => new {
 | 
			
		||||
				a.Key.tt2,
 | 
			
		||||
				cou1 = a.Count(),
 | 
			
		||||
 
 | 
			
		||||
@@ -25,16 +25,16 @@ namespace FreeSql.Tests.Sqlite {
 | 
			
		||||
			for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newTitle{a}", Clicks = a * 100 });
 | 
			
		||||
 | 
			
		||||
			var sql = insert.AppendData(items.First()).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"Clicks\", \"Title\", \"CreateTime\") VALUES(@Clicks0, @Title0, @CreateTime0)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"Clicks\", \"Title\", \"CreateTime\") VALUES(@Clicks_0, @Title_0, @CreateTime_0)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"Clicks\", \"Title\", \"CreateTime\") VALUES(@Clicks0, @Title0, @CreateTime0), (@Clicks1, @Title1, @CreateTime1), (@Clicks2, @Title2, @CreateTime2), (@Clicks3, @Title3, @CreateTime3), (@Clicks4, @Title4, @CreateTime4), (@Clicks5, @Title5, @CreateTime5), (@Clicks6, @Title6, @CreateTime6), (@Clicks7, @Title7, @CreateTime7), (@Clicks8, @Title8, @CreateTime8), (@Clicks9, @Title9, @CreateTime9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"Clicks\", \"Title\", \"CreateTime\") VALUES(@Clicks_0, @Title_0, @CreateTime_0), (@Clicks_1, @Title_1, @CreateTime_1), (@Clicks_2, @Title_2, @CreateTime_2), (@Clicks_3, @Title_3, @CreateTime_3), (@Clicks_4, @Title_4, @CreateTime_4), (@Clicks_5, @Title_5, @CreateTime_5), (@Clicks_6, @Title_6, @CreateTime_6), (@Clicks_7, @Title_7, @CreateTime_7), (@Clicks_8, @Title_8, @CreateTime_8), (@Clicks_9, @Title_9, @CreateTime_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).InsertColumns(a => a.Title).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"Title\") VALUES(@Title0), (@Title1), (@Title2), (@Title3), (@Title4), (@Title5), (@Title6), (@Title7), (@Title8), (@Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"Title\") VALUES(@Title_0), (@Title_1), (@Title_2), (@Title_3), (@Title_4), (@Title_5), (@Title_6), (@Title_7), (@Title_8), (@Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"Clicks\", \"Title\") VALUES(@Clicks0, @Title0), (@Clicks1, @Title1), (@Clicks2, @Title2), (@Clicks3, @Title3), (@Clicks4, @Title4), (@Clicks5, @Title5), (@Clicks6, @Title6), (@Clicks7, @Title7), (@Clicks8, @Title8), (@Clicks9, @Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"Clicks\", \"Title\") VALUES(@Clicks_0, @Title_0), (@Clicks_1, @Title_1), (@Clicks_2, @Title_2), (@Clicks_3, @Title_3), (@Clicks_4, @Title_4), (@Clicks_5, @Title_5), (@Clicks_6, @Title_6), (@Clicks_7, @Title_7), (@Clicks_8, @Title_8), (@Clicks_9, @Title_9)", sql);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[Fact]
 | 
			
		||||
@@ -43,10 +43,10 @@ namespace FreeSql.Tests.Sqlite {
 | 
			
		||||
			for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newTitle{a}", Clicks = a * 100 });
 | 
			
		||||
 | 
			
		||||
			var sql = insert.AppendData(items).InsertColumns(a => a.Title).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"Title\") VALUES(@Title0), (@Title1), (@Title2), (@Title3), (@Title4), (@Title5), (@Title6), (@Title7), (@Title8), (@Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"Title\") VALUES(@Title_0), (@Title_1), (@Title_2), (@Title_3), (@Title_4), (@Title_5), (@Title_6), (@Title_7), (@Title_8), (@Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).InsertColumns(a => new { a.Title, a.Clicks }).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"Clicks\", \"Title\") VALUES(@Clicks0, @Title0), (@Clicks1, @Title1), (@Clicks2, @Title2), (@Clicks3, @Title3), (@Clicks4, @Title4), (@Clicks5, @Title5), (@Clicks6, @Title6), (@Clicks7, @Title7), (@Clicks8, @Title8), (@Clicks9, @Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"Clicks\", \"Title\") VALUES(@Clicks_0, @Title_0), (@Clicks_1, @Title_1), (@Clicks_2, @Title_2), (@Clicks_3, @Title_3), (@Clicks_4, @Title_4), (@Clicks_5, @Title_5), (@Clicks_6, @Title_6), (@Clicks_7, @Title_7), (@Clicks_8, @Title_8), (@Clicks_9, @Title_9)", sql);
 | 
			
		||||
		}
 | 
			
		||||
		[Fact]
 | 
			
		||||
		public void IgnoreColumns() {
 | 
			
		||||
@@ -54,10 +54,10 @@ namespace FreeSql.Tests.Sqlite {
 | 
			
		||||
			for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newTitle{a}", Clicks = a * 100 });
 | 
			
		||||
 | 
			
		||||
			var sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"Clicks\", \"Title\") VALUES(@Clicks0, @Title0), (@Clicks1, @Title1), (@Clicks2, @Title2), (@Clicks3, @Title3), (@Clicks4, @Title4), (@Clicks5, @Title5), (@Clicks6, @Title6), (@Clicks7, @Title7), (@Clicks8, @Title8), (@Clicks9, @Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"Clicks\", \"Title\") VALUES(@Clicks_0, @Title_0), (@Clicks_1, @Title_1), (@Clicks_2, @Title_2), (@Clicks_3, @Title_3), (@Clicks_4, @Title_4), (@Clicks_5, @Title_5), (@Clicks_6, @Title_6), (@Clicks_7, @Title_7), (@Clicks_8, @Title_8), (@Clicks_9, @Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).IgnoreColumns(a => new { a.Title, a.CreateTime }).ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"Clicks\") VALUES(@Clicks0), (@Clicks1), (@Clicks2), (@Clicks3), (@Clicks4), (@Clicks5), (@Clicks6), (@Clicks7), (@Clicks8), (@Clicks9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"tb_topic_insert\"(\"Clicks\") VALUES(@Clicks_0), (@Clicks_1), (@Clicks_2), (@Clicks_3), (@Clicks_4), (@Clicks_5), (@Clicks_6), (@Clicks_7), (@Clicks_8), (@Clicks_9)", sql);
 | 
			
		||||
		}
 | 
			
		||||
		[Fact]
 | 
			
		||||
		public void ExecuteAffrows() {
 | 
			
		||||
@@ -84,28 +84,28 @@ namespace FreeSql.Tests.Sqlite {
 | 
			
		||||
			for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newTitle{a}", Clicks = a * 100 });
 | 
			
		||||
 | 
			
		||||
			var sql = insert.AppendData(items.First()).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"Clicks\", \"Title\", \"CreateTime\") VALUES(@Clicks0, @Title0, @CreateTime0)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"Clicks\", \"Title\", \"CreateTime\") VALUES(@Clicks_0, @Title_0, @CreateTime_0)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"Clicks\", \"Title\", \"CreateTime\") VALUES(@Clicks0, @Title0, @CreateTime0), (@Clicks1, @Title1, @CreateTime1), (@Clicks2, @Title2, @CreateTime2), (@Clicks3, @Title3, @CreateTime3), (@Clicks4, @Title4, @CreateTime4), (@Clicks5, @Title5, @CreateTime5), (@Clicks6, @Title6, @CreateTime6), (@Clicks7, @Title7, @CreateTime7), (@Clicks8, @Title8, @CreateTime8), (@Clicks9, @Title9, @CreateTime9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"Clicks\", \"Title\", \"CreateTime\") VALUES(@Clicks_0, @Title_0, @CreateTime_0), (@Clicks_1, @Title_1, @CreateTime_1), (@Clicks_2, @Title_2, @CreateTime_2), (@Clicks_3, @Title_3, @CreateTime_3), (@Clicks_4, @Title_4, @CreateTime_4), (@Clicks_5, @Title_5, @CreateTime_5), (@Clicks_6, @Title_6, @CreateTime_6), (@Clicks_7, @Title_7, @CreateTime_7), (@Clicks_8, @Title_8, @CreateTime_8), (@Clicks_9, @Title_9, @CreateTime_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).InsertColumns(a => a.Title).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"Title\") VALUES(@Title0), (@Title1), (@Title2), (@Title3), (@Title4), (@Title5), (@Title6), (@Title7), (@Title8), (@Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"Title\") VALUES(@Title_0), (@Title_1), (@Title_2), (@Title_3), (@Title_4), (@Title_5), (@Title_6), (@Title_7), (@Title_8), (@Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"Clicks\", \"Title\") VALUES(@Clicks0, @Title0), (@Clicks1, @Title1), (@Clicks2, @Title2), (@Clicks3, @Title3), (@Clicks4, @Title4), (@Clicks5, @Title5), (@Clicks6, @Title6), (@Clicks7, @Title7), (@Clicks8, @Title8), (@Clicks9, @Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"Clicks\", \"Title\") VALUES(@Clicks_0, @Title_0), (@Clicks_1, @Title_1), (@Clicks_2, @Title_2), (@Clicks_3, @Title_3), (@Clicks_4, @Title_4), (@Clicks_5, @Title_5), (@Clicks_6, @Title_6), (@Clicks_7, @Title_7), (@Clicks_8, @Title_8), (@Clicks_9, @Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).InsertColumns(a => a.Title).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"Title\") VALUES(@Title0), (@Title1), (@Title2), (@Title3), (@Title4), (@Title5), (@Title6), (@Title7), (@Title8), (@Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"Title\") VALUES(@Title_0), (@Title_1), (@Title_2), (@Title_3), (@Title_4), (@Title_5), (@Title_6), (@Title_7), (@Title_8), (@Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).InsertColumns(a => new { a.Title, a.Clicks }).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"Clicks\", \"Title\") VALUES(@Clicks0, @Title0), (@Clicks1, @Title1), (@Clicks2, @Title2), (@Clicks3, @Title3), (@Clicks4, @Title4), (@Clicks5, @Title5), (@Clicks6, @Title6), (@Clicks7, @Title7), (@Clicks8, @Title8), (@Clicks9, @Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"Clicks\", \"Title\") VALUES(@Clicks_0, @Title_0), (@Clicks_1, @Title_1), (@Clicks_2, @Title_2), (@Clicks_3, @Title_3), (@Clicks_4, @Title_4), (@Clicks_5, @Title_5), (@Clicks_6, @Title_6), (@Clicks_7, @Title_7), (@Clicks_8, @Title_8), (@Clicks_9, @Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"Clicks\", \"Title\") VALUES(@Clicks0, @Title0), (@Clicks1, @Title1), (@Clicks2, @Title2), (@Clicks3, @Title3), (@Clicks4, @Title4), (@Clicks5, @Title5), (@Clicks6, @Title6), (@Clicks7, @Title7), (@Clicks8, @Title8), (@Clicks9, @Title9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"Clicks\", \"Title\") VALUES(@Clicks_0, @Title_0), (@Clicks_1, @Title_1), (@Clicks_2, @Title_2), (@Clicks_3, @Title_3), (@Clicks_4, @Title_4), (@Clicks_5, @Title_5), (@Clicks_6, @Title_6), (@Clicks_7, @Title_7), (@Clicks_8, @Title_8), (@Clicks_9, @Title_9)", sql);
 | 
			
		||||
 | 
			
		||||
			sql = insert.AppendData(items).IgnoreColumns(a => new { a.Title, a.CreateTime }).AsTable(a => "Topic_InsertAsTable").ToSql();
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"Clicks\") VALUES(@Clicks0), (@Clicks1), (@Clicks2), (@Clicks3), (@Clicks4), (@Clicks5), (@Clicks6), (@Clicks7), (@Clicks8), (@Clicks9)", sql);
 | 
			
		||||
			Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"Clicks\") VALUES(@Clicks_0), (@Clicks_1), (@Clicks_2), (@Clicks_3), (@Clicks_4), (@Clicks_5), (@Clicks_6), (@Clicks_7), (@Clicks_8), (@Clicks_9)", sql);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -506,6 +506,8 @@ namespace FreeSql.Tests.Sqlite {
 | 
			
		||||
			.Having(a => a.Count() < 300 || a.Avg(a.Key.mod4) < 100)
 | 
			
		||||
			.OrderBy(a => a.Key.tt2)
 | 
			
		||||
			.OrderByDescending(a => a.Count())
 | 
			
		||||
			.Offset(10)
 | 
			
		||||
			.Limit(2)
 | 
			
		||||
			.ToList(a => new {
 | 
			
		||||
				a.Key.tt2,
 | 
			
		||||
				cou1 = a.Count(),
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
	<PropertyGroup>
 | 
			
		||||
		<TargetFramework>netstandard2.0</TargetFramework>
 | 
			
		||||
		<Version>0.3.23</Version>
 | 
			
		||||
		<Version>0.3.24</Version>
 | 
			
		||||
		<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
 | 
			
		||||
		<Authors>YeXiangQin</Authors>
 | 
			
		||||
		<Description>FreeSql is the most convenient ORM in dotnet. It supports Mysql, Postgresql, SqlServer, Oracle and Sqlite.</Description>
 | 
			
		||||
 
 | 
			
		||||
@@ -43,6 +43,40 @@ namespace FreeSql {
 | 
			
		||||
		/// <param name="select">选择列</param>
 | 
			
		||||
		/// <returns></returns>
 | 
			
		||||
		string ToSql<TReturn>(Expression<Func<ISelectGroupingAggregate<T1>, TReturn>> select);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// 查询向后偏移行数
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		/// <param name="offset"></param>
 | 
			
		||||
		/// <returns></returns>
 | 
			
		||||
		ISelectGrouping<T1> Skip(int offset);
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// 查询向后偏移行数
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		/// <param name="offset">行数</param>
 | 
			
		||||
		/// <returns></returns>
 | 
			
		||||
		ISelectGrouping<T1> Offset(int offset);
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// 查询多少条数据
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		/// <param name="limit"></param>
 | 
			
		||||
		/// <returns></returns>
 | 
			
		||||
		ISelectGrouping<T1> Limit(int limit);
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// 查询多少条数据
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		/// <param name="limit"></param>
 | 
			
		||||
		/// <returns></returns>
 | 
			
		||||
		ISelectGrouping<T1> Take(int limit);
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// 分页
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		/// <param name="pageIndex">第几页</param>
 | 
			
		||||
		/// <param name="pageSize">每页多少</param>
 | 
			
		||||
		/// <returns></returns>
 | 
			
		||||
		ISelectGrouping<T1> Page(int pageIndex, int pageSize);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public interface ISelectGroupingAggregate<T1> {
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,14 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure<T1>();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		protected void ClearData() {
 | 
			
		||||
			_source.Clear();
 | 
			
		||||
			_where.Clear();
 | 
			
		||||
			_whereTimes = 0;
 | 
			
		||||
			_params.Clear();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		public IDelete<T1> WithTransaction(DbTransaction transaction) {
 | 
			
		||||
			_transaction = transaction;
 | 
			
		||||
			return this;
 | 
			
		||||
@@ -38,12 +46,16 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
		public int ExecuteAffrows() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
			if (string.IsNullOrEmpty(sql)) return 0;
 | 
			
		||||
			return _orm.Ado.ExecuteNonQuery(_transaction, CommandType.Text, sql, _params.ToArray());
 | 
			
		||||
			var affrows = _orm.Ado.ExecuteNonQuery(_transaction, CommandType.Text, sql, _params.ToArray());
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return affrows;
 | 
			
		||||
		}
 | 
			
		||||
		async public Task<int> ExecuteAffrowsAsync() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
			if (string.IsNullOrEmpty(sql)) return 0;
 | 
			
		||||
			return await _orm.Ado.ExecuteNonQueryAsync(_transaction, CommandType.Text, sql, _params.ToArray());
 | 
			
		||||
			var affrows = await _orm.Ado.ExecuteNonQueryAsync(_transaction, CommandType.Text, sql, _params.ToArray());
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return affrows;
 | 
			
		||||
		}
 | 
			
		||||
		public abstract List<T1> ExecuteDeleted();
 | 
			
		||||
		public abstract Task<List<T1>> ExecuteDeletedAsync();
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,12 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure<T1>();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		protected void ClearData() {
 | 
			
		||||
			_source.Clear();
 | 
			
		||||
			_ignore.Clear();
 | 
			
		||||
			_params = null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public IInsert<T1> WithTransaction(DbTransaction transaction) {
 | 
			
		||||
			_transaction = transaction;
 | 
			
		||||
			return this;
 | 
			
		||||
@@ -267,8 +273,16 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
		}
 | 
			
		||||
		#endregion
 | 
			
		||||
 | 
			
		||||
		internal int RawExecuteAffrows() => _orm.Ado.ExecuteNonQuery(_transaction, CommandType.Text, ToSql(), _params);
 | 
			
		||||
		internal Task<int> RawExecuteAffrowsAsync() => _orm.Ado.ExecuteNonQueryAsync(_transaction, CommandType.Text, ToSql(), _params);
 | 
			
		||||
		internal int RawExecuteAffrows() {
 | 
			
		||||
			var affrows = _orm.Ado.ExecuteNonQuery(_transaction, CommandType.Text, ToSql(), _params);
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return affrows;
 | 
			
		||||
		}
 | 
			
		||||
		async internal Task<int> RawExecuteAffrowsAsync() {
 | 
			
		||||
			var affrows = await _orm.Ado.ExecuteNonQueryAsync(_transaction, CommandType.Text, ToSql(), _params);
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return affrows;
 | 
			
		||||
		}
 | 
			
		||||
		internal abstract long RawExecuteIdentity();
 | 
			
		||||
		internal abstract Task<long> RawExecuteIdentityAsync();
 | 
			
		||||
		internal abstract List<T1> RawExecuteInserted();
 | 
			
		||||
@@ -331,8 +345,8 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
						if (_noneParameter)
 | 
			
		||||
							sb.Append(_commonUtils.GetNoneParamaterSqlValue(specialParams, col.CsType, val));
 | 
			
		||||
						else {
 | 
			
		||||
							sb.Append(_commonUtils.QuoteWriteParamter(col.CsType, _commonUtils.QuoteParamterName($"{col.CsName}{didx}")));
 | 
			
		||||
							_params[didx * colidx + colidx2] = _commonUtils.AppendParamter(null, $"{col.CsName}{didx}", col.CsType, val);
 | 
			
		||||
							sb.Append(_commonUtils.QuoteWriteParamter(col.CsType, _commonUtils.QuoteParamterName($"{col.CsName}_{didx}")));
 | 
			
		||||
							_params[didx * colidx + colidx2] = _commonUtils.AppendParamter(null, $"{col.CsName}_{didx}", col.CsType, val);
 | 
			
		||||
						}
 | 
			
		||||
						++colidx2;
 | 
			
		||||
					}
 | 
			
		||||
 
 | 
			
		||||
@@ -79,5 +79,25 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			var method = _select.GetType().GetMethod("ToSql", new[] { typeof(string) });
 | 
			
		||||
			return method.Invoke(_select, new object[] { field.Length > 0 ? field.Remove(0, 2).ToString() : null }) as string;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public ISelectGrouping<T1> Skip(int offset) {
 | 
			
		||||
			var method = _select.GetType().GetMethod("Skip", new[] { typeof(int) });
 | 
			
		||||
			method.Invoke(_select, new object[] { offset });
 | 
			
		||||
			return this;
 | 
			
		||||
		}
 | 
			
		||||
		public ISelectGrouping<T1> Offset(int offset) => this.Skip(offset);
 | 
			
		||||
 | 
			
		||||
		public ISelectGrouping<T1> Limit(int limit) {
 | 
			
		||||
			var method = _select.GetType().GetMethod("Limit", new[] { typeof(int) });
 | 
			
		||||
			method.Invoke(_select, new object[] { limit });
 | 
			
		||||
			return this;
 | 
			
		||||
		}
 | 
			
		||||
		public ISelectGrouping<T1> Take(int limit) => this.Limit(limit);
 | 
			
		||||
 | 
			
		||||
		public ISelectGrouping<T1> Page(int pageIndex, int pageSize) {
 | 
			
		||||
			var method = _select.GetType().GetMethod("Page", new[] { typeof(int), typeof(int) });
 | 
			
		||||
			method.Invoke(_select, new object[] { pageIndex, pageSize });
 | 
			
		||||
			return this;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -35,6 +35,15 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure<T1>();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		protected void ClearData() {
 | 
			
		||||
			_source.Clear();
 | 
			
		||||
			_ignore.Clear();
 | 
			
		||||
			_where.Clear();
 | 
			
		||||
			_set.Clear();
 | 
			
		||||
			_params.Clear();
 | 
			
		||||
			_paramsSource.Clear();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public IUpdate<T1> WithTransaction(DbTransaction transaction) {
 | 
			
		||||
			_transaction = transaction;
 | 
			
		||||
			return this;
 | 
			
		||||
@@ -47,12 +56,16 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
		public int ExecuteAffrows() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
			if (string.IsNullOrEmpty(sql)) return 0;
 | 
			
		||||
			return _orm.Ado.ExecuteNonQuery(_transaction, CommandType.Text, sql, _params.Concat(_paramsSource).ToArray());
 | 
			
		||||
			var affrows = _orm.Ado.ExecuteNonQuery(_transaction, CommandType.Text, sql, _params.Concat(_paramsSource).ToArray());
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return affrows;
 | 
			
		||||
		}
 | 
			
		||||
		async public Task<int> ExecuteAffrowsAsync() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
			if (string.IsNullOrEmpty(sql)) return 0;
 | 
			
		||||
			return await _orm.Ado.ExecuteNonQueryAsync(_transaction, CommandType.Text, sql, _params.Concat(_paramsSource).ToArray());
 | 
			
		||||
			var affrows = await _orm.Ado.ExecuteNonQueryAsync(_transaction, CommandType.Text, sql, _params.Concat(_paramsSource).ToArray());
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return affrows;
 | 
			
		||||
		}
 | 
			
		||||
		public abstract List<T1> ExecuteUpdated();
 | 
			
		||||
		public abstract Task<List<T1>> ExecuteUpdatedAsync();
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,9 @@ namespace FreeSql.MySql.Curd {
 | 
			
		||||
				sb.Append(_commonUtils.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
			
		||||
				++colidx;
 | 
			
		||||
			}
 | 
			
		||||
			return _orm.Ado.Query<T1>(_transaction, CommandType.Text, sb.ToString(), _params.ToArray());
 | 
			
		||||
			var ret = _orm.Ado.Query<T1>(_transaction, CommandType.Text, sb.ToString(), _params.ToArray());
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		async public override Task<List<T1>> ExecuteDeletedAsync() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
@@ -39,7 +41,9 @@ namespace FreeSql.MySql.Curd {
 | 
			
		||||
				sb.Append(_commonUtils.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
			
		||||
				++colidx;
 | 
			
		||||
			}
 | 
			
		||||
			return await _orm.Ado.QueryAsync<T1>(_transaction, CommandType.Text, sb.ToString(), _params.ToArray());
 | 
			
		||||
			var ret = await _orm.Ado.QueryAsync<T1>(_transaction, CommandType.Text, sb.ToString(), _params.ToArray());
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -23,13 +23,17 @@ namespace FreeSql.MySql.Curd {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
			if (string.IsNullOrEmpty(sql)) return 0;
 | 
			
		||||
 | 
			
		||||
			return long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(_transaction, CommandType.Text, string.Concat(sql, "; SELECT LAST_INSERT_ID();"), _params)), out var trylng) ? trylng : 0;
 | 
			
		||||
			var id = long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(_transaction, CommandType.Text, string.Concat(sql, "; SELECT LAST_INSERT_ID();"), _params)), out var trylng) ? trylng : 0;
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return id;
 | 
			
		||||
		}
 | 
			
		||||
		async internal override Task<long> RawExecuteIdentityAsync() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
			if (string.IsNullOrEmpty(sql)) return 0;
 | 
			
		||||
 | 
			
		||||
			return long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(_transaction, CommandType.Text, string.Concat(sql, "; SELECT LAST_INSERT_ID();"), _params)), out var trylng) ? trylng : 0;
 | 
			
		||||
			var id = long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(_transaction, CommandType.Text, string.Concat(sql, "; SELECT LAST_INSERT_ID();"), _params)), out var trylng) ? trylng : 0;
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return id;
 | 
			
		||||
		}
 | 
			
		||||
		internal override List<T1> RawExecuteInserted() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
@@ -44,7 +48,9 @@ namespace FreeSql.MySql.Curd {
 | 
			
		||||
				sb.Append(_commonUtils.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
			
		||||
				++colidx;
 | 
			
		||||
			}
 | 
			
		||||
			return _orm.Ado.Query<T1>(_transaction, CommandType.Text, sb.ToString(), _params);
 | 
			
		||||
			var ret = _orm.Ado.Query<T1>(_transaction, CommandType.Text, sb.ToString(), _params);
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		async internal override Task<List<T1>> RawExecuteInsertedAsync() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
@@ -59,7 +65,9 @@ namespace FreeSql.MySql.Curd {
 | 
			
		||||
				sb.Append(_commonUtils.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
			
		||||
				++colidx;
 | 
			
		||||
			}
 | 
			
		||||
			return await _orm.Ado.QueryAsync<T1>(_transaction, CommandType.Text, sb.ToString(), _params);
 | 
			
		||||
			var ret = await _orm.Ado.QueryAsync<T1>(_transaction, CommandType.Text, sb.ToString(), _params);
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,9 @@ namespace FreeSql.MySql.Curd {
 | 
			
		||||
				sb.Append(_commonUtils.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
			
		||||
				++colidx;
 | 
			
		||||
			}
 | 
			
		||||
			return _orm.Ado.Query<T1>(_transaction, CommandType.Text, sb.ToString(), _params.Concat(_paramsSource).ToArray());
 | 
			
		||||
			var ret = _orm.Ado.Query<T1>(_transaction, CommandType.Text, sb.ToString(), _params.Concat(_paramsSource).ToArray());
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		async public override Task<List<T1>> ExecuteUpdatedAsync() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
@@ -42,7 +44,9 @@ namespace FreeSql.MySql.Curd {
 | 
			
		||||
				sb.Append(_commonUtils.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
			
		||||
				++colidx;
 | 
			
		||||
			}
 | 
			
		||||
			return await _orm.Ado.QueryAsync<T1>(_transaction, CommandType.Text, sb.ToString(), _params.Concat(_paramsSource).ToArray());
 | 
			
		||||
			var ret = await _orm.Ado.QueryAsync<T1>(_transaction, CommandType.Text, sb.ToString(), _params.Concat(_paramsSource).ToArray());
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys) {
 | 
			
		||||
 
 | 
			
		||||
@@ -69,8 +69,8 @@ namespace FreeSql.Oracle.Curd {
 | 
			
		||||
						if (_noneParameter)
 | 
			
		||||
							sb.Append(_commonUtils.GetNoneParamaterSqlValue(specialParams, col.CsType, val));
 | 
			
		||||
						else {
 | 
			
		||||
							sb.Append(_commonUtils.QuoteWriteParamter(col.CsType, _commonUtils.QuoteParamterName($"{col.CsName}{didx}")));
 | 
			
		||||
							_params[didx * colidx + colidx2] = _commonUtils.AppendParamter(null, $"{col.CsName}{didx}", col.CsType, val);
 | 
			
		||||
							sb.Append(_commonUtils.QuoteWriteParamter(col.CsType, _commonUtils.QuoteParamterName($"{col.CsName}_{didx}")));
 | 
			
		||||
							_params[didx * colidx + colidx2] = _commonUtils.AppendParamter(null, $"{col.CsName}_{didx}", col.CsType, val);
 | 
			
		||||
						}
 | 
			
		||||
						++colidx2;
 | 
			
		||||
					}
 | 
			
		||||
@@ -95,7 +95,9 @@ namespace FreeSql.Oracle.Curd {
 | 
			
		||||
			var identParam = _commonUtils.AppendParamter(null, $"{_identCol.CsName}99", _identCol.CsType, 0) as OracleParameter;
 | 
			
		||||
			identParam.Direction = ParameterDirection.Output;
 | 
			
		||||
			_orm.Ado.ExecuteNonQuery(_transaction, CommandType.Text, $"{sql} RETURNING {identColName} INTO {identParam.ParameterName}", _params.Concat(new[] { identParam }).ToArray());
 | 
			
		||||
			return long.TryParse(string.Concat(identParam.Value), out var trylng) ? trylng : 0;
 | 
			
		||||
			var id = long.TryParse(string.Concat(identParam.Value), out var trylng) ? trylng : 0;
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return id;
 | 
			
		||||
		}
 | 
			
		||||
		async internal override Task<long> RawExecuteIdentityAsync() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
@@ -109,7 +111,9 @@ namespace FreeSql.Oracle.Curd {
 | 
			
		||||
			var identParam = _commonUtils.AppendParamter(null, $"{_identCol.CsName}99", _identCol.CsType, 0) as OracleParameter;
 | 
			
		||||
			identParam.Direction = ParameterDirection.Output;
 | 
			
		||||
			await _orm.Ado.ExecuteNonQueryAsync(_transaction, CommandType.Text, $"{sql} RETURNING {identColName} INTO {identParam.ParameterName}", _params.Concat(new[] { identParam }).ToArray());
 | 
			
		||||
			return long.TryParse(string.Concat(identParam.Value), out var trylng) ? trylng : 0;
 | 
			
		||||
			var id = long.TryParse(string.Concat(identParam.Value), out var trylng) ? trylng : 0;
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return id;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal override List<T1> RawExecuteInserted() {
 | 
			
		||||
@@ -117,6 +121,7 @@ namespace FreeSql.Oracle.Curd {
 | 
			
		||||
			if (string.IsNullOrEmpty(sql)) return new List<T1>();
 | 
			
		||||
 | 
			
		||||
			this.ExecuteAffrows();
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return _source;
 | 
			
		||||
		}
 | 
			
		||||
		async internal override Task<List<T1>> RawExecuteInsertedAsync() {
 | 
			
		||||
@@ -124,6 +129,7 @@ namespace FreeSql.Oracle.Curd {
 | 
			
		||||
			if (string.IsNullOrEmpty(sql)) return new List<T1>();
 | 
			
		||||
 | 
			
		||||
			await this.ExecuteAffrowsAsync();
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return _source;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,9 @@ namespace FreeSql.PostgreSQL.Curd {
 | 
			
		||||
				sb.Append(_commonUtils.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
			
		||||
				++colidx;
 | 
			
		||||
			}
 | 
			
		||||
			return _orm.Ado.Query<T1>(_transaction, CommandType.Text, sb.ToString(), _params.ToArray());
 | 
			
		||||
			var ret = _orm.Ado.Query<T1>(_transaction, CommandType.Text, sb.ToString(), _params.ToArray());
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		async public override Task<List<T1>> ExecuteDeletedAsync() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
@@ -39,7 +41,9 @@ namespace FreeSql.PostgreSQL.Curd {
 | 
			
		||||
				sb.Append(_commonUtils.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
			
		||||
				++colidx;
 | 
			
		||||
			}
 | 
			
		||||
			return await _orm.Ado.QueryAsync<T1>(_transaction, CommandType.Text, sb.ToString(), _params.ToArray());
 | 
			
		||||
			var ret = await _orm.Ado.QueryAsync<T1>(_transaction, CommandType.Text, sb.ToString(), _params.ToArray());
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,9 @@ namespace FreeSql.PostgreSQL.Curd {
 | 
			
		||||
				_orm.Ado.ExecuteNonQuery(_transaction, CommandType.Text, sql, _params);
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
			return long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(_transaction, CommandType.Text, string.Concat(sql, " RETURNING ", _commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name)), _params)), out var trylng) ? trylng : 0;
 | 
			
		||||
			var id = long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(_transaction, CommandType.Text, string.Concat(sql, " RETURNING ", _commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name)), _params)), out var trylng) ? trylng : 0;
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return id;
 | 
			
		||||
		}
 | 
			
		||||
		async internal override Task<long> RawExecuteIdentityAsync() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
@@ -40,7 +42,9 @@ namespace FreeSql.PostgreSQL.Curd {
 | 
			
		||||
				await _orm.Ado.ExecuteNonQueryAsync(_transaction, CommandType.Text, sql, _params);
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
			return long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(_transaction, CommandType.Text, string.Concat(sql, " RETURNING ", _commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name)), _params)), out var trylng) ? trylng : 0;
 | 
			
		||||
			var id = long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(_transaction, CommandType.Text, string.Concat(sql, " RETURNING ", _commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name)), _params)), out var trylng) ? trylng : 0;
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return id;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal override List<T1> RawExecuteInserted() {
 | 
			
		||||
@@ -56,7 +60,9 @@ namespace FreeSql.PostgreSQL.Curd {
 | 
			
		||||
				sb.Append(_commonUtils.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
			
		||||
				++colidx;
 | 
			
		||||
			}
 | 
			
		||||
			return _orm.Ado.Query<T1>(_transaction, CommandType.Text, sb.ToString(), _params);
 | 
			
		||||
			var ret = _orm.Ado.Query<T1>(_transaction, CommandType.Text, sb.ToString(), _params);
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		async internal override Task<List<T1>> RawExecuteInsertedAsync() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
@@ -71,7 +77,9 @@ namespace FreeSql.PostgreSQL.Curd {
 | 
			
		||||
				sb.Append(_commonUtils.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
			
		||||
				++colidx;
 | 
			
		||||
			}
 | 
			
		||||
			return await _orm.Ado.QueryAsync<T1>(_transaction, CommandType.Text, sb.ToString(), _params);
 | 
			
		||||
			var ret = await _orm.Ado.QueryAsync<T1>(_transaction, CommandType.Text, sb.ToString(), _params);
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,9 @@ namespace FreeSql.PostgreSQL.Curd {
 | 
			
		||||
				sb.Append(_commonUtils.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
			
		||||
				++colidx;
 | 
			
		||||
			}
 | 
			
		||||
			return _orm.Ado.Query<T1>(_transaction, CommandType.Text, sb.ToString(), _params.Concat(_paramsSource).ToArray());
 | 
			
		||||
			var ret = _orm.Ado.Query<T1>(_transaction, CommandType.Text, sb.ToString(), _params.Concat(_paramsSource).ToArray());
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		async public override Task<List<T1>> ExecuteUpdatedAsync() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
@@ -42,7 +44,9 @@ namespace FreeSql.PostgreSQL.Curd {
 | 
			
		||||
				sb.Append(_commonUtils.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
			
		||||
				++colidx;
 | 
			
		||||
			}
 | 
			
		||||
			return await _orm.Ado.QueryAsync<T1>(_transaction, CommandType.Text, sb.ToString(), _params.Concat(_paramsSource).ToArray());
 | 
			
		||||
			var ret = await _orm.Ado.QueryAsync<T1>(_transaction, CommandType.Text, sb.ToString(), _params.Concat(_paramsSource).ToArray());
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys) {
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,9 @@ namespace FreeSql.SqlServer.Curd {
 | 
			
		||||
			sb.Insert(0, sql.Substring(0, validx));
 | 
			
		||||
			sb.Append(sql.Substring(validx));
 | 
			
		||||
 | 
			
		||||
			return _orm.Ado.Query<T1>(_transaction, CommandType.Text, sb.ToString(), _params.ToArray());
 | 
			
		||||
			var ret = _orm.Ado.Query<T1>(_transaction, CommandType.Text, sb.ToString(), _params.ToArray());
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		async public override Task<List<T1>> ExecuteDeletedAsync() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
@@ -50,7 +52,9 @@ namespace FreeSql.SqlServer.Curd {
 | 
			
		||||
			sb.Insert(0, sql.Substring(0, validx));
 | 
			
		||||
			sb.Append(sql.Substring(validx));
 | 
			
		||||
 | 
			
		||||
			return await _orm.Ado.QueryAsync<T1>(_transaction, CommandType.Text, sb.ToString(), _params.ToArray());
 | 
			
		||||
			var ret = await _orm.Ado.QueryAsync<T1>(_transaction, CommandType.Text, sb.ToString(), _params.ToArray());
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -26,13 +26,17 @@ namespace FreeSql.SqlServer.Curd {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
			if (string.IsNullOrEmpty(sql)) return 0;
 | 
			
		||||
 | 
			
		||||
			return long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(_transaction, CommandType.Text, string.Concat(sql, "; SELECT SCOPE_IDENTITY();"), _params)), out var trylng) ? trylng : 0;
 | 
			
		||||
			var id = long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(_transaction, CommandType.Text, string.Concat(sql, "; SELECT SCOPE_IDENTITY();"), _params)), out var trylng) ? trylng : 0;
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return id;
 | 
			
		||||
		}
 | 
			
		||||
		async internal override Task<long> RawExecuteIdentityAsync() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
			if (string.IsNullOrEmpty(sql)) return 0;
 | 
			
		||||
 | 
			
		||||
			return long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(_transaction, CommandType.Text, string.Concat(sql, "; SELECT SCOPE_IDENTITY();"), _params)), out var trylng) ? trylng : 0;
 | 
			
		||||
			var id = long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(_transaction, CommandType.Text, string.Concat(sql, "; SELECT SCOPE_IDENTITY();"), _params)), out var trylng) ? trylng : 0;
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return id;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal override List<T1> RawExecuteInserted() {
 | 
			
		||||
@@ -53,7 +57,9 @@ namespace FreeSql.SqlServer.Curd {
 | 
			
		||||
			sb.Insert(0, sql.Substring(0, validx + 1));
 | 
			
		||||
			sb.Append(sql.Substring(validx + 1));
 | 
			
		||||
 | 
			
		||||
			return _orm.Ado.Query<T1>(_transaction, CommandType.Text, sb.ToString(), _params);
 | 
			
		||||
			var ret = _orm.Ado.Query<T1>(_transaction, CommandType.Text, sb.ToString(), _params);
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		async internal override Task<List<T1>> RawExecuteInsertedAsync() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
@@ -73,7 +79,9 @@ namespace FreeSql.SqlServer.Curd {
 | 
			
		||||
			sb.Insert(0, sql.Substring(0, validx + 1));
 | 
			
		||||
			sb.Append(sql.Substring(validx + 1));
 | 
			
		||||
 | 
			
		||||
			return await _orm.Ado.QueryAsync<T1>(_transaction, CommandType.Text, sb.ToString(), _params);
 | 
			
		||||
			var ret = await _orm.Ado.QueryAsync<T1>(_transaction, CommandType.Text, sb.ToString(), _params);
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -1,281 +0,0 @@
 | 
			
		||||
//using FreeSql.Internal;
 | 
			
		||||
//using System;
 | 
			
		||||
//using System.Collections.Generic;
 | 
			
		||||
//using System.Data;
 | 
			
		||||
//using System.Data.Common;
 | 
			
		||||
//using System.Linq;
 | 
			
		||||
//using System.Text;
 | 
			
		||||
//using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
//namespace FreeSql.SqlServer.Curd {
 | 
			
		||||
 | 
			
		||||
//	class SqlServerInsert<T1> : Internal.CommonProvider.InsertProvider<T1> where T1 : class {
 | 
			
		||||
//		public SqlServerInsert(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
 | 
			
		||||
//			: base(orm, commonUtils, commonExpression) {
 | 
			
		||||
//		}
 | 
			
		||||
 | 
			
		||||
//		public override int ExecuteAffrows() {
 | 
			
		||||
//			var sql = this.ToSql2100();
 | 
			
		||||
//			switch (sql.Count) {
 | 
			
		||||
//				case 0: return 0;
 | 
			
		||||
//				case 1: return _orm.Ado.ExecuteNonQuery(_transaction, CommandType.Text, sql[0].Item1, sql[0].Item2);
 | 
			
		||||
//				default:
 | 
			
		||||
//					var affrows = 0;
 | 
			
		||||
//					if (_transaction == null) {
 | 
			
		||||
//						using (var conn = _orm.Ado.MasterPool.Get()) {
 | 
			
		||||
//							var tran = conn.Value.BeginTransaction();
 | 
			
		||||
//							try {
 | 
			
		||||
//								foreach (var s in sql)
 | 
			
		||||
//									affrows += _orm.Ado.ExecuteNonQuery(tran, CommandType.Text, s.Item1, s.Item2);
 | 
			
		||||
//								tran.Commit();
 | 
			
		||||
//							} catch {
 | 
			
		||||
//								tran.Rollback();
 | 
			
		||||
//							}
 | 
			
		||||
//						}
 | 
			
		||||
//					} else {
 | 
			
		||||
//						foreach (var s in sql)
 | 
			
		||||
//							affrows += _orm.Ado.ExecuteNonQuery(_transaction, CommandType.Text, s.Item1, s.Item2);
 | 
			
		||||
//					}
 | 
			
		||||
//					return affrows;
 | 
			
		||||
//			}
 | 
			
		||||
//		}
 | 
			
		||||
//		async public override Task<int> ExecuteAffrowsAsync() {
 | 
			
		||||
//			var sql = this.ToSql2100();
 | 
			
		||||
//			switch (sql.Count) {
 | 
			
		||||
//				case 0: return 0;
 | 
			
		||||
//				case 1: return await _orm.Ado.ExecuteNonQueryAsync(_transaction, CommandType.Text, sql[0].Item1, sql[0].Item2);
 | 
			
		||||
//				default:
 | 
			
		||||
//					var affrows = 0;
 | 
			
		||||
//					if (_transaction == null) {
 | 
			
		||||
//						using (var conn = await _orm.Ado.MasterPool.GetAsync()) {
 | 
			
		||||
//							var tran = conn.Value.BeginTransaction();
 | 
			
		||||
//							try {
 | 
			
		||||
//								foreach (var s in sql)
 | 
			
		||||
//									affrows += await _orm.Ado.ExecuteNonQueryAsync(tran, CommandType.Text, s.Item1, s.Item2);
 | 
			
		||||
//								tran.Commit();
 | 
			
		||||
//							} catch {
 | 
			
		||||
//								tran.Rollback();
 | 
			
		||||
//							}
 | 
			
		||||
//						}
 | 
			
		||||
//					} else {
 | 
			
		||||
//						foreach (var s in sql)
 | 
			
		||||
//							affrows += await _orm.Ado.ExecuteNonQueryAsync(_transaction, CommandType.Text, s.Item1, s.Item2);
 | 
			
		||||
//					}
 | 
			
		||||
//					return affrows;
 | 
			
		||||
//			}
 | 
			
		||||
//		}
 | 
			
		||||
 | 
			
		||||
//		public override long ExecuteIdentity() {
 | 
			
		||||
//			var sql = this.ToSql2100();
 | 
			
		||||
//			switch (sql.Count) {
 | 
			
		||||
//				case 0: return 0;
 | 
			
		||||
//				case 1:
 | 
			
		||||
//					if (string.IsNullOrEmpty(sql[0].Item1)) return 0;
 | 
			
		||||
//					return long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(_transaction, CommandType.Text, string.Concat(sql[0].Item1, "; SELECT SCOPE_IDENTITY();"), sql[0].Item2)), out var trylng) ? trylng : 0;
 | 
			
		||||
//				default:
 | 
			
		||||
//					long ret = 0;
 | 
			
		||||
//					if (_transaction == null) {
 | 
			
		||||
//						using (var conn = _orm.Ado.MasterPool.Get()) {
 | 
			
		||||
//							var tran = conn.Value.BeginTransaction();
 | 
			
		||||
//							try {
 | 
			
		||||
//								for (var a = 0; a < sql.Count; a++) {
 | 
			
		||||
//									var s = sql[a];
 | 
			
		||||
//									if (a < sql.Count - 1) _orm.Ado.ExecuteNonQuery(tran, CommandType.Text, s.Item1, s.Item2);
 | 
			
		||||
//									else ret = long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(tran, CommandType.Text, string.Concat(s.Item1, "; SELECT SCOPE_IDENTITY();"), s.Item2)), out trylng) ? trylng : 0;
 | 
			
		||||
//								}
 | 
			
		||||
//								tran.Commit();
 | 
			
		||||
//							} catch {
 | 
			
		||||
//								tran.Rollback();
 | 
			
		||||
//							}
 | 
			
		||||
//						}
 | 
			
		||||
//					} else {
 | 
			
		||||
//						for (var a = 0; a < sql.Count; a++) {
 | 
			
		||||
//							var s = sql[a];
 | 
			
		||||
//							if (a < sql.Count - 1) _orm.Ado.ExecuteNonQuery(_transaction, CommandType.Text, s.Item1, s.Item2);
 | 
			
		||||
//							else ret = long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(_transaction, CommandType.Text, string.Concat(s.Item1, "; SELECT SCOPE_IDENTITY();"), s.Item2)), out trylng) ? trylng : 0;
 | 
			
		||||
//						}
 | 
			
		||||
//					}
 | 
			
		||||
//					return ret;
 | 
			
		||||
//			}
 | 
			
		||||
//		}
 | 
			
		||||
//		async public override Task<long> ExecuteIdentityAsync() {
 | 
			
		||||
//			var sql = this.ToSql2100();
 | 
			
		||||
//			switch (sql.Count) {
 | 
			
		||||
//				case 0: return 0;
 | 
			
		||||
//				case 1:
 | 
			
		||||
//					if (string.IsNullOrEmpty(sql[0].Item1)) return 0;
 | 
			
		||||
//					return long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(_transaction, CommandType.Text, string.Concat(sql[0].Item1, "; SELECT SCOPE_IDENTITY();"), sql[0].Item2)), out var trylng) ? trylng : 0;
 | 
			
		||||
//				default:
 | 
			
		||||
//					long ret = 0;
 | 
			
		||||
//					if (_transaction == null) {
 | 
			
		||||
//						using (var conn = await _orm.Ado.MasterPool.GetAsync()) {
 | 
			
		||||
//							var tran = conn.Value.BeginTransaction();
 | 
			
		||||
//							try {
 | 
			
		||||
//								for (var a = 0; a < sql.Count; a++) {
 | 
			
		||||
//									var s = sql[a];
 | 
			
		||||
//									if (a < sql.Count - 1) await _orm.Ado.ExecuteNonQueryAsync(tran, CommandType.Text, s.Item1, s.Item2);
 | 
			
		||||
//									else ret = long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(tran, CommandType.Text, string.Concat(s.Item1, "; SELECT SCOPE_IDENTITY();"), s.Item2)), out trylng) ? trylng : 0;
 | 
			
		||||
//								}
 | 
			
		||||
//								tran.Commit();
 | 
			
		||||
//							} catch {
 | 
			
		||||
//								tran.Rollback();
 | 
			
		||||
//							}
 | 
			
		||||
//						}
 | 
			
		||||
//					} else {
 | 
			
		||||
//						for (var a = 0; a < sql.Count; a++) {
 | 
			
		||||
//							var s = sql[a];
 | 
			
		||||
//							if (a < sql.Count - 1) await _orm.Ado.ExecuteNonQueryAsync(_transaction, CommandType.Text, s.Item1, s.Item2);
 | 
			
		||||
//							else ret = long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(_transaction, CommandType.Text, string.Concat(s.Item1, "; SELECT SCOPE_IDENTITY();"), s.Item2)), out trylng) ? trylng : 0;
 | 
			
		||||
//						}
 | 
			
		||||
//					}
 | 
			
		||||
//					return ret;
 | 
			
		||||
//			}
 | 
			
		||||
//		}
 | 
			
		||||
 | 
			
		||||
//		public override List<T1> ExecuteInserted() {
 | 
			
		||||
//			string output = null;
 | 
			
		||||
//			Func<string, string> getOutputSql = oldsql => {
 | 
			
		||||
//				if (string.IsNullOrEmpty(output)) {
 | 
			
		||||
//					var sb = new StringBuilder();
 | 
			
		||||
//					sb.Append(" OUTPUT ");
 | 
			
		||||
//					var colidx = 0;
 | 
			
		||||
//					foreach (var col in _table.Columns.Values) {
 | 
			
		||||
//						if (colidx > 0) sb.Append(", ");
 | 
			
		||||
//						sb.Append(_commonUtils.QuoteReadColumn(col.CsType, $"INSERTED.{_commonUtils.QuoteSqlName(col.Attribute.Name)}")).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
			
		||||
//						++colidx;
 | 
			
		||||
//					}
 | 
			
		||||
//					output = sb.ToString();
 | 
			
		||||
//				}
 | 
			
		||||
//				var validx = oldsql.IndexOf(") VALUES");
 | 
			
		||||
//				if (validx == -1) throw new ArgumentException("找不到 VALUES");
 | 
			
		||||
//				var newsql = new StringBuilder().Append(output);
 | 
			
		||||
//				newsql.Insert(0, oldsql.Substring(0, validx + 1));
 | 
			
		||||
//				newsql.Append(oldsql.Substring(validx + 1));
 | 
			
		||||
//				return newsql.ToString();
 | 
			
		||||
//			};
 | 
			
		||||
 | 
			
		||||
//			var sql = this.ToSql2100();
 | 
			
		||||
//			switch (sql.Count) {
 | 
			
		||||
//				case 0: return new List<T1>();
 | 
			
		||||
//				case 1:
 | 
			
		||||
//					if (string.IsNullOrEmpty(sql[0].Item1)) return new List<T1>();
 | 
			
		||||
//					return _orm.Ado.Query<T1>(_transaction, CommandType.Text, getOutputSql(sql[0].Item1), sql[0].Item2);
 | 
			
		||||
//				default:
 | 
			
		||||
//					var ret = new List<T1>();
 | 
			
		||||
//					if (_transaction == null) {
 | 
			
		||||
//						using (var conn = _orm.Ado.MasterPool.Get()) {
 | 
			
		||||
//							var tran = conn.Value.BeginTransaction();
 | 
			
		||||
//							try {
 | 
			
		||||
//								foreach (var s in sql)
 | 
			
		||||
//									ret.AddRange(_orm.Ado.Query<T1>(tran, CommandType.Text, getOutputSql(s.Item1), s.Item2));
 | 
			
		||||
//								tran.Commit();
 | 
			
		||||
//							} catch {
 | 
			
		||||
//								tran.Rollback();
 | 
			
		||||
//							}
 | 
			
		||||
//						}
 | 
			
		||||
//					} else {
 | 
			
		||||
//						foreach (var s in sql)
 | 
			
		||||
//							ret.AddRange(_orm.Ado.Query<T1>(_transaction, CommandType.Text, getOutputSql(s.Item1), s.Item2));
 | 
			
		||||
//					}
 | 
			
		||||
//					return ret;
 | 
			
		||||
//			}
 | 
			
		||||
//		}
 | 
			
		||||
//		async public override Task<List<T1>> ExecuteInsertedAsync() {
 | 
			
		||||
//			string output = null;
 | 
			
		||||
//			Func<string, string> getOutputSql = oldsql => {
 | 
			
		||||
//				if (string.IsNullOrEmpty(output)) {
 | 
			
		||||
//					var sb = new StringBuilder();
 | 
			
		||||
//					sb.Append(" OUTPUT ");
 | 
			
		||||
//					var colidx = 0;
 | 
			
		||||
//					foreach (var col in _table.Columns.Values) {
 | 
			
		||||
//						if (colidx > 0) sb.Append(", ");
 | 
			
		||||
//						sb.Append(_commonUtils.QuoteReadColumn(col.CsType, $"INSERTED.{_commonUtils.QuoteSqlName(col.Attribute.Name)}")).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
			
		||||
//						++colidx;
 | 
			
		||||
//					}
 | 
			
		||||
//					output = sb.ToString();
 | 
			
		||||
//				}
 | 
			
		||||
//				var validx = oldsql.IndexOf(") VALUES");
 | 
			
		||||
//				if (validx == -1) throw new ArgumentException("找不到 VALUES");
 | 
			
		||||
//				var newsql = new StringBuilder().Append(output);
 | 
			
		||||
//				newsql.Insert(0, oldsql.Substring(0, validx + 1));
 | 
			
		||||
//				newsql.Append(oldsql.Substring(validx + 1));
 | 
			
		||||
//				return oldsql;
 | 
			
		||||
//			};
 | 
			
		||||
 | 
			
		||||
//			var sql = this.ToSql2100();
 | 
			
		||||
//			switch (sql.Count) {
 | 
			
		||||
//				case 0: return new List<T1>();
 | 
			
		||||
//				case 1:
 | 
			
		||||
//					if (string.IsNullOrEmpty(sql[0].Item1)) return new List<T1>();
 | 
			
		||||
//					return await _orm.Ado.QueryAsync<T1>(_transaction, CommandType.Text, getOutputSql(sql[0].Item1), sql[0].Item2);
 | 
			
		||||
//				default:
 | 
			
		||||
//					var ret = new List<T1>();
 | 
			
		||||
//					if (_transaction == null) {
 | 
			
		||||
//						using (var conn = await _orm.Ado.MasterPool.GetAsync()) {
 | 
			
		||||
//							var tran = conn.Value.BeginTransaction();
 | 
			
		||||
//							try {
 | 
			
		||||
//								foreach (var s in sql)
 | 
			
		||||
//									ret.AddRange(await _orm.Ado.QueryAsync<T1>(tran, CommandType.Text, getOutputSql(s.Item1), s.Item2));
 | 
			
		||||
//								tran.Commit();
 | 
			
		||||
//							} catch {
 | 
			
		||||
//								tran.Rollback();
 | 
			
		||||
//							}
 | 
			
		||||
//						}
 | 
			
		||||
//					} else {
 | 
			
		||||
//						foreach (var s in sql)
 | 
			
		||||
//							ret.AddRange(await _orm.Ado.QueryAsync<T1>(_transaction, CommandType.Text, getOutputSql(s.Item1), s.Item2));
 | 
			
		||||
//					}
 | 
			
		||||
//					return ret;
 | 
			
		||||
//			}
 | 
			
		||||
//		}
 | 
			
		||||
 | 
			
		||||
//		public List<(string, DbParameter[])> ToSql2100() { //传入的请求具有过多的参数。该服务器支持最多 2100 个参数。请减少参数的数目,然后重新发送该请求。
 | 
			
		||||
//			if (_source == null || _source.Any() == false) return new List<(string, DbParameter[])>();
 | 
			
		||||
//			var ret = new List<(string, DbParameter[])>();
 | 
			
		||||
//			var sbhead = new StringBuilder();
 | 
			
		||||
//			sbhead.Append("INSERT INTO ").Append(_commonUtils.QuoteSqlName(_tableRule?.Invoke(_table.DbName) ?? _table.DbName)).Append("(");
 | 
			
		||||
//			var colidx = 0;
 | 
			
		||||
//			foreach (var col in _table.Columns.Values)
 | 
			
		||||
//				if (col.Attribute.IsIdentity == false && _ignore.ContainsKey(col.Attribute.Name) == false) {
 | 
			
		||||
//					if (colidx > 0) sbhead.Append(", ");
 | 
			
		||||
//					sbhead.Append(_commonUtils.QuoteSqlName(col.Attribute.Name));
 | 
			
		||||
//					++colidx;
 | 
			
		||||
//				}
 | 
			
		||||
//			sbhead.Append(") VALUES");
 | 
			
		||||
//			var sbh = sbhead.ToString();
 | 
			
		||||
 | 
			
		||||
//			var sbsql = new StringBuilder().Append(sbh);
 | 
			
		||||
//			var sbsqlParams = new List<DbParameter>();
 | 
			
		||||
//			var didx = 0;
 | 
			
		||||
//			foreach (var d in _source) {
 | 
			
		||||
//				if ((didx + 1) * colidx >= 2100) {
 | 
			
		||||
//					ret.Add((sbsql.ToString(), sbsqlParams.ToArray()));
 | 
			
		||||
//					sbsql.Clear().Append(sbh);
 | 
			
		||||
//					sbsqlParams.Clear();
 | 
			
		||||
//					didx = 0;
 | 
			
		||||
//				}
 | 
			
		||||
 | 
			
		||||
//				if (sbsqlParams.Count > 0) sbsql.Append(", ");
 | 
			
		||||
//				sbsql.Append("(");
 | 
			
		||||
//				var colidx2 = 0;
 | 
			
		||||
//				foreach (var col in _table.Columns.Values)
 | 
			
		||||
//					if (col.Attribute.IsIdentity == false && _ignore.ContainsKey(col.Attribute.Name) == false) {
 | 
			
		||||
//						if (colidx2 > 0) sbsql.Append(", ");
 | 
			
		||||
//						sbsql.Append(_commonUtils.QuoteWriteParamter(col.CsType, $"{_commonUtils.QuoteParamterName(col.CsName)}{didx}"));
 | 
			
		||||
//						object val = null;
 | 
			
		||||
//						if (_table.Properties.TryGetValue(col.CsName, out var tryp)) {
 | 
			
		||||
//							val = tryp.GetValue(d);
 | 
			
		||||
//							if (col.Attribute.IsPrimary && (col.CsType == typeof(Guid) || col.CsType == typeof(Guid?))
 | 
			
		||||
//								&& (val == null || (Guid)val == Guid.Empty)) tryp.SetValue(d, val = FreeUtil.NewMongodbId());
 | 
			
		||||
//						}
 | 
			
		||||
//						sbsqlParams.Add(_commonUtils.AppendParamter(null, $"{col.CsName}{didx}", col.CsType, val));
 | 
			
		||||
//						++colidx2;
 | 
			
		||||
//					}
 | 
			
		||||
//				sbsql.Append(")");
 | 
			
		||||
//				++didx;
 | 
			
		||||
//			}
 | 
			
		||||
//			ret.Add((sbsql.ToString(), sbsqlParams.ToArray()));
 | 
			
		||||
//			return ret;
 | 
			
		||||
//		}
 | 
			
		||||
//	}
 | 
			
		||||
//}
 | 
			
		||||
@@ -33,7 +33,9 @@ namespace FreeSql.SqlServer.Curd {
 | 
			
		||||
			sb.Insert(0, sql.Substring(0, validx));
 | 
			
		||||
			sb.Append(sql.Substring(validx));
 | 
			
		||||
 | 
			
		||||
			return _orm.Ado.Query<T1>(_transaction, CommandType.Text, sb.ToString(), _params.Concat(_paramsSource).ToArray());
 | 
			
		||||
			var ret = _orm.Ado.Query<T1>(_transaction, CommandType.Text, sb.ToString(), _params.Concat(_paramsSource).ToArray());
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		async public override Task<List<T1>> ExecuteUpdatedAsync() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
@@ -53,7 +55,9 @@ namespace FreeSql.SqlServer.Curd {
 | 
			
		||||
			sb.Insert(0, sql.Substring(0, validx));
 | 
			
		||||
			sb.Append(sql.Substring(validx));
 | 
			
		||||
 | 
			
		||||
			return await _orm.Ado.QueryAsync<T1>(_transaction, CommandType.Text, sb.ToString(), _params.Concat(_paramsSource).ToArray());
 | 
			
		||||
			var ret = await _orm.Ado.QueryAsync<T1>(_transaction, CommandType.Text, sb.ToString(), _params.Concat(_paramsSource).ToArray());
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys) {
 | 
			
		||||
 
 | 
			
		||||
@@ -25,19 +25,24 @@ namespace FreeSql.Sqlite.Curd {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
			if (string.IsNullOrEmpty(sql)) return 0;
 | 
			
		||||
 | 
			
		||||
			return long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(_transaction, CommandType.Text, string.Concat(sql, "; SELECT last_insert_rowid();"), _params)), out var trylng) ? trylng : 0;
 | 
			
		||||
			var id = long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(_transaction, CommandType.Text, string.Concat(sql, "; SELECT last_insert_rowid();"), _params)), out var trylng) ? trylng : 0;
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return id;
 | 
			
		||||
		}
 | 
			
		||||
		async internal override Task<long> RawExecuteIdentityAsync() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
			if (string.IsNullOrEmpty(sql)) return 0;
 | 
			
		||||
 | 
			
		||||
			return long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(_transaction, CommandType.Text, string.Concat(sql, "; SELECT last_insert_rowid();"), _params)), out var trylng) ? trylng : 0;
 | 
			
		||||
			var id = long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(_transaction, CommandType.Text, string.Concat(sql, "; SELECT last_insert_rowid();"), _params)), out var trylng) ? trylng : 0;
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return id;
 | 
			
		||||
		}
 | 
			
		||||
		internal override List<T1> RawExecuteInserted() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
			if (string.IsNullOrEmpty(sql)) return new List<T1>();
 | 
			
		||||
 | 
			
		||||
			this.ExecuteAffrows();
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return _source;
 | 
			
		||||
		}
 | 
			
		||||
		async internal override Task<List<T1>> RawExecuteInsertedAsync() {
 | 
			
		||||
@@ -45,6 +50,7 @@ namespace FreeSql.Sqlite.Curd {
 | 
			
		||||
			if (string.IsNullOrEmpty(sql)) return new List<T1>();
 | 
			
		||||
 | 
			
		||||
			await this.ExecuteAffrowsAsync();
 | 
			
		||||
			this.ClearData();
 | 
			
		||||
			return _source;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user