- 增加 Repository/DbContext SaveMany 方法实现一对多,子数据的完整保存;

- 调整 SaveManyToMany 方法名为 SaveMany;
This commit is contained in:
28810 2019-11-21 16:42:20 +08:00
parent b5629b13a6
commit 04107d3d24
15 changed files with 150 additions and 109 deletions

View File

@ -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

View File

@ -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>

View File

@ -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)

View File

@ -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

View File

@ -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>

View File

@ -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();
} }
} }

View File

@ -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();
} }
} }

View File

@ -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);

View File

@ -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

View File

@ -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();

View File

@ -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))
{ {

View File

@ -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}})">

View File

@ -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>
/// 多表查询时,该方法标记后,表达式条件将对所有表进行附加 /// 多表查询时,该方法标记后,表达式条件将对所有表进行附加

View File

@ -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()

View File

@ -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)
{ {