- 恢复 BaseEntity SaveMany 方法;

This commit is contained in:
2881099
2024-11-22 11:23:32 +08:00
parent e0369ac855
commit 85e732fab0
8 changed files with 146 additions and 123 deletions

View File

@@ -226,6 +226,16 @@ namespace FreeSql
return affrows;
}
async public virtual Task SaveManyAsync(TEntity entity, string propertyName, CancellationToken cancellationToken = default)
{
var tracking = new AggregateRootTrackingChangeInfo();
var stateKey = Orm.GetEntityKeyString(EntityType, entity, false);
if (_states.TryGetValue(stateKey, out var state) == false) throw new Exception($"AggregateRootRepository 使用仓储对象查询后,才可以保存数据 {Orm.GetEntityString(EntityType, entity)}");
AggregateRootUtils.CompareEntityValue(_boundaryName, Orm, EntityType, state.Value, entity, propertyName, tracking);
await SaveTrackingChangeAsync(tracking, cancellationToken);
Attach(entity); //应该只存储 propertyName 内容
}
async Task<int> SaveTrackingChangeAsync(AggregateRootTrackingChangeInfo tracking, CancellationToken cancellationToken)
{
var affrows = 0;

View File

@@ -162,5 +162,18 @@ namespace FreeSql
Repository.UnitOfWork = _resolveUow?.Invoke();
return Repository.InsertOrUpdate(this as TEntity);
}
/// <summary>
/// To completely save the navigation properties of the entity in the form of sub-tables. <br />
/// 【完整】保存导航属性,子表
/// </summary>
/// <param name="navigatePropertyName">Navigation property name</param>
public virtual void SaveMany(string navigatePropertyName)
{
if (Repository == null)
Repository = Orm.GetRepository<TEntity>();
Repository.UnitOfWork = _resolveUow?.Invoke();
Repository.SaveMany(this as TEntity, navigatePropertyName);
}
}
}

View File

@@ -149,6 +149,19 @@ namespace FreeSql
Repository.UnitOfWork = _resolveUow?.Invoke();
return Repository.InsertOrUpdateAsync(this as TEntity);
}
/// <summary>
/// To completely save the navigation properties of the entity in the form of sub-tables. <br />
/// 【完整】保存导航属性,子表
/// </summary>
/// <param name="navigatePropertyName">Navigation property name</param>
public virtual Task SaveManyAsync(string navigatePropertyName)
{
if (Repository == null)
Repository = Orm.GetRepository<TEntity>();
Repository.UnitOfWork = _resolveUow?.Invoke();
return Repository.SaveManyAsync(this as TEntity, navigatePropertyName);
}
#endif
}
}

View File

@@ -82,6 +82,13 @@
</summary>
<returns></returns>
</member>
<member name="M:FreeSql.BaseEntity`1.SaveMany(System.String)">
<summary>
To completely save the navigation properties of the entity in the form of sub-tables. <br />
【完整】保存导航属性,子表
</summary>
<param name="navigatePropertyName">Navigation property name</param>
</member>
<member name="T:FreeSql.BaseEntityAsync`2">
<summary>
Entity base class, including CreateTime/UpdateTime/IsDeleted, the async CRUD methods, and ID primary key definition.
@@ -152,6 +159,13 @@
</summary>
<returns></returns>
</member>
<member name="M:FreeSql.BaseEntityAsync`1.SaveManyAsync(System.String)">
<summary>
To completely save the navigation properties of the entity in the form of sub-tables. <br />
【完整】保存导航属性,子表
</summary>
<param name="navigatePropertyName">Navigation property name</param>
</member>
<member name="T:FreeSql.BaseEntity">
<summary>
Entity base class, including CreateTime/UpdateTime/IsDeleted.

View File

@@ -149,6 +149,65 @@ namespace FreeSql
await AddOrUpdateNavigateAsync(item, true, null, cancellationToken);
}
async public Task SaveManyAsync(TEntity item, string propertyName, CancellationToken cancellationToken = default)
{
if (item == null) return;
if (string.IsNullOrEmpty(propertyName)) return;
if (_table.Properties.TryGetValue(propertyName, out var prop) == false) throw new KeyNotFoundException(DbContextErrorStrings.NotFound_Property(_table.Type.FullName, propertyName));
if (_table.ColumnsByCsIgnore.ContainsKey(propertyName)) throw new ArgumentException(DbContextErrorStrings.TypeHasSetProperty_IgnoreAttribute(_table.Type.FullName, propertyName));
var tref = _table.GetTableRef(propertyName, true, false);
if (tref == null) return;
switch (tref.RefType)
{
case TableRefType.OneToOne:
case TableRefType.ManyToOne:
case TableRefType.PgArrayToMany:
throw new ArgumentException(DbContextErrorStrings.PropertyOfType_IsNot_OneToManyOrManyToMany(_table.Type.FullName, propertyName));
}
await DbContextFlushCommandAsync(cancellationToken);
var oldEnable = _db.Options.EnableCascadeSave;
_db.Options.EnableCascadeSave = false;
try
{
await AddOrUpdateNavigateAsync(item, false, propertyName, cancellationToken);
if (tref.RefType == TableRefType.OneToMany)
{
await DbContextFlushCommandAsync(cancellationToken);
//删除没有保存的数据,求出主体的条件
var deleteWhereParentParam = Expression.Parameter(typeof(object), "a");
Expression whereParentExp = null;
for (var colidx = 0; colidx < tref.Columns.Count; colidx++)
{
var whereExp = Expression.Equal(
Expression.MakeMemberAccess(Expression.Convert(deleteWhereParentParam, tref.RefEntityType), tref.RefColumns[colidx].Table.Properties[tref.RefColumns[colidx].CsName]),
Expression.Constant(
FreeSql.Internal.Utils.GetDataReaderValue(
tref.Columns[colidx].CsType,
_db.OrmOriginal.GetEntityValueWithPropertyName(_table.Type, item, tref.Columns[colidx].CsName)), tref.RefColumns[colidx].CsType)
);
if (whereParentExp == null) whereParentExp = whereExp;
else whereParentExp = Expression.AndAlso(whereParentExp, whereExp);
}
var propValEach = GetItemValue(item, prop) as IEnumerable;
var subDelete = _db.OrmOriginal.Delete<object>().AsType(tref.RefEntityType)
.WithTransaction(_uow?.GetOrBeginTransaction())
.Where(Expression.Lambda<Func<object, bool>>(whereParentExp, deleteWhereParentParam));
foreach (var propValItem in propValEach)
{
subDelete.WhereDynamic(propValEach, true);
break;
}
await subDelete.ExecuteAffrowsAsync(cancellationToken);
}
}
finally
{
_db.Options.EnableCascadeSave = oldEnable;
}
}
async Task AddOrUpdateNavigateAsync(TEntity item, bool isAdd, string propertyName, CancellationToken cancellationToken)
{
Func<PropertyInfo, Task> action = async prop =>

View File

@@ -68,6 +68,12 @@ namespace FreeSql
await _db.SaveChangesAsync(cancellationToken);
return entity;
}
public virtual async Task SaveManyAsync(TEntity entity, string propertyName, CancellationToken cancellationToken = default)
{
await _dbset.SaveManyAsync(entity, propertyName, cancellationToken);
await _db.SaveChangesAsync(cancellationToken);
}
}
partial class BaseRepository<TEntity, TKey>

View File

@@ -126,6 +126,7 @@ namespace FreeSql
Task<int> UpdateAsync(TEntity entity, CancellationToken cancellationToken = default);
Task<int> UpdateAsync(IEnumerable<TEntity> entitys, CancellationToken cancellationToken = default);
Task<TEntity> InsertOrUpdateAsync(TEntity entity, CancellationToken cancellationToken = default);
Task SaveManyAsync(TEntity entity, string propertyName, CancellationToken cancellationToken = default);
Task<int> DeleteAsync(TEntity entity, CancellationToken cancellationToken = default);
Task<int> DeleteAsync(IEnumerable<TEntity> entitys, CancellationToken cancellationToken = default);

View File

@@ -5831,6 +5831,36 @@
<param name="end"></param>
<returns></returns>
</member>
<member name="M:FreeSqlGlobalExpressionCallExtensions.In``1(``0,``0)">
<summary>
field IN (value1)
</summary>
</member>
<member name="M:FreeSqlGlobalExpressionCallExtensions.In``1(``0,``0,``0)">
<summary>
field in (value1, value2)
</summary>
</member>
<member name="M:FreeSqlGlobalExpressionCallExtensions.In``1(``0,``0,``0,``0)">
<summary>
field in (value1, value2, value3)
</summary>
</member>
<member name="M:FreeSqlGlobalExpressionCallExtensions.In``1(``0,``0,``0,``0,``0)">
<summary>
field in (value1, value2, value3, value4)
</summary>
</member>
<member name="M:FreeSqlGlobalExpressionCallExtensions.In``1(``0,``0,``0,``0,``0,``0)">
<summary>
field in (value1, value2, value3, value4, value5)
</summary>
</member>
<member name="M:FreeSqlGlobalExpressionCallExtensions.In``1(``0,``0[])">
<summary>
field in (values)
</summary>
</member>
<member name="M:FreeSqlGlobalExtensions.DisplayCsharp(System.Type,System.Boolean)">
<summary>
获取 Type 的原始 c# 文本表示
@@ -6346,126 +6376,3 @@
</member>
</members>
</doc>
<returns></returns>
</member>
<member name="M:IFreeSql.Insert``1(System.Collections.Generic.List{``0})">
<summary>
插入数据,传入实体集合
</summary>
<typeparam name="T1"></typeparam>
<param name="source"></param>
<returns></returns>
</member>
<member name="M:IFreeSql.Insert``1(System.Collections.Generic.IEnumerable{``0})">
<summary>
插入数据,传入实体集合
</summary>
<typeparam name="T1"></typeparam>
<param name="source"></param>
<returns></returns>
</member>
<member name="M:IFreeSql.InsertOrUpdate``1">
<summary>
插入或更新数据,此功能依赖数据库特性(低版本可能不支持),参考如下:<para></para>
MySql 5.6+: on duplicate key update<para></para>
PostgreSQL 9.4+: on conflict do update<para></para>
SqlServer 2008+: merge into<para></para>
Oracle 11+: merge into<para></para>
Sqlite: replace into<para></para>
DuckDB: on conflict do update<para></para>
达梦: merge into<para></para>
人大金仓on conflict do update<para></para>
神通merge into<para></para>
MsAccess不支持<para></para>
注意区别FreeSql.Repository 仓储也有 InsertOrUpdate 方法(不依赖数据库特性)
</summary>
<typeparam name="T1"></typeparam>
<returns></returns>
</member>
<member name="M:IFreeSql.Update``1">
<summary>
修改数据
</summary>
<typeparam name="T1"></typeparam>
<returns></returns>
</member>
<member name="M:IFreeSql.Update``1(System.Object)">
<summary>
修改数据,传入动态条件,如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1}
</summary>
<typeparam name="T1"></typeparam>
<param name="dywhere">主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合</param>
<returns></returns>
</member>
<member name="M:IFreeSql.Select``1">
<summary>
查询数据
</summary>
<typeparam name="T1"></typeparam>
<returns></returns>
</member>
<member name="M:IFreeSql.Select``1(System.Object)">
<summary>
查询数据,传入动态条件,如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1}
</summary>
<typeparam name="T1"></typeparam>
<param name="dywhere">主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合</param>
<returns></returns>
</member>
<member name="M:IFreeSql.Delete``1">
<summary>
删除数据
</summary>
<typeparam name="T1"></typeparam>
<returns></returns>
</member>
<member name="M:IFreeSql.Delete``1(System.Object)">
<summary>
删除数据,传入动态条件,如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1}
</summary>
<typeparam name="T1"></typeparam>
<param name="dywhere">主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合</param>
<returns></returns>
</member>
<member name="M:IFreeSql.Transaction(System.Action)">
<summary>
开启事务(不支持异步)<para></para>
v1.5.0 关闭了线程事务超时自动提交的机制
</summary>
<param name="handler">事务体 () => {}</param>
</member>
<member name="M:IFreeSql.Transaction(System.Data.IsolationLevel,System.Action)">
<summary>
开启事务(不支持异步)<para></para>
v1.5.0 关闭了线程事务超时自动提交的机制
</summary>
<param name="isolationLevel"></param>
<param name="handler">事务体 () => {}</param>
</member>
<member name="P:IFreeSql.Ado">
<summary>
数据库访问对象
</summary>
</member>
<member name="P:IFreeSql.Aop">
<summary>
所有拦截方法都在这里
</summary>
</member>
<member name="P:IFreeSql.CodeFirst">
<summary>
CodeFirst 模式开发相关方法
</summary>
</member>
<member name="P:IFreeSql.DbFirst">
<summary>
DbFirst 模式开发相关方法
</summary>
</member>
<member name="P:IFreeSql.GlobalFilter">
<summary>
全局过滤设置,可默认附加为 Select/Update/Delete 条件
</summary>
</member>
</members>
</doc>