mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-04-22 10:42:52 +08:00
- 增加 Repository/DbContext SaveMany 方法实现一对多,子数据的完整保存;
- 调整 SaveManyToMany 方法名为 SaveMany;
This commit is contained in:
parent
b5629b13a6
commit
04107d3d24
@ -158,14 +158,18 @@ namespace FreeSql
|
|||||||
this.Set<TEntity>().AddOrUpdate(data);
|
this.Set<TEntity>().AddOrUpdate(data);
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 保存实体的指定 ManyToMany 导航属性
|
/// 保存实体的指定 ManyToMany/OneToMany 导航属性(完整对比)<para></para>
|
||||||
|
/// 场景:在关闭级联保存功能之后,手工使用本方法<para></para>
|
||||||
|
/// 例子:保存商品的 OneToMany 集合属性,SaveMany(goods, "Skus")<para></para>
|
||||||
|
/// 当 goods.Skus 为空(非null)时,会删除表中已存在的所有数据<para></para>
|
||||||
|
/// 当 goods.Skus 不为空(非null)时,添加/更新后,删除表中不存在 Skus 集合属性的所有记录
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data">实体对象</param>
|
/// <param name="data">实体对象</param>
|
||||||
/// <param name="propertyName">属性名</param>
|
/// <param name="propertyName">属性名</param>
|
||||||
public void SaveManyToMany<TEntity>(TEntity data, string propertyName) where TEntity : class
|
public void SaveMany<TEntity>(TEntity data, string propertyName) where TEntity : class
|
||||||
{
|
{
|
||||||
CheckEntityTypeOrThrow(typeof(TEntity));
|
CheckEntityTypeOrThrow(typeof(TEntity));
|
||||||
this.Set<TEntity>().SaveManyToMany(data, propertyName);
|
this.Set<TEntity>().SaveMany(data, propertyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -212,10 +216,10 @@ namespace FreeSql
|
|||||||
CheckEntityTypeOrThrow(typeof(TEntity));
|
CheckEntityTypeOrThrow(typeof(TEntity));
|
||||||
return this.Set<TEntity>().AddOrUpdateAsync(data);
|
return this.Set<TEntity>().AddOrUpdateAsync(data);
|
||||||
}
|
}
|
||||||
public Task SaveManyToManyAsync<TEntity>(TEntity data, string propertyName) where TEntity : class
|
public Task SaveManyAsync<TEntity>(TEntity data, string propertyName) where TEntity : class
|
||||||
{
|
{
|
||||||
CheckEntityTypeOrThrow(typeof(TEntity));
|
CheckEntityTypeOrThrow(typeof(TEntity));
|
||||||
return this.Set<TEntity>().SaveManyToManyAsync(data, propertyName);
|
return this.Set<TEntity>().SaveManyAsync(data, propertyName);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -9,9 +9,9 @@ namespace FreeSql
|
|||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否开启一对多,多对多联级保存功能<para></para>
|
/// 是否开启一对多,多对多级联保存功能<para></para>
|
||||||
/// <para></para>
|
/// <para></para>
|
||||||
/// 【一对多】模型下, 保存时可联级保存实体的属性集合。出于使用安全考虑我们没做完整对比,只实现实体属性集合的添加或更新操作,所以不会删除实体属性集合的数据。<para></para>
|
/// 【一对多】模型下, 保存时可级联保存实体的属性集合。出于使用安全考虑我们没做完整对比,只实现实体属性集合的添加或更新操作,所以不会删除实体属性集合的数据。<para></para>
|
||||||
/// 完整对比的功能使用起来太危险,试想下面的场景:<para></para>
|
/// 完整对比的功能使用起来太危险,试想下面的场景:<para></para>
|
||||||
/// - 保存的时候,实体的属性集合是空的,如何操作?记录全部删除?<para></para>
|
/// - 保存的时候,实体的属性集合是空的,如何操作?记录全部删除?<para></para>
|
||||||
/// - 保存的时候,由于数据库中记录非常之多,那么只想保存子表的部分数据,或者只需要添加,如何操作?<para></para>
|
/// - 保存的时候,由于数据库中记录非常之多,那么只想保存子表的部分数据,或者只需要添加,如何操作?<para></para>
|
||||||
|
@ -133,22 +133,44 @@ namespace FreeSql
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async public Task SaveManyToManyAsync(TEntity item, string propertyName)
|
async public Task SaveManyAsync(TEntity item, string propertyName)
|
||||||
{
|
{
|
||||||
if (item == null) return;
|
if (item == null) return;
|
||||||
if (_table.Properties.ContainsKey(propertyName) == false) throw new KeyNotFoundException($"{_table.Type.FullName} 不存在属性 {propertyName}");
|
if (string.IsNullOrEmpty(propertyName)) return;
|
||||||
|
if (_table.Properties.TryGetValue(propertyName, out var prop) == false) throw new KeyNotFoundException($"{_table.Type.FullName} 不存在属性 {propertyName}");
|
||||||
if (_table.ColumnsByCsIgnore.ContainsKey(propertyName)) throw new ArgumentException($"{_table.Type.FullName} 类型已设置属性 {propertyName} 忽略特性");
|
if (_table.ColumnsByCsIgnore.ContainsKey(propertyName)) throw new ArgumentException($"{_table.Type.FullName} 类型已设置属性 {propertyName} 忽略特性");
|
||||||
|
|
||||||
var tref = _table.GetTableRef(propertyName, true);
|
var tref = _table.GetTableRef(propertyName, true);
|
||||||
if (tref.RefType != Internal.Model.TableRefType.ManyToMany) throw new ArgumentException($"{_table.Type.FullName} 类型的属性 {propertyName} 不是 ManyToMany 特性");
|
if (tref == null) return;
|
||||||
DbContextExecCommand();
|
switch (tref.RefType)
|
||||||
|
{
|
||||||
|
case Internal.Model.TableRefType.OneToOne:
|
||||||
|
case Internal.Model.TableRefType.ManyToOne:
|
||||||
|
throw new ArgumentException($"{_table.Type.FullName} 类型的属性 {propertyName} 不是 OneToMany 或 ManyToMany 特性");
|
||||||
|
}
|
||||||
|
|
||||||
|
await DbContextExecCommandAsync();
|
||||||
var oldEnable = _db.Options.EnableAddOrUpdateNavigateList;
|
var oldEnable = _db.Options.EnableAddOrUpdateNavigateList;
|
||||||
_db.Options.EnableAddOrUpdateNavigateList = false;
|
_db.Options.EnableAddOrUpdateNavigateList = false;
|
||||||
await AddOrUpdateNavigateListAsync(item, false, propertyName);
|
try
|
||||||
_db.Options.EnableAddOrUpdateNavigateList = oldEnable;
|
{
|
||||||
|
await AddOrUpdateNavigateListAsync(item, false, propertyName);
|
||||||
|
if (tref.RefType == Internal.Model.TableRefType.OneToMany)
|
||||||
|
{
|
||||||
|
await DbContextExecCommandAsync();
|
||||||
|
//删除没有保存的数据
|
||||||
|
var propValEach = GetItemValue(item, prop) as IEnumerable;
|
||||||
|
await _db.Orm.Select<object>().AsType(tref.RefEntityType).WhereDynamic(propValEach, true)
|
||||||
|
.ToDelete().ExecuteAffrowsAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_db.Options.EnableAddOrUpdateNavigateList = oldEnable;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
async Task AddOrUpdateNavigateListAsync(TEntity item, bool isAdd, string propertyName = null)
|
async Task AddOrUpdateNavigateListAsync(TEntity item, bool isAdd, string propertyName = null)
|
||||||
{
|
{
|
||||||
Type itemType = null;
|
|
||||||
Func<PropertyInfo, Task> action = async prop =>
|
Func<PropertyInfo, Task> action = async prop =>
|
||||||
{
|
{
|
||||||
if (_table.ColumnsByCsIgnore.ContainsKey(prop.Name)) return;
|
if (_table.ColumnsByCsIgnore.ContainsKey(prop.Name)) return;
|
||||||
@ -163,26 +185,7 @@ namespace FreeSql
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
object propVal = null;
|
var propValEach = GetItemValue(item, prop) as IEnumerable;
|
||||||
if (itemType == null) itemType = item.GetType();
|
|
||||||
if (_table.TypeLazy != null && itemType == _table.TypeLazy)
|
|
||||||
{
|
|
||||||
var lazyField = _dicLazyIsSetField.GetOrAdd(_table.TypeLazy, tl => new ConcurrentDictionary<string, FieldInfo>()).GetOrAdd(prop.Name, propName =>
|
|
||||||
_table.TypeLazy.GetField($"__lazy__{propName}", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance));
|
|
||||||
if (lazyField != null)
|
|
||||||
{
|
|
||||||
var lazyFieldValue = (bool)lazyField.GetValue(item);
|
|
||||||
if (lazyFieldValue == false) return;
|
|
||||||
}
|
|
||||||
propVal = prop.GetValue(item);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
propVal = prop.GetValue(item);
|
|
||||||
if (propVal == null) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var propValEach = propVal as IEnumerable;
|
|
||||||
if (propValEach == null) return;
|
if (propValEach == null) return;
|
||||||
DbSet<object> refSet = GetDbSetObject(tref.RefEntityType);
|
DbSet<object> refSet = GetDbSetObject(tref.RefEntityType);
|
||||||
switch (tref.RefType)
|
switch (tref.RefType)
|
||||||
|
@ -136,34 +136,53 @@ namespace FreeSql
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ConcurrentDictionary<Type, ConcurrentDictionary<string, FieldInfo>> _dicLazyIsSetField = new ConcurrentDictionary<Type, ConcurrentDictionary<string, FieldInfo>>();
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 保存实体的指定 ManyToMany 导航属性
|
/// 保存实体的指定 ManyToMany/OneToMany 导航属性(完整对比)<para></para>
|
||||||
|
/// 场景:在关闭级联保存功能之后,手工使用本方法<para></para>
|
||||||
|
/// 例子:保存商品的 OneToMany 集合属性,SaveMany(goods, "Skus")<para></para>
|
||||||
|
/// 当 goods.Skus 为空(非null)时,会删除表中已存在的所有数据<para></para>
|
||||||
|
/// 当 goods.Skus 不为空(非null)时,添加/更新后,删除表中不存在 Skus 集合属性的所有记录
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="item">实体对象</param>
|
/// <param name="item">实体对象</param>
|
||||||
/// <param name="propertyName">属性名</param>
|
/// <param name="propertyName">属性名</param>
|
||||||
public void SaveManyToMany(TEntity item, string propertyName)
|
public void SaveMany(TEntity item, string propertyName)
|
||||||
{
|
{
|
||||||
if (item == null) return;
|
if (item == null) return;
|
||||||
if (_table.Properties.ContainsKey(propertyName) == false) throw new KeyNotFoundException($"{_table.Type.FullName} 不存在属性 {propertyName}");
|
if (string.IsNullOrEmpty(propertyName)) return;
|
||||||
|
if (_table.Properties.TryGetValue(propertyName, out var prop) == false) throw new KeyNotFoundException($"{_table.Type.FullName} 不存在属性 {propertyName}");
|
||||||
if (_table.ColumnsByCsIgnore.ContainsKey(propertyName)) throw new ArgumentException($"{_table.Type.FullName} 类型已设置属性 {propertyName} 忽略特性");
|
if (_table.ColumnsByCsIgnore.ContainsKey(propertyName)) throw new ArgumentException($"{_table.Type.FullName} 类型已设置属性 {propertyName} 忽略特性");
|
||||||
|
|
||||||
var tref = _table.GetTableRef(propertyName, true);
|
var tref = _table.GetTableRef(propertyName, true);
|
||||||
if (tref.RefType != Internal.Model.TableRefType.ManyToMany) throw new ArgumentException($"{_table.Type.FullName} 类型的属性 {propertyName} 不是 ManyToMany 特性");
|
if (tref == null) return;
|
||||||
|
switch (tref.RefType)
|
||||||
|
{
|
||||||
|
case Internal.Model.TableRefType.OneToOne:
|
||||||
|
case Internal.Model.TableRefType.ManyToOne:
|
||||||
|
throw new ArgumentException($"{_table.Type.FullName} 类型的属性 {propertyName} 不是 OneToMany 或 ManyToMany 特性");
|
||||||
|
}
|
||||||
|
|
||||||
DbContextExecCommand();
|
DbContextExecCommand();
|
||||||
var oldEnable = _db.Options.EnableAddOrUpdateNavigateList;
|
var oldEnable = _db.Options.EnableAddOrUpdateNavigateList;
|
||||||
_db.Options.EnableAddOrUpdateNavigateList = false;
|
_db.Options.EnableAddOrUpdateNavigateList = false;
|
||||||
AddOrUpdateNavigateList(item, false, propertyName);
|
try
|
||||||
_db.Options.EnableAddOrUpdateNavigateList = oldEnable;
|
{
|
||||||
|
AddOrUpdateNavigateList(item, false, propertyName);
|
||||||
|
if (tref.RefType == Internal.Model.TableRefType.OneToMany)
|
||||||
|
{
|
||||||
|
DbContextExecCommand();
|
||||||
|
//删除没有保存的数据
|
||||||
|
var propValEach = GetItemValue(item, prop) as IEnumerable;
|
||||||
|
_db.Orm.Select<object>().AsType(tref.RefEntityType).WhereDynamic(propValEach, true)
|
||||||
|
.ToDelete().ExecuteAffrows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_db.Options.EnableAddOrUpdateNavigateList = oldEnable;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/// <summary>
|
|
||||||
/// 联级保存导航集合
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">实体对象</param>
|
|
||||||
/// <param name="isAdd">是否为新增的实体对象</param>
|
|
||||||
/// <param name="propertyName">指定保存的属性</param>
|
|
||||||
void AddOrUpdateNavigateList(TEntity item, bool isAdd, string propertyName = null)
|
void AddOrUpdateNavigateList(TEntity item, bool isAdd, string propertyName = null)
|
||||||
{
|
{
|
||||||
Type itemType = null;
|
|
||||||
Action<PropertyInfo> action = prop =>
|
Action<PropertyInfo> action = prop =>
|
||||||
{
|
{
|
||||||
if (_table.ColumnsByCsIgnore.ContainsKey(prop.Name)) return;
|
if (_table.ColumnsByCsIgnore.ContainsKey(prop.Name)) return;
|
||||||
@ -178,26 +197,7 @@ namespace FreeSql
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
object propVal = null;
|
var propValEach = GetItemValue(item, prop) as IEnumerable;
|
||||||
if (itemType == null) itemType = item.GetType();
|
|
||||||
if (_table.TypeLazy != null && itemType == _table.TypeLazy)
|
|
||||||
{
|
|
||||||
var lazyField = _dicLazyIsSetField.GetOrAdd(_table.TypeLazy, tl => new ConcurrentDictionary<string, FieldInfo>()).GetOrAdd(prop.Name, propName =>
|
|
||||||
_table.TypeLazy.GetField($"__lazy__{propName}", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance));
|
|
||||||
if (lazyField != null)
|
|
||||||
{
|
|
||||||
var lazyFieldValue = (bool)lazyField.GetValue(item);
|
|
||||||
if (lazyFieldValue == false) return;
|
|
||||||
}
|
|
||||||
propVal = prop.GetValue(item, null);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
propVal = prop.GetValue(item, null);
|
|
||||||
if (propVal == null) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var propValEach = propVal as IEnumerable;
|
|
||||||
if (propValEach == null) return;
|
if (propValEach == null) return;
|
||||||
DbSet<object> refSet = GetDbSetObject(tref.RefEntityType);
|
DbSet<object> refSet = GetDbSetObject(tref.RefEntityType);
|
||||||
switch (tref.RefType)
|
switch (tref.RefType)
|
||||||
@ -313,6 +313,29 @@ namespace FreeSql
|
|||||||
else if (_table.Properties.TryGetValue(propertyName, out var prop))
|
else if (_table.Properties.TryGetValue(propertyName, out var prop))
|
||||||
action(prop);
|
action(prop);
|
||||||
}
|
}
|
||||||
|
static ConcurrentDictionary<Type, ConcurrentDictionary<string, FieldInfo>> _dicLazyIsSetField = new ConcurrentDictionary<Type, ConcurrentDictionary<string, FieldInfo>>();
|
||||||
|
object GetItemValue(TEntity item, PropertyInfo prop)
|
||||||
|
{
|
||||||
|
object propVal = null;
|
||||||
|
var itemType = item.GetType();
|
||||||
|
if (_table.TypeLazy != null && itemType == _table.TypeLazy)
|
||||||
|
{
|
||||||
|
var lazyField = _dicLazyIsSetField.GetOrAdd(_table.TypeLazy, tl => new ConcurrentDictionary<string, FieldInfo>()).GetOrAdd(prop.Name, propName =>
|
||||||
|
_table.TypeLazy.GetField($"__lazy__{propName}", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance));
|
||||||
|
if (lazyField != null)
|
||||||
|
{
|
||||||
|
var lazyFieldValue = (bool)lazyField.GetValue(item);
|
||||||
|
if (lazyFieldValue == false) return null;
|
||||||
|
}
|
||||||
|
propVal = prop.GetValue(item, null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
propVal = prop.GetValue(item, null);
|
||||||
|
if (propVal == null) return null;
|
||||||
|
}
|
||||||
|
return propVal;
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Update
|
#region Update
|
||||||
|
@ -32,9 +32,13 @@
|
|||||||
<typeparam name="TEntity"></typeparam>
|
<typeparam name="TEntity"></typeparam>
|
||||||
<param name="data"></param>
|
<param name="data"></param>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:FreeSql.DbContext.SaveManyToMany``1(``0,System.String)">
|
<member name="M:FreeSql.DbContext.SaveMany``1(``0,System.String)">
|
||||||
<summary>
|
<summary>
|
||||||
保存实体的指定 ManyToMany 导航属性
|
保存实体的指定 ManyToMany/OneToMany 导航属性(完整对比)<para></para>
|
||||||
|
场景:在关闭级联保存功能之后,手工使用本方法<para></para>
|
||||||
|
例子:保存商品的 OneToMany 集合属性,SaveMany(goods, "Skus")<para></para>
|
||||||
|
当 goods.Skus 为空(非null)时,会删除表中已存在的所有数据<para></para>
|
||||||
|
当 goods.Skus 不为空(非null)时,添加/更新后,删除表中不存在 Skus 集合属性的所有记录
|
||||||
</summary>
|
</summary>
|
||||||
<param name="data">实体对象</param>
|
<param name="data">实体对象</param>
|
||||||
<param name="propertyName">属性名</param>
|
<param name="propertyName">属性名</param>
|
||||||
@ -65,9 +69,9 @@
|
|||||||
</member>
|
</member>
|
||||||
<member name="P:FreeSql.DbContextOptions.EnableAddOrUpdateNavigateList">
|
<member name="P:FreeSql.DbContextOptions.EnableAddOrUpdateNavigateList">
|
||||||
<summary>
|
<summary>
|
||||||
是否开启一对多,多对多联级保存功能<para></para>
|
是否开启一对多,多对多级联保存功能<para></para>
|
||||||
<para></para>
|
<para></para>
|
||||||
【一对多】模型下, 保存时可联级保存实体的属性集合。出于使用安全考虑我们没做完整对比,只实现实体属性集合的添加或更新操作,所以不会删除实体属性集合的数据。<para></para>
|
【一对多】模型下, 保存时可级联保存实体的属性集合。出于使用安全考虑我们没做完整对比,只实现实体属性集合的添加或更新操作,所以不会删除实体属性集合的数据。<para></para>
|
||||||
完整对比的功能使用起来太危险,试想下面的场景:<para></para>
|
完整对比的功能使用起来太危险,试想下面的场景:<para></para>
|
||||||
- 保存的时候,实体的属性集合是空的,如何操作?记录全部删除?<para></para>
|
- 保存的时候,实体的属性集合是空的,如何操作?记录全部删除?<para></para>
|
||||||
- 保存的时候,由于数据库中记录非常之多,那么只想保存子表的部分数据,或者只需要添加,如何操作?<para></para>
|
- 保存的时候,由于数据库中记录非常之多,那么只想保存子表的部分数据,或者只需要添加,如何操作?<para></para>
|
||||||
@ -106,34 +110,23 @@
|
|||||||
清空状态数据
|
清空状态数据
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:FreeSql.DbSet`1.RemoveAsync(System.Linq.Expressions.Expression{System.Func{`0,System.Boolean}})">
|
|
||||||
<summary>
|
|
||||||
根据 lambda 条件删除数据
|
|
||||||
</summary>
|
|
||||||
<param name="predicate"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.DbSet`1.Add(`0)">
|
<member name="M:FreeSql.DbSet`1.Add(`0)">
|
||||||
<summary>
|
<summary>
|
||||||
添加
|
添加
|
||||||
</summary>
|
</summary>
|
||||||
<param name="data"></param>
|
<param name="data"></param>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:FreeSql.DbSet`1.SaveManyToMany(`0,System.String)">
|
<member name="M:FreeSql.DbSet`1.SaveMany(`0,System.String)">
|
||||||
<summary>
|
<summary>
|
||||||
保存实体的指定 ManyToMany 导航属性
|
保存实体的指定 ManyToMany/OneToMany 导航属性(完整对比)<para></para>
|
||||||
|
场景:在关闭级联保存功能之后,手工使用本方法<para></para>
|
||||||
|
例子:保存商品的 OneToMany 集合属性,SaveMany(goods, "Skus")<para></para>
|
||||||
|
当 goods.Skus 为空(非null)时,会删除表中已存在的所有数据<para></para>
|
||||||
|
当 goods.Skus 不为空(非null)时,添加/更新后,删除表中不存在 Skus 集合属性的所有记录
|
||||||
</summary>
|
</summary>
|
||||||
<param name="item">实体对象</param>
|
<param name="item">实体对象</param>
|
||||||
<param name="propertyName">属性名</param>
|
<param name="propertyName">属性名</param>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:FreeSql.DbSet`1.AddOrUpdateNavigateList(`0,System.Boolean,System.String)">
|
|
||||||
<summary>
|
|
||||||
联级保存导航集合
|
|
||||||
</summary>
|
|
||||||
<param name="item">实体对象</param>
|
|
||||||
<param name="isAdd">是否为新增的实体对象</param>
|
|
||||||
<param name="propertyName">指定保存的属性</param>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.DbSet`1.Update(`0)">
|
<member name="M:FreeSql.DbSet`1.Update(`0)">
|
||||||
<summary>
|
<summary>
|
||||||
更新
|
更新
|
||||||
@ -240,9 +233,13 @@
|
|||||||
</summary>
|
</summary>
|
||||||
<param name="data"></param>
|
<param name="data"></param>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:FreeSql.IBasicRepository`1.SaveManyToMany(`0,System.String)">
|
<member name="M:FreeSql.IBasicRepository`1.SaveMany(`0,System.String)">
|
||||||
<summary>
|
<summary>
|
||||||
保存实体的指定 ManyToMany 导航属性
|
保存实体的指定 ManyToMany/OneToMany 导航属性(完整对比)<para></para>
|
||||||
|
场景:在关闭级联保存功能之后,手工使用本方法<para></para>
|
||||||
|
例子:保存商品的 OneToMany 集合属性,SaveMany(goods, "Skus")<para></para>
|
||||||
|
当 goods.Skus 为空(非null)时,会删除表中已存在的所有数据<para></para>
|
||||||
|
当 goods.Skus 不为空(非null)时,添加/更新后,删除表中不存在 Skus 集合属性的所有记录
|
||||||
</summary>
|
</summary>
|
||||||
<param name="entity">实体对象</param>
|
<param name="entity">实体对象</param>
|
||||||
<param name="propertyName">属性名</param>
|
<param name="propertyName">属性名</param>
|
||||||
|
@ -130,9 +130,9 @@ namespace FreeSql
|
|||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SaveManyToMany(TEntity entity, string propertyName)
|
public void SaveMany(TEntity entity, string propertyName)
|
||||||
{
|
{
|
||||||
_dbset.SaveManyToMany(entity, propertyName);
|
_dbset.SaveMany(entity, propertyName);
|
||||||
_db.SaveChanges();
|
_db.SaveChanges();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,9 +64,9 @@ namespace FreeSql
|
|||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
async public Task SaveManyToManyAsync(TEntity entity, string propertyName)
|
async public Task SaveManyAsync(TEntity entity, string propertyName)
|
||||||
{
|
{
|
||||||
await _dbset.SaveManyToManyAsync(entity, propertyName);
|
await _dbset.SaveManyAsync(entity, propertyName);
|
||||||
await _db.SaveChangesAsync();
|
await _db.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,11 +30,15 @@ namespace FreeSql
|
|||||||
|
|
||||||
TEntity InsertOrUpdate(TEntity entity);
|
TEntity InsertOrUpdate(TEntity entity);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 保存实体的指定 ManyToMany 导航属性
|
/// 保存实体的指定 ManyToMany/OneToMany 导航属性(完整对比)<para></para>
|
||||||
|
/// 场景:在关闭级联保存功能之后,手工使用本方法<para></para>
|
||||||
|
/// 例子:保存商品的 OneToMany 集合属性,SaveMany(goods, "Skus")<para></para>
|
||||||
|
/// 当 goods.Skus 为空(非null)时,会删除表中已存在的所有数据<para></para>
|
||||||
|
/// 当 goods.Skus 不为空(非null)时,添加/更新后,删除表中不存在 Skus 集合属性的所有记录
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="entity">实体对象</param>
|
/// <param name="entity">实体对象</param>
|
||||||
/// <param name="propertyName">属性名</param>
|
/// <param name="propertyName">属性名</param>
|
||||||
void SaveManyToMany(TEntity entity, string propertyName);
|
void SaveMany(TEntity entity, string propertyName);
|
||||||
|
|
||||||
IUpdate<TEntity> UpdateDiy { get; }
|
IUpdate<TEntity> UpdateDiy { get; }
|
||||||
|
|
||||||
@ -49,7 +53,7 @@ namespace FreeSql
|
|||||||
Task<int> UpdateAsync(TEntity entity);
|
Task<int> UpdateAsync(TEntity entity);
|
||||||
Task<int> UpdateAsync(IEnumerable<TEntity> entitys);
|
Task<int> UpdateAsync(IEnumerable<TEntity> entitys);
|
||||||
Task<TEntity> InsertOrUpdateAsync(TEntity entity);
|
Task<TEntity> InsertOrUpdateAsync(TEntity entity);
|
||||||
Task SaveManyToManyAsync(TEntity entity, string propertyName);
|
Task SaveManyAsync(TEntity entity, string propertyName);
|
||||||
|
|
||||||
Task<int> DeleteAsync(TEntity entity);
|
Task<int> DeleteAsync(TEntity entity);
|
||||||
Task<int> DeleteAsync(IEnumerable<TEntity> entitys);
|
Task<int> DeleteAsync(IEnumerable<TEntity> entitys);
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
### v0.6.5
|
### v0.6.5
|
||||||
|
|
||||||
- 修复 Repository 联级保存的 bug;
|
- 修复 Repository 级联保存的 bug;
|
||||||
- 添加工作单元开启方法;
|
- 添加工作单元开启方法;
|
||||||
- 适配 .net framework 4.5、netstandard 2.0;
|
- 适配 .net framework 4.5、netstandard 2.0;
|
||||||
|
|
||||||
@ -192,7 +192,7 @@ fsql.GetGuidRepository<User>().Select.FromRepository(logRepository)
|
|||||||
|
|
||||||
- 修复 AddOrUpdate/InsertOrUpdate 当主键无值时,仍然查询了一次数据库;
|
- 修复 AddOrUpdate/InsertOrUpdate 当主键无值时,仍然查询了一次数据库;
|
||||||
- 增加 查询数据时 TrackToList 对导航集合的状态跟踪;
|
- 增加 查询数据时 TrackToList 对导航集合的状态跟踪;
|
||||||
- 完善 AddOrUpdateNavigateList 联级保存,忽略标记 IsIgnore 的集合属性;
|
- 完善 AddOrUpdateNavigateList 级联保存,忽略标记 IsIgnore 的集合属性;
|
||||||
- 完成 IFreeSql.Include、IncludeMany 功能;
|
- 完成 IFreeSql.Include、IncludeMany 功能;
|
||||||
|
|
||||||
### v0.5.12
|
### v0.5.12
|
||||||
|
@ -361,7 +361,9 @@ namespace FreeSql.Tests
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
repo.DbContextOptions.EnableAddOrUpdateNavigateList = false; //关闭级联保存功能
|
||||||
repo.Insert(cts);
|
repo.Insert(cts);
|
||||||
|
repo.SaveMany(cts[0], "Childs"); //指定保存 Childs 一对多属性
|
||||||
cts[0].Name = "分类11";
|
cts[0].Name = "分类11";
|
||||||
cts[0].Childs.Clear();
|
cts[0].Childs.Clear();
|
||||||
cts[1].Name = "分类22";
|
cts[1].Name = "分类22";
|
||||||
@ -415,9 +417,9 @@ namespace FreeSql.Tests
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
var repo = g.sqlite.GetRepository<Song>();
|
var repo = g.sqlite.GetRepository<Song>();
|
||||||
//repo.DbContextOptions.EnableAddOrUpdateNavigateList = false; //关闭联级保存功能
|
//repo.DbContextOptions.EnableAddOrUpdateNavigateList = false; //关闭级联保存功能
|
||||||
repo.Insert(ss);
|
repo.Insert(ss);
|
||||||
repo.SaveManyToMany(ss[0], "Tags"); //指定保存 Tags 多对多属性
|
//repo.SaveMany(ss[0], "Tags"); //指定保存 Tags 多对多属性
|
||||||
|
|
||||||
ss[0].Name = "爱你一万年.mp5";
|
ss[0].Name = "爱你一万年.mp5";
|
||||||
ss[0].Tags.Clear();
|
ss[0].Tags.Clear();
|
||||||
|
@ -98,7 +98,7 @@ namespace FreeSql.Tests
|
|||||||
var sql = g.mysql.Select<testenumWhere>().Where(a => a.type == testenumWhereType.Blaaa).ToSql();
|
var sql = g.mysql.Select<testenumWhere>().Where(a => a.type == testenumWhereType.Blaaa).ToSql();
|
||||||
var tolist = g.mysql.Select<testenumWhere>().Where(a => a.type == testenumWhereType.Blaaa).ToList();
|
var tolist = g.mysql.Select<testenumWhere>().Where(a => a.type == testenumWhereType.Blaaa).ToList();
|
||||||
|
|
||||||
//支持 1对多 联级保存
|
//支持 1对多 级联保存
|
||||||
|
|
||||||
using (var ctx = new FreeContext(g.sqlite))
|
using (var ctx = new FreeContext(g.sqlite))
|
||||||
{
|
{
|
||||||
@ -127,7 +127,7 @@ namespace FreeSql.Tests
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void Update()
|
public void Update()
|
||||||
{
|
{
|
||||||
//查询 1对多,再联级保存
|
//查询 1对多,再级联保存
|
||||||
|
|
||||||
using (var ctx = new FreeContext(g.sqlite))
|
using (var ctx = new FreeContext(g.sqlite))
|
||||||
{
|
{
|
||||||
|
@ -1431,11 +1431,12 @@
|
|||||||
<param name="exp">lambda表达式</param>
|
<param name="exp">lambda表达式</param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:FreeSql.ISelect`1.WhereDynamic(System.Object)">
|
<member name="M:FreeSql.ISelect`1.WhereDynamic(System.Object,System.Boolean)">
|
||||||
<summary>
|
<summary>
|
||||||
传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1}
|
传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1}
|
||||||
</summary>
|
</summary>
|
||||||
<param name="dywhere">主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合</param>
|
<param name="dywhere">主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合</param>
|
||||||
|
<param name="not">是否标识为NOT</param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:FreeSql.ISelect`1.WhereCascade(System.Linq.Expressions.Expression{System.Func{`0,System.Boolean}})">
|
<member name="M:FreeSql.ISelect`1.WhereCascade(System.Linq.Expressions.Expression{System.Func{`0,System.Boolean}})">
|
||||||
|
@ -293,8 +293,9 @@ namespace FreeSql
|
|||||||
/// 传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1}
|
/// 传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1}
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dywhere">主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合</param>
|
/// <param name="dywhere">主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合</param>
|
||||||
|
/// <param name="not">是否标识为NOT</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
ISelect<T1> WhereDynamic(object dywhere);
|
ISelect<T1> WhereDynamic(object dywhere, bool not = false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 多表查询时,该方法标记后,表达式条件将对所有表进行附加
|
/// 多表查询时,该方法标记后,表达式条件将对所有表进行附加
|
||||||
|
@ -888,12 +888,16 @@ namespace FreeSql.Internal.CommonProvider
|
|||||||
public IDelete<T1> ToDelete()
|
public IDelete<T1> ToDelete()
|
||||||
{
|
{
|
||||||
if (_tables[0].Table.Primarys.Any() == false) throw new Exception($"ToDelete 功能要求实体类 {_tables[0].Table.CsName} 必须有主键");
|
if (_tables[0].Table.Primarys.Any() == false) throw new Exception($"ToDelete 功能要求实体类 {_tables[0].Table.CsName} 必须有主键");
|
||||||
return _orm.Delete<T1>().Where(GetToDeleteWhere("ftb_del"));
|
var del = _orm.Delete<T1>();
|
||||||
|
if (_tables[0].Table.Type != typeof(T1)) del.AsType(_tables[0].Table.Type);
|
||||||
|
return del.Where(GetToDeleteWhere("ftb_del"));
|
||||||
}
|
}
|
||||||
public IUpdate<T1> ToUpdate()
|
public IUpdate<T1> ToUpdate()
|
||||||
{
|
{
|
||||||
if (_tables[0].Table.Primarys.Any() == false) throw new Exception($"ToUpdate 功能要求实体类 {_tables[0].Table.CsName} 必须有主键");
|
if (_tables[0].Table.Primarys.Any() == false) throw new Exception($"ToUpdate 功能要求实体类 {_tables[0].Table.CsName} 必须有主键");
|
||||||
return _orm.Update<T1>().Where(GetToDeleteWhere("ftb_upd"));
|
var upd = _orm.Update<T1>();
|
||||||
|
if (_tables[0].Table.Type != typeof(T1)) upd.AsType(_tables[0].Table.Type);
|
||||||
|
return upd.Where(GetToDeleteWhere("ftb_upd"));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<Dictionary<Type, string>> GetTableRuleUnions()
|
protected List<Dictionary<Type, string>> GetTableRuleUnions()
|
||||||
|
@ -319,7 +319,9 @@ namespace FreeSql.Internal.CommonProvider
|
|||||||
_tables[0].Parameter = exp.Parameters[0];
|
_tables[0].Parameter = exp.Parameters[0];
|
||||||
return this.InternalWhere(exp?.Body);
|
return this.InternalWhere(exp?.Body);
|
||||||
}
|
}
|
||||||
public ISelect<T1> WhereDynamic(object dywhere) => this.Where(_commonUtils.WhereObject(_tables.First().Table, $"{_tables.First().Alias}.", dywhere));
|
public ISelect<T1> WhereDynamic(object dywhere, bool not = false) => not == false ?
|
||||||
|
this.Where(_commonUtils.WhereObject(_tables.First().Table, $"{_tables.First().Alias}.", dywhere)) :
|
||||||
|
this.Where($"not({_commonUtils.WhereObject(_tables.First().Table, $"{_tables.First().Alias}.", dywhere)})");
|
||||||
|
|
||||||
public ISelect<T1> WhereCascade(Expression<Func<T1, bool>> exp)
|
public ISelect<T1> WhereCascade(Expression<Func<T1, bool>> exp)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user