From 0a048567b851d0de49877585449f28b6ce0385ca Mon Sep 17 00:00:00 2001
From: 2881099 <2881099@qq.com>
Date: Tue, 22 Aug 2023 14:14:20 +0800
Subject: [PATCH] =?UTF-8?q?-=20=E5=A2=9E=E5=8A=A0=20IInsertOrUpdate=20Batc?=
=?UTF-8?q?hOptions=20=E9=80=89=E9=A1=B9=EF=BC=9B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
FreeSql/Interface/Curd/IInsertOrUpdate.cs | 10 ++
.../CommonProvider/InsertOrUpdateProvider.cs | 101 ++++++++++++++----
2 files changed, 92 insertions(+), 19 deletions(-)
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));