mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 09:15:27 +08:00 
			
		
		
		
	解决 SqlServer 批量添加参数最多 2100 个参数
This commit is contained in:
		@@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFramework>netstandard2.0</TargetFramework>
 | 
			
		||||
    <Version>0.3.13.1</Version>
 | 
			
		||||
    <Version>0.3.14</Version>
 | 
			
		||||
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
 | 
			
		||||
    <Authors>YeXiangQin</Authors>
 | 
			
		||||
    <Description>打造 .NETCore 最方便的 ORM,DbFirst 与 CodeFirst 混合使用,提供从实体同步数据库,或者从数据库生成实体代码,支持 MySql/SqlServer/PostgreSQL/Oracle/Sqlite,读写分离、分表分库。</Description>
 | 
			
		||||
 
 | 
			
		||||
@@ -43,8 +43,8 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			return this;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public int ExecuteAffrows() => _orm.Ado.ExecuteNonQuery(_transaction, CommandType.Text, this.ToSql(), _params);
 | 
			
		||||
		public Task<int> ExecuteAffrowsAsync() => _orm.Ado.ExecuteNonQueryAsync(_transaction, CommandType.Text, this.ToSql(), _params);
 | 
			
		||||
		public virtual int ExecuteAffrows() => _orm.Ado.ExecuteNonQuery(_transaction, CommandType.Text, this.ToSql(), _params);
 | 
			
		||||
		public virtual Task<int> ExecuteAffrowsAsync() => _orm.Ado.ExecuteNonQueryAsync(_transaction, CommandType.Text, this.ToSql(), _params);
 | 
			
		||||
		public abstract long ExecuteIdentity();
 | 
			
		||||
		public abstract Task<long> ExecuteIdentityAsync();
 | 
			
		||||
		public abstract List<T1> ExecuteInserted();
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,8 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Data;
 | 
			
		||||
using System.Data.Common;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
@@ -12,58 +14,267 @@ namespace FreeSql.SqlServer.Curd {
 | 
			
		||||
			: base(orm, commonUtils, commonExpression) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override long ExecuteIdentity() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
			if (string.IsNullOrEmpty(sql)) return 0;
 | 
			
		||||
		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;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
			return long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(_transaction, CommandType.Text, string.Concat(sql, "; SELECT SCOPE_IDENTITY();"), _params)), out var trylng) ? trylng : 0;
 | 
			
		||||
		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.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 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() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
			if (string.IsNullOrEmpty(sql)) return new List<T1>();
 | 
			
		||||
			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 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;
 | 
			
		||||
			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;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			var validx = sql.IndexOf(") VALUES");
 | 
			
		||||
			if (validx == -1) throw new ArgumentException("找不到 VALUES");
 | 
			
		||||
			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);
 | 
			
		||||
		}
 | 
			
		||||
		async public override Task<List<T1>> ExecuteInsertedAsync() {
 | 
			
		||||
			var sql = this.ToSql();
 | 
			
		||||
			if (string.IsNullOrEmpty(sql)) return new List<T1>();
 | 
			
		||||
			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 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;
 | 
			
		||||
			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;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
			var validx = sql.IndexOf(") VALUES");
 | 
			
		||||
			if (validx == -1) throw new ArgumentException("找不到 VALUES");
 | 
			
		||||
			sb.Insert(0, sql.Substring(0, validx + 1));
 | 
			
		||||
			sb.Append(sql.Substring(validx + 1));
 | 
			
		||||
		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();
 | 
			
		||||
 | 
			
		||||
			return await _orm.Ado.QueryAsync<T1>(_transaction, CommandType.Text, sb.ToString(), _params);
 | 
			
		||||
			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();
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				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;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user