diff --git a/FreeSql/Interface/Curd/IInsertOrUpdate.cs b/FreeSql/Interface/Curd/IInsertOrUpdate.cs index 76e3ee20..14dd06a1 100644 --- a/FreeSql/Interface/Curd/IInsertOrUpdate.cs +++ b/FreeSql/Interface/Curd/IInsertOrUpdate.cs @@ -96,6 +96,16 @@ namespace FreeSql /// IInsertOrUpdate UpdateSet(Expression> exp); + /// + /// 批量执行选项设置,一般不需要使用该方法 + /// 各数据库 rows 限制不一样,默认设置:200 + /// 若没有事务传入,内部(默认)会自动开启新事务,保证拆包执行的完整性。 + /// + /// 指定根据 rows 上限数量拆分执行 + /// 是否自动开启事务 + /// + IInsertOrUpdate BatchOptions(int rowsLimit, bool autoTransaction = true); + /// /// 设置表名规则,可用于分库/分表,参数1:默认表名;返回值:新表名; /// diff --git a/FreeSql/Internal/CommonProvider/InsertOrUpdateProvider.cs b/FreeSql/Internal/CommonProvider/InsertOrUpdateProvider.cs index e8ccd0b8..89a25562 100644 --- a/FreeSql/Internal/CommonProvider/InsertOrUpdateProvider.cs +++ b/FreeSql/Internal/CommonProvider/InsertOrUpdateProvider.cs @@ -27,6 +27,8 @@ namespace FreeSql.Internal.CommonProvider public TableInfo _table; public ColumnInfo[] _tempPrimarys; public Func _tableRule; + public int _batchValuesLimit; + public bool _batchAutoTransaction = true; public DbParameter[] _params; public DbTransaction _transaction; public DbConnection _connection; @@ -56,7 +58,13 @@ namespace FreeSql.Internal.CommonProvider { _source.Clear(); _sourceSql = null; + _doNothing = false; + _updateIgnore.Clear(); _auditValueChangedDict.Clear(); + _updateSetDict.Clear(); + _batchValuesLimit = 0; + _batchAutoTransaction = false; + _params = null; } public IInsertOrUpdate WithTransaction(DbTransaction transaction) @@ -204,6 +212,13 @@ namespace FreeSql.Internal.CommonProvider return this; } + public virtual IInsertOrUpdate BatchOptions(int valuesLimit, bool autoTransaction = true) + { + _batchValuesLimit = valuesLimit; + _batchAutoTransaction = autoTransaction; + return this; + } + protected string TableRuleInvoke() { var tbname = _table?.DbName ?? ""; @@ -353,19 +368,31 @@ namespace FreeSql.Internal.CommonProvider if (threadTransaction != null) this.WithTransaction(threadTransaction); } - if (_transaction != null || _orm.Ado.MasterPool == null) + if (_transaction != null || _orm.Ado.MasterPool == null || _batchAutoTransaction == false) { _SplitSourceByIdentityValueIsNullFlag = 1; foreach (var tmpsource in ss.Item1) { - _source = tmpsource; - affrows += this.RawExecuteAffrows(); + var pageTotal = Math.Ceiling(tmpsource.Count * 1.0 / _batchValuesLimit); + for (var pageNumber = 1; pageNumber <= pageTotal; pageNumber++) + { + _source = pageNumber > 1 ? + tmpsource.Skip((pageNumber - 1) * _batchValuesLimit).Take(_batchValuesLimit).ToList() : + tmpsource.Take(_batchValuesLimit).ToList(); + affrows += this.RawExecuteAffrows(); + } } _SplitSourceByIdentityValueIsNullFlag = 2; foreach (var tmpsource in ss.Item2) { - _source = tmpsource; - affrows += this.RawExecuteAffrows(); + var pageTotal = Math.Ceiling(tmpsource.Count * 1.0 / _batchValuesLimit); + for (var pageNumber = 1; pageNumber <= pageTotal; pageNumber++) + { + _source = pageNumber > 1 ? + tmpsource.Skip((pageNumber - 1) * _batchValuesLimit).Take(_batchValuesLimit).ToList() : + tmpsource.Take(_batchValuesLimit).ToList(); + affrows += this.RawExecuteAffrows(); + } } } else @@ -380,14 +407,26 @@ namespace FreeSql.Internal.CommonProvider _SplitSourceByIdentityValueIsNullFlag = 1; foreach (var tmpsource in ss.Item1) { - _source = tmpsource; - affrows += this.RawExecuteAffrows(); + var pageTotal = Math.Ceiling(tmpsource.Count * 1.0 / _batchValuesLimit); + for (var pageNumber = 1; pageNumber <= pageTotal; pageNumber++) + { + _source = pageNumber > 1 ? + tmpsource.Skip((pageNumber - 1) * _batchValuesLimit).Take(_batchValuesLimit).ToList() : + tmpsource.Take(_batchValuesLimit).ToList(); + affrows += this.RawExecuteAffrows(); + } } _SplitSourceByIdentityValueIsNullFlag = 2; foreach (var tmpsource in ss.Item2) { - _source = tmpsource; - affrows += this.RawExecuteAffrows(); + var pageTotal = Math.Ceiling(tmpsource.Count * 1.0 / _batchValuesLimit); + for (var pageNumber = 1; pageNumber <= pageTotal; pageNumber++) + { + _source = pageNumber > 1 ? + tmpsource.Skip((pageNumber - 1) * _batchValuesLimit).Take(_batchValuesLimit).ToList() : + tmpsource.Take(_batchValuesLimit).ToList(); + affrows += this.RawExecuteAffrows(); + } } _transaction.Commit(); _orm.Aop.TraceAfterHandler?.Invoke(this, new Aop.TraceAfterEventArgs(transBefore, CoreStrings.Commit, null)); @@ -461,7 +500,7 @@ namespace FreeSql.Internal.CommonProvider } async public Task ExecuteAffrowsAsync(CancellationToken cancellationToken = default) { - if (_sourceSql != null) return this.RawExecuteAffrows(); + if (_sourceSql != null) return await this.RawExecuteAffrowsAsync(cancellationToken); var affrows = 0; var ss = SplitSourceByIdentityValueIsNull(_source); try @@ -472,19 +511,31 @@ namespace FreeSql.Internal.CommonProvider if (threadTransaction != null) this.WithTransaction(threadTransaction); } - if (_transaction != null || _orm.Ado.MasterPool == null) + if (_transaction != null || _orm.Ado.MasterPool == null || _batchAutoTransaction == false) { _SplitSourceByIdentityValueIsNullFlag = 1; foreach (var tmpsource in ss.Item1) { - _source = tmpsource; - affrows += await this.RawExecuteAffrowsAsync(cancellationToken); + var pageTotal = Math.Ceiling(tmpsource.Count * 1.0 / _batchValuesLimit); + for (var pageNumber = 1; pageNumber <= pageTotal; pageNumber++) + { + _source = pageNumber > 1 ? + tmpsource.Skip((pageNumber - 1) * _batchValuesLimit).Take(_batchValuesLimit).ToList() : + tmpsource.Take(_batchValuesLimit).ToList(); + affrows += await this.RawExecuteAffrowsAsync(cancellationToken); + } } _SplitSourceByIdentityValueIsNullFlag = 2; foreach (var tmpsource in ss.Item2) { - _source = tmpsource; - affrows += await this.RawExecuteAffrowsAsync(cancellationToken); + var pageTotal = Math.Ceiling(tmpsource.Count * 1.0 / _batchValuesLimit); + for (var pageNumber = 1; pageNumber <= pageTotal; pageNumber++) + { + _source = pageNumber > 1 ? + tmpsource.Skip((pageNumber - 1) * _batchValuesLimit).Take(_batchValuesLimit).ToList() : + tmpsource.Take(_batchValuesLimit).ToList(); + affrows += await this.RawExecuteAffrowsAsync(cancellationToken); + } } } else @@ -499,14 +550,26 @@ namespace FreeSql.Internal.CommonProvider _SplitSourceByIdentityValueIsNullFlag = 1; foreach (var tmpsource in ss.Item1) { - _source = tmpsource; - affrows += await this.RawExecuteAffrowsAsync(cancellationToken); + var pageTotal = Math.Ceiling(tmpsource.Count * 1.0 / _batchValuesLimit); + for (var pageNumber = 1; pageNumber <= pageTotal; pageNumber++) + { + _source = pageNumber > 1 ? + tmpsource.Skip((pageNumber - 1) * _batchValuesLimit).Take(_batchValuesLimit).ToList() : + tmpsource.Take(_batchValuesLimit).ToList(); + affrows += await this.RawExecuteAffrowsAsync(cancellationToken); + } } _SplitSourceByIdentityValueIsNullFlag = 2; foreach (var tmpsource in ss.Item2) { - _source = tmpsource; - affrows += await this.RawExecuteAffrowsAsync(cancellationToken); + var pageTotal = Math.Ceiling(tmpsource.Count * 1.0 / _batchValuesLimit); + for (var pageNumber = 1; pageNumber <= pageTotal; pageNumber++) + { + _source = pageNumber > 1 ? + tmpsource.Skip((pageNumber - 1) * _batchValuesLimit).Take(_batchValuesLimit).ToList() : + tmpsource.Take(_batchValuesLimit).ToList(); + affrows += await this.RawExecuteAffrowsAsync(cancellationToken); + } } _transaction.Commit(); _orm.Aop.TraceAfterHandler?.Invoke(this, new Aop.TraceAfterEventArgs(transBefore, CoreStrings.Commit, null));