- 增加 DbContext、Repository SaveManyToMany 方法,实现手工保存 ManyToMany 关联数据;

This commit is contained in:
28810 2019-11-16 01:47:04 +08:00
parent 0f7dd75e64
commit e26dbfe526
8 changed files with 129 additions and 39 deletions

View File

@ -136,6 +136,13 @@ namespace FreeSql
/// <param name="data"></param>
public void AddOrUpdate<TEntity>(TEntity data) where TEntity : class => this.Set<TEntity>().AddOrUpdate(data);
/// <summary>
/// 保存实体的指定 ManyToMany 导航属性
/// </summary>
/// <param name="data">实体对象</param>
/// <param name="propertyName">属性名</param>
public void SaveManyToMany<TEntity>(TEntity data, string propertyName) where TEntity : class => this.Set<TEntity>().SaveManyToMany(data, propertyName);
/// <summary>
/// 附加实体,可用于不查询就更新或删除
/// </summary>
@ -163,6 +170,7 @@ namespace FreeSql
public Task UpdateRangeAsync<TEntity>(IEnumerable<TEntity> data) where TEntity : class => this.Set<TEntity>().UpdateRangeAsync(data);
public Task AddOrUpdateAsync<TEntity>(TEntity data) where TEntity : class => this.Set<TEntity>().AddOrUpdateAsync(data);
public Task SaveManyToManyAsync<TEntity>(TEntity data, string propertyName) where TEntity : class => this.Set<TEntity>().SaveManyToManyAsync(data, propertyName);
#endif
#endregion

View File

@ -132,44 +132,58 @@ namespace FreeSql
await AddOrUpdateNavigateListAsync(item, true);
}
}
async Task AddOrUpdateNavigateListAsync(TEntity item, bool isAdd)
async public Task SaveManyToManyAsync(TEntity item, string propertyName)
{
if (item == null) return;
if (_table.Properties.ContainsKey(propertyName) == false) throw new KeyNotFoundException($"{_table.Type.FullName} 不存在属性 {propertyName}");
if (_table.ColumnsByCsIgnore.ContainsKey(propertyName)) throw new ArgumentException($"{_table.Type.FullName} 类型已设置属性 {propertyName} 忽略特性");
var tref = _table.GetTableRef(propertyName, true);
if (tref.RefType != Internal.Model.TableRefType.ManyToMany) throw new ArgumentException($"{_table.Type.FullName} 类型的属性 {propertyName} 不是 ManyToMany 特性");
DbContextExecCommand();
var oldEnable = _db.Options.EnableAddOrUpdateNavigateList;
_db.Options.EnableAddOrUpdateNavigateList = false;
await AddOrUpdateNavigateListAsync(item, false, propertyName);
_db.Options.EnableAddOrUpdateNavigateList = oldEnable;
}
async Task AddOrUpdateNavigateListAsync(TEntity item, bool isAdd, string propertyName = null)
{
Type itemType = null;
foreach (var prop in _table.Properties)
Func<PropertyInfo, Task> action = async prop =>
{
if (_table.ColumnsByCsIgnore.ContainsKey(prop.Key)) continue;
if (_table.ColumnsByCs.ContainsKey(prop.Key)) continue;
if (_table.ColumnsByCsIgnore.ContainsKey(prop.Name)) return;
if (_table.ColumnsByCs.ContainsKey(prop.Name)) return;
var tref = _table.GetTableRef(prop.Key, true);
if (tref == null) continue;
var tref = _table.GetTableRef(prop.Name, true);
if (tref == null) return;
switch (tref.RefType)
{
case Internal.Model.TableRefType.OneToOne:
case Internal.Model.TableRefType.ManyToOne:
continue;
return;
}
object propVal = null;
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.Key, propName =>
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) continue;
if (lazyFieldValue == false) return;
}
propVal = prop.Value.GetValue(item);
propVal = prop.GetValue(item);
}
else
{
propVal = prop.Value.GetValue(item);
if (propVal == null) continue;
propVal = prop.GetValue(item);
if (propVal == null) return;
}
var propValEach = propVal as IEnumerable;
if (propValEach == null) continue;
if (propValEach == null) return;
DbSet<object> refSet = GetDbSetObject(tref.RefEntityType);
switch (tref.RefType)
{
@ -276,7 +290,13 @@ namespace FreeSql
}
break;
}
}
};
if (string.IsNullOrEmpty(propertyName))
foreach (var prop in _table.Properties)
await action(prop.Value);
else if (_table.Properties.TryGetValue(propertyName, out var prop))
await action(prop);
}
#endregion

View File

@ -135,50 +135,70 @@ namespace FreeSql
AddOrUpdateNavigateList(item, true);
}
}
static ConcurrentDictionary<Type, ConcurrentDictionary<string, FieldInfo>> _dicLazyIsSetField = new ConcurrentDictionary<Type, ConcurrentDictionary<string, FieldInfo>>();
/// <summary>
/// 保存实体的指定 ManyToMany 导航属性
/// </summary>
/// <param name="item">实体对象</param>
/// <param name="propertyName">属性名</param>
public void SaveManyToMany(TEntity item, string propertyName)
{
if (item == null) return;
if (_table.Properties.ContainsKey(propertyName) == false) throw new KeyNotFoundException($"{_table.Type.FullName} 不存在属性 {propertyName}");
if (_table.ColumnsByCsIgnore.ContainsKey(propertyName)) throw new ArgumentException($"{_table.Type.FullName} 类型已设置属性 {propertyName} 忽略特性");
var tref = _table.GetTableRef(propertyName, true);
if (tref.RefType != Internal.Model.TableRefType.ManyToMany) throw new ArgumentException($"{_table.Type.FullName} 类型的属性 {propertyName} 不是 ManyToMany 特性");
DbContextExecCommand();
var oldEnable = _db.Options.EnableAddOrUpdateNavigateList;
_db.Options.EnableAddOrUpdateNavigateList = false;
AddOrUpdateNavigateList(item, false, propertyName);
_db.Options.EnableAddOrUpdateNavigateList = oldEnable;
}
/// <summary>
/// 联级保存导航集合
/// </summary>
/// <param name="item">实体对象</param>
/// <param name="isAdd">是否为新增的实体对象</param>
void AddOrUpdateNavigateList(TEntity item, bool isAdd)
/// <param name="propertyName">指定保存的属性</param>
void AddOrUpdateNavigateList(TEntity item, bool isAdd, string propertyName = null)
{
Type itemType = null;
foreach (var prop in _table.Properties)
Action<PropertyInfo> action = prop =>
{
if (_table.ColumnsByCsIgnore.ContainsKey(prop.Key)) continue;
if (_table.ColumnsByCs.ContainsKey(prop.Key)) continue;
if (_table.ColumnsByCsIgnore.ContainsKey(prop.Name)) return;
if (_table.ColumnsByCs.ContainsKey(prop.Name)) return;
var tref = _table.GetTableRef(prop.Key, true);
if (tref == null) continue;
var tref = _table.GetTableRef(prop.Name, true);
if (tref == null) return;
switch (tref.RefType)
{
case Internal.Model.TableRefType.OneToOne:
case Internal.Model.TableRefType.ManyToOne:
continue;
return;
}
object propVal = null;
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.Key, propName =>
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) continue;
if (lazyFieldValue == false) return;
}
propVal = prop.Value.GetValue(item, null);
propVal = prop.GetValue(item, null);
}
else
{
propVal = prop.Value.GetValue(item, null);
if (propVal == null) continue;
propVal = prop.GetValue(item, null);
if (propVal == null) return;
}
var propValEach = propVal as IEnumerable;
if (propValEach == null) continue;
if (propValEach == null) return;
DbSet<object> refSet = GetDbSetObject(tref.RefEntityType);
switch (tref.RefType)
{
@ -285,7 +305,13 @@ namespace FreeSql
}
break;
}
}
};
if (string.IsNullOrEmpty(propertyName))
foreach (var prop in _table.Properties)
action(prop.Value);
else if (_table.Properties.TryGetValue(propertyName, out var prop))
action(prop);
}
#endregion

View File

@ -32,6 +32,13 @@
<typeparam name="TEntity"></typeparam>
<param name="data"></param>
</member>
<member name="M:FreeSql.DbContext.SaveManyToMany``1(``0,System.String)">
<summary>
保存实体的指定 ManyToMany 导航属性
</summary>
<param name="data">实体对象</param>
<param name="propertyName">属性名</param>
</member>
<member name="M:FreeSql.DbContext.Attach``1(``0)">
<summary>
附加实体,可用于不查询就更新或删除
@ -99,25 +106,26 @@
清空状态数据
</summary>
</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)">
<summary>
添加
</summary>
<param name="data"></param>
</member>
<member name="M:FreeSql.DbSet`1.AddOrUpdateNavigateList(`0,System.Boolean)">
<member name="M:FreeSql.DbSet`1.SaveManyToMany(`0,System.String)">
<summary>
保存实体的指定 ManyToMany 导航属性
</summary>
<param name="item">实体对象</param>
<param name="propertyName">属性名</param>
</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)">
<summary>
@ -225,6 +233,13 @@
</summary>
<param name="data"></param>
</member>
<member name="M:FreeSql.IBasicRepository`1.SaveManyToMany(`0,System.String)">
<summary>
保存实体的指定 ManyToMany 导航属性
</summary>
<param name="entity">实体对象</param>
<param name="propertyName">属性名</param>
</member>
<member name="P:FreeSql.IUnitOfWork.Enable">
<summary>
是否启用工作单元

View File

@ -129,6 +129,12 @@ namespace FreeSql
_db.SaveChanges();
return entity;
}
public void SaveManyToMany(TEntity entity, string propertyName)
{
_dbset.SaveManyToMany(entity, propertyName);
_db.SaveChanges();
}
}
public abstract partial class BaseRepository<TEntity, TKey> : BaseRepository<TEntity>, IBaseRepository<TEntity, TKey>

View File

@ -36,7 +36,7 @@ namespace FreeSql
async public virtual Task<TEntity> InsertAsync(TEntity entity)
{
await _dbset.AddAsync(entity);
_db.SaveChanges();
await _db.SaveChangesAsync();
return entity;
}
async public virtual Task<List<TEntity>> InsertAsync(IEnumerable<TEntity> entitys)
@ -60,9 +60,15 @@ namespace FreeSql
async public Task<TEntity> InsertOrUpdateAsync(TEntity entity)
{
await _dbset.AddOrUpdateAsync(entity);
_db.SaveChanges();
await _db.SaveChangesAsync();
return entity;
}
async public Task SaveManyToManyAsync(TEntity entity, string propertyName)
{
await _dbset.SaveManyToManyAsync(entity, propertyName);
await _db.SaveChangesAsync();
}
}
partial class BaseRepository<TEntity, TKey>

View File

@ -29,6 +29,12 @@ namespace FreeSql
int Update(IEnumerable<TEntity> entitys);
TEntity InsertOrUpdate(TEntity entity);
/// <summary>
/// 保存实体的指定 ManyToMany 导航属性
/// </summary>
/// <param name="entity">实体对象</param>
/// <param name="propertyName">属性名</param>
void SaveManyToMany(TEntity entity, string propertyName);
IUpdate<TEntity> UpdateDiy { get; }
@ -43,6 +49,7 @@ namespace FreeSql
Task<int> UpdateAsync(TEntity entity);
Task<int> UpdateAsync(IEnumerable<TEntity> entitys);
Task<TEntity> InsertOrUpdateAsync(TEntity entity);
Task SaveManyToManyAsync(TEntity entity, string propertyName);
Task<int> DeleteAsync(TEntity entity);
Task<int> DeleteAsync(IEnumerable<TEntity> entitys);

View File

@ -415,7 +415,9 @@ namespace FreeSql.Tests
}
};
var repo = g.sqlite.GetRepository<Song>();
//repo.DbContextOptions.EnableAddOrUpdateNavigateList = false; //关闭联级保存功能
repo.Insert(ss);
repo.SaveManyToMany(ss[0], "Tags"); //指定保存 Tags 多对多属性
ss[0].Name = "爱你一万年.mp5";
ss[0].Tags.Clear();