mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-04-22 10:42:52 +08:00
解决 SqlServer 批量添加参数最多 2100 个参数
This commit is contained in:
parent
f653f03073
commit
aa2040a629
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<Version>0.3.13.1</Version>
|
||||
<Version>0.3.14</Version>
|
||||
<Authors>YeXiangQin</Authors>
|
||||
<Description>FreeSql 通用仓库层实现,支持 MySql/SqlServer/PostgreSQL/Oracle/Sqlite,读写分离、分表分库。</Description>
|
||||
<PackageProjectUrl>https://github.com/2881099/FreeSql</PackageProjectUrl>
|
||||
|
@ -68,6 +68,12 @@ namespace FreeSql.Tests.SqlServer {
|
||||
|
||||
var item = g.sqlserver.Insert<Topic>(new Topic { Title = "xxxx", CreateTime = DateTime.Now }).ExecuteInserted();
|
||||
Assert.Equal(item[0].Id, delete.Where(a => a.Id == item[0].Id).ExecuteDeleted()[0].Id);
|
||||
|
||||
var items = Enumerable.Range(0, 3001).Select(a => new Topic { Title = "xxxx" + a, CreateTime = DateTime.Now });
|
||||
var itemsInserted = g.sqlserver.Insert<Topic>(items).ExecuteInserted();
|
||||
Assert.Equal(items.First().Title, itemsInserted[0].Title);
|
||||
|
||||
Assert.Equal(itemsInserted[0].Id, delete.Where(a => a.Id == itemsInserted[0].Id).ExecuteDeleted()[0].Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -66,6 +66,9 @@ namespace FreeSql.Tests.SqlServer {
|
||||
|
||||
Assert.Equal(1, insert.AppendData(items.First()).ExecuteAffrows());
|
||||
Assert.Equal(10, insert.AppendData(items).ExecuteAffrows());
|
||||
|
||||
items = Enumerable.Range(0, 9989).Select(a => new Topic { Title = "newtitle" + a, CreateTime = DateTime.Now }).ToList();
|
||||
Assert.Equal(9989, g.sqlserver.Insert<Topic>(items).ExecuteAffrows());
|
||||
}
|
||||
[Fact]
|
||||
public void ExecuteIdentity() {
|
||||
@ -73,6 +76,11 @@ 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 });
|
||||
|
||||
Assert.NotEqual(0, insert.AppendData(items.First()).ExecuteIdentity());
|
||||
|
||||
|
||||
items = Enumerable.Range(0, 9999).Select(a => new Topic { Title = "newtitle" + a, CreateTime = DateTime.Now }).ToList();
|
||||
var lastId = g.sqlite.Select<Topic>().Max(a => a.Id);
|
||||
Assert.NotEqual(lastId, g.sqlserver.Insert<Topic>(items).ExecuteIdentity());
|
||||
}
|
||||
[Fact]
|
||||
public void ExecuteInserted() {
|
||||
@ -80,6 +88,11 @@ 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 items2 = insert.AppendData(items).ExecuteInserted();
|
||||
|
||||
items = Enumerable.Range(0, 9990).Select(a => new Topic { Title = "newtitle" + a, CreateTime = DateTime.Now }).ToList();
|
||||
var itemsInserted = g.sqlserver.Insert<Topic>(items).ExecuteInserted();
|
||||
Assert.Equal(items.First().Title, itemsInserted.First().Title);
|
||||
Assert.Equal(items.Last().Title, itemsInserted.Last().Title);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -66,7 +66,7 @@ namespace FreeSql.Tests.Sqlite {
|
||||
[Fact]
|
||||
public void ExecuteDeleted() {
|
||||
|
||||
//var item = g.Sqlite.Insert<Topic>(new Topic { Title = "xxxx", CreateTime = DateTime.Now }).ExecuteInserted();
|
||||
//var item = g.Sqlite.Delete<Topic>(new Topic { Title = "xxxx", CreateTime = DateTime.Now }).ExecuteInserted();
|
||||
//Assert.Equal(item[0].Id, delete.Where(a => a.Id == item[0].Id).ExecuteDeleted()[0].Id);
|
||||
}
|
||||
|
||||
|
@ -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,23 +14,128 @@ 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;
|
||||
@ -37,18 +144,46 @@ namespace FreeSql.SqlServer.Curd {
|
||||
sb.Append(_commonUtils.QuoteReadColumn(col.CsType, $"INSERTED.{_commonUtils.QuoteSqlName(col.Attribute.Name)}")).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
|
||||
++colidx;
|
||||
}
|
||||
|
||||
var validx = sql.IndexOf(") VALUES");
|
||||
output = sb.ToString();
|
||||
}
|
||||
var validx = oldsql.IndexOf(") VALUES");
|
||||
if (validx == -1) throw new ArgumentException("找不到 VALUES");
|
||||
sb.Insert(0, sql.Substring(0, validx + 1));
|
||||
sb.Append(sql.Substring(validx + 1));
|
||||
var newsql = new StringBuilder().Append(output);
|
||||
newsql.Insert(0, oldsql.Substring(0, validx + 1));
|
||||
newsql.Append(oldsql.Substring(validx + 1));
|
||||
return newsql.ToString();
|
||||
};
|
||||
|
||||
return _orm.Ado.Query<T1>(_transaction, CommandType.Text, sb.ToString(), _params);
|
||||
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() {
|
||||
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;
|
||||
@ -57,13 +192,89 @@ namespace FreeSql.SqlServer.Curd {
|
||||
sb.Append(_commonUtils.QuoteReadColumn(col.CsType, $"INSERTED.{_commonUtils.QuoteSqlName(col.Attribute.Name)}")).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
|
||||
++colidx;
|
||||
}
|
||||
|
||||
var validx = sql.IndexOf(") VALUES");
|
||||
output = sb.ToString();
|
||||
}
|
||||
var validx = oldsql.IndexOf(") VALUES");
|
||||
if (validx == -1) throw new ArgumentException("找不到 VALUES");
|
||||
sb.Insert(0, sql.Substring(0, validx + 1));
|
||||
sb.Append(sql.Substring(validx + 1));
|
||||
var newsql = new StringBuilder().Append(output);
|
||||
newsql.Insert(0, oldsql.Substring(0, validx + 1));
|
||||
newsql.Append(oldsql.Substring(validx + 1));
|
||||
return oldsql;
|
||||
};
|
||||
|
||||
return await _orm.Ado.QueryAsync<T1>(_transaction, CommandType.Text, sb.ToString(), _params);
|
||||
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();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user