mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-12-21 17:05:47 +08:00
- 增加 ISelect.ToDataTable 系列方法;
- 增加 无参数化命令执行,可配置全局 ICodeFirst.IsNoneCommandParameter、或临时 IInsert/IUpdate.NoneParameter() 便于调试; - 关闭 自动同步结构功能,避免线上环境误操作; - 优化 IInsert 批量插入容易导致 values 过多、或参数化过多的问题,5个数据库均已优化;
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using FreeSql.Internal.Model;
|
||||
using SafeObjectPool;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
@@ -18,6 +19,7 @@ namespace FreeSql.Internal.CommonProvider {
|
||||
protected Dictionary<string, bool> _ignore = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
|
||||
protected TableInfo _table;
|
||||
protected Func<string, string> _tableRule;
|
||||
protected bool _noneParameter;
|
||||
protected DbParameter[] _params;
|
||||
protected DbTransaction _transaction;
|
||||
|
||||
@@ -26,6 +28,7 @@ namespace FreeSql.Internal.CommonProvider {
|
||||
_commonUtils = commonUtils;
|
||||
_commonExpression = commonExpression;
|
||||
_table = _commonUtils.GetTableByEntity(typeof(T1));
|
||||
_noneParameter = _orm.CodeFirst.IsNoneCommandParameter;
|
||||
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure<T1>();
|
||||
}
|
||||
|
||||
@@ -33,6 +36,10 @@ namespace FreeSql.Internal.CommonProvider {
|
||||
_transaction = transaction;
|
||||
return this;
|
||||
}
|
||||
public IInsert<T1> NoneParameter() {
|
||||
_noneParameter = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IInsert<T1> AppendData(T1 source) {
|
||||
if (source != null) _source.Add(source);
|
||||
@@ -43,8 +50,228 @@ namespace FreeSql.Internal.CommonProvider {
|
||||
return this;
|
||||
}
|
||||
|
||||
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);
|
||||
#region 参数化数据限制,或values数量限制
|
||||
internal List<T1>[] SplitSource(int valuesLimit, int parameterLimit) {
|
||||
valuesLimit = valuesLimit - 1;
|
||||
parameterLimit = parameterLimit - 1;
|
||||
if (_source == null || _source.Any() == false) return new List<T1>[0];
|
||||
if (_source.Count == 1) return new[] { _source };
|
||||
if (_noneParameter) {
|
||||
if (_source.Count < valuesLimit) return new[] { _source };
|
||||
|
||||
var execCount = (int)Math.Ceiling(1.0 * _source.Count / valuesLimit);
|
||||
var ret = new List<T1>[execCount];
|
||||
for (var a = 0; a < execCount; a++) {
|
||||
var subSource = new List<T1>();
|
||||
subSource = _source.GetRange(a * valuesLimit, Math.Min(valuesLimit, _source.Count - a * valuesLimit));
|
||||
ret[a] = subSource;
|
||||
}
|
||||
return ret;
|
||||
} else {
|
||||
var colSum = _table.Columns.Count - _ignore.Count;
|
||||
var takeMax = parameterLimit / colSum;
|
||||
var pamTotal = colSum * _source.Count;
|
||||
if (pamTotal < parameterLimit) return new[] { _source };
|
||||
|
||||
var execCount = (int)Math.Ceiling(1.0 * pamTotal / parameterLimit);
|
||||
var ret = new List<T1>[execCount];
|
||||
for (var a = 0; a < execCount; a++) {
|
||||
var subSource = new List<T1>();
|
||||
subSource = _source.GetRange(a * takeMax, Math.Min(takeMax, _source.Count - a * takeMax));
|
||||
ret[a] = subSource;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
internal int SplitExecuteAffrows(int valuesLimit, int parameterLimit) {
|
||||
var ss = SplitSource(valuesLimit, parameterLimit);
|
||||
if (ss.Any() == false) return 0;
|
||||
if (ss.Length == 1) return this.RawExecuteAffrows();
|
||||
|
||||
var ret = 0;
|
||||
if (_transaction != null) {
|
||||
for (var a = 0; a < ss.Length; a++) {
|
||||
_source = ss[a];
|
||||
ret += this.RawExecuteAffrows();
|
||||
}
|
||||
} else {
|
||||
using (var conn = _orm.Ado.MasterPool.Get()) {
|
||||
_transaction = conn.Value.BeginTransaction();
|
||||
try {
|
||||
for (var a = 0; a < ss.Length; a++) {
|
||||
_source = ss[a];
|
||||
ret += this.RawExecuteAffrows();
|
||||
}
|
||||
_transaction.Commit();
|
||||
} catch {
|
||||
_transaction.Rollback();
|
||||
throw;
|
||||
}
|
||||
_transaction = null;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
async internal Task<int> SplitExecuteAffrowsAsync(int valuesLimit, int parameterLimit) {
|
||||
var ss = SplitSource(valuesLimit, parameterLimit);
|
||||
if (ss.Any() == false) return 0;
|
||||
if (ss.Length == 1) return await this.RawExecuteAffrowsAsync();
|
||||
|
||||
var ret = 0;
|
||||
if (_transaction != null) {
|
||||
for (var a = 0; a < ss.Length; a++) {
|
||||
_source = ss[a];
|
||||
ret += await this.RawExecuteAffrowsAsync();
|
||||
}
|
||||
} else {
|
||||
using (var conn = await _orm.Ado.MasterPool.GetAsync()) {
|
||||
_transaction = conn.Value.BeginTransaction();
|
||||
try {
|
||||
for (var a = 0; a < ss.Length; a++) {
|
||||
_source = ss[a];
|
||||
ret += await this.RawExecuteAffrowsAsync();
|
||||
}
|
||||
_transaction.Commit();
|
||||
} catch {
|
||||
_transaction.Rollback();
|
||||
throw;
|
||||
}
|
||||
_transaction = null;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
internal long SplitExecuteIdentity(int valuesLimit, int parameterLimit) {
|
||||
var ss = SplitSource(valuesLimit, parameterLimit);
|
||||
if (ss.Any() == false) return 0;
|
||||
if (ss.Length == 1) return this.RawExecuteIdentity();
|
||||
|
||||
long ret = 0;
|
||||
if (_transaction != null) {
|
||||
for (var a = 0; a < ss.Length; a++) {
|
||||
_source = ss[a];
|
||||
if (a < ss.Length - 1) this.RawExecuteAffrows();
|
||||
else ret = this.RawExecuteIdentity();
|
||||
}
|
||||
} else {
|
||||
using (var conn = _orm.Ado.MasterPool.Get()) {
|
||||
_transaction = conn.Value.BeginTransaction();
|
||||
try {
|
||||
for (var a = 0; a < ss.Length; a++) {
|
||||
_source = ss[a];
|
||||
if (a < ss.Length - 1) this.RawExecuteAffrows();
|
||||
else ret = this.RawExecuteIdentity();
|
||||
}
|
||||
_transaction.Commit();
|
||||
} catch {
|
||||
_transaction.Rollback();
|
||||
throw;
|
||||
}
|
||||
_transaction = null;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
async internal Task<long> SplitExecuteIdentityAsync(int valuesLimit, int parameterLimit) {
|
||||
var ss = SplitSource(valuesLimit, parameterLimit);
|
||||
if (ss.Any() == false) return 0;
|
||||
if (ss.Length == 1) return await this.RawExecuteIdentityAsync();
|
||||
|
||||
long ret = 0;
|
||||
if (_transaction != null) {
|
||||
for (var a = 0; a < ss.Length; a++) {
|
||||
_source = ss[a];
|
||||
if (a < ss.Length - 1) await this.RawExecuteAffrowsAsync();
|
||||
else ret = await this.RawExecuteIdentityAsync();
|
||||
}
|
||||
} else {
|
||||
using (var conn = await _orm.Ado.MasterPool.GetAsync()) {
|
||||
_transaction = conn.Value.BeginTransaction();
|
||||
try {
|
||||
for (var a = 0; a < ss.Length; a++) {
|
||||
_source = ss[a];
|
||||
if (a < ss.Length - 1) await this.RawExecuteAffrowsAsync();
|
||||
else ret = await this.RawExecuteIdentityAsync();
|
||||
}
|
||||
_transaction.Commit();
|
||||
} catch {
|
||||
_transaction.Rollback();
|
||||
throw;
|
||||
}
|
||||
_transaction = null;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
internal List<T1> SplitExecuteInserted(int valuesLimit, int parameterLimit) {
|
||||
var ss = SplitSource(valuesLimit, parameterLimit);
|
||||
if (ss.Any() == false) return new List<T1>();
|
||||
if (ss.Length == 1) return this.RawExecuteInserted();
|
||||
|
||||
var ret = new List<T1>();
|
||||
if (_transaction != null) {
|
||||
for (var a = 0; a < ss.Length; a++) {
|
||||
_source = ss[a];
|
||||
ret.AddRange(this.RawExecuteInserted());
|
||||
}
|
||||
} else {
|
||||
using (var conn = _orm.Ado.MasterPool.Get()) {
|
||||
_transaction = conn.Value.BeginTransaction();
|
||||
try {
|
||||
for (var a = 0; a < ss.Length; a++) {
|
||||
_source = ss[a];
|
||||
ret.AddRange(this.RawExecuteInserted());
|
||||
}
|
||||
_transaction.Commit();
|
||||
} catch {
|
||||
_transaction.Rollback();
|
||||
throw;
|
||||
}
|
||||
_transaction = null;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
async internal Task<List<T1>> SplitExecuteInsertedAsync(int valuesLimit, int parameterLimit) {
|
||||
var ss = SplitSource(valuesLimit, parameterLimit);
|
||||
if (ss.Any() == false) return new List<T1>();
|
||||
if (ss.Length == 1) return await this.RawExecuteInsertedAsync();
|
||||
|
||||
var ret = new List<T1>();
|
||||
if (_transaction != null) {
|
||||
for (var a = 0; a < ss.Length; a++) {
|
||||
_source = ss[a];
|
||||
ret.AddRange(await this.RawExecuteInsertedAsync());
|
||||
}
|
||||
} else {
|
||||
using (var conn = await _orm.Ado.MasterPool.GetAsync()) {
|
||||
_transaction = conn.Value.BeginTransaction();
|
||||
try {
|
||||
for (var a = 0; a < ss.Length; a++) {
|
||||
_source = ss[a];
|
||||
ret.AddRange(await this.RawExecuteInsertedAsync());
|
||||
}
|
||||
_transaction.Commit();
|
||||
} catch {
|
||||
_transaction.Rollback();
|
||||
throw;
|
||||
}
|
||||
_transaction = null;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#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 abstract long RawExecuteIdentity();
|
||||
internal abstract Task<long> RawExecuteIdentityAsync();
|
||||
internal abstract List<T1> RawExecuteInserted();
|
||||
internal abstract Task<List<T1>> RawExecuteInsertedAsync();
|
||||
|
||||
public virtual int ExecuteAffrows() => RawExecuteAffrows();
|
||||
public virtual Task<int> ExecuteAffrowsAsync() => RawExecuteAffrowsAsync();
|
||||
public abstract long ExecuteIdentity();
|
||||
public abstract Task<long> ExecuteIdentityAsync();
|
||||
public abstract List<T1> ExecuteInserted();
|
||||
@@ -81,9 +308,8 @@ namespace FreeSql.Internal.CommonProvider {
|
||||
++colidx;
|
||||
}
|
||||
sb.Append(") VALUES");
|
||||
//_params = new DbParameter[colidx * _source.Count];
|
||||
_params = new DbParameter[0];
|
||||
//_params = new DbParameter[colidx * 5]; //批量添加第5行起,不使用参数化
|
||||
_params = _noneParameter ? new DbParameter[0] : new DbParameter[colidx * _source.Count];
|
||||
var specialParams = new List<DbParameter>();
|
||||
var didx = 0;
|
||||
foreach (var d in _source) {
|
||||
if (didx > 0) sb.Append(", ");
|
||||
@@ -98,17 +324,19 @@ namespace FreeSql.Internal.CommonProvider {
|
||||
if (col.Attribute.IsPrimary && (col.CsType == typeof(Guid) || col.CsType == typeof(Guid?))
|
||||
&& (val == null || (Guid)val == Guid.Empty)) tryp.SetValue(d, val = FreeUtil.NewMongodbId());
|
||||
}
|
||||
//if (didx >= 5)
|
||||
sb.Append(_commonUtils.GetNoneParamaterSqlValue(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);
|
||||
//}
|
||||
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);
|
||||
}
|
||||
++colidx2;
|
||||
}
|
||||
sb.Append(")");
|
||||
++didx;
|
||||
}
|
||||
if (_noneParameter && specialParams.Any())
|
||||
_params = specialParams.ToArray();
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user