diff --git a/FreeSql.DbContext/DbContext/DbContext.cs b/FreeSql.DbContext/DbContext/DbContext.cs index 88ef9f85..539f5183 100644 --- a/FreeSql.DbContext/DbContext/DbContext.cs +++ b/FreeSql.DbContext/DbContext/DbContext.cs @@ -136,6 +136,13 @@ namespace FreeSql /// public void AddOrUpdate(TEntity data) where TEntity : class => this.Set().AddOrUpdate(data); + /// + /// 保存实体的指定 ManyToMany 导航属性 + /// + /// 实体对象 + /// 属性名 + public void SaveManyToMany(TEntity data, string propertyName) where TEntity : class => this.Set().SaveManyToMany(data, propertyName); + /// /// 附加实体,可用于不查询就更新或删除 /// @@ -163,6 +170,7 @@ namespace FreeSql public Task UpdateRangeAsync(IEnumerable data) where TEntity : class => this.Set().UpdateRangeAsync(data); public Task AddOrUpdateAsync(TEntity data) where TEntity : class => this.Set().AddOrUpdateAsync(data); + public Task SaveManyToManyAsync(TEntity data, string propertyName) where TEntity : class => this.Set().SaveManyToManyAsync(data, propertyName); #endif #endregion diff --git a/FreeSql.DbContext/DbSet/DbSetAsync.cs b/FreeSql.DbContext/DbSet/DbSetAsync.cs index de28479d..0adf77f3 100644 --- a/FreeSql.DbContext/DbSet/DbSetAsync.cs +++ b/FreeSql.DbContext/DbSet/DbSetAsync.cs @@ -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 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()).GetOrAdd(prop.Key, propName => + var lazyField = _dicLazyIsSetField.GetOrAdd(_table.TypeLazy, tl => new ConcurrentDictionary()).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 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 diff --git a/FreeSql.DbContext/DbSet/DbSetSync.cs b/FreeSql.DbContext/DbSet/DbSetSync.cs index 52068519..5be76522 100644 --- a/FreeSql.DbContext/DbSet/DbSetSync.cs +++ b/FreeSql.DbContext/DbSet/DbSetSync.cs @@ -135,50 +135,70 @@ namespace FreeSql AddOrUpdateNavigateList(item, true); } } + static ConcurrentDictionary> _dicLazyIsSetField = new ConcurrentDictionary>(); /// + /// 保存实体的指定 ManyToMany 导航属性 + /// + /// 实体对象 + /// 属性名 + 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; + } + /// /// 联级保存导航集合 /// /// 实体对象 /// 是否为新增的实体对象 - void AddOrUpdateNavigateList(TEntity item, bool isAdd) + /// 指定保存的属性 + void AddOrUpdateNavigateList(TEntity item, bool isAdd, string propertyName = null) { Type itemType = null; - foreach (var prop in _table.Properties) + Action 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()).GetOrAdd(prop.Key, propName => + var lazyField = _dicLazyIsSetField.GetOrAdd(_table.TypeLazy, tl => new ConcurrentDictionary()).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 refSet = GetDbSetObject(tref.RefEntityType); switch (tref.RefType) { @@ -230,7 +250,7 @@ namespace FreeSql foreach (var midItem in midList) { var curContains = new List(); - for(var curIdx = 0; curIdx < curList.Count; curIdx ++) + for (var curIdx = 0; curIdx < curList.Count; curIdx++) { var isEquals = true; for (var midcolidx = tref.Columns.Count; midcolidx < tref.MiddleColumns.Count; midcolidx++) @@ -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 diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index 2711e35d..9c0597d5 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -32,6 +32,13 @@ + + + 保存实体的指定 ManyToMany 导航属性 + + 实体对象 + 属性名 + 附加实体,可用于不查询就更新或删除 @@ -99,25 +106,26 @@ 清空状态数据 - - - 根据 lambda 条件删除数据 - - - - 添加 - + + + 保存实体的指定 ManyToMany 导航属性 + + 实体对象 + 属性名 + + 联级保存导航集合 实体对象 是否为新增的实体对象 + 指定保存的属性 @@ -225,6 +233,13 @@ + + + 保存实体的指定 ManyToMany 导航属性 + + 实体对象 + 属性名 + 是否启用工作单元 diff --git a/FreeSql.DbContext/Repository/Repository/BaseRepository.cs b/FreeSql.DbContext/Repository/Repository/BaseRepository.cs index 80145899..38dd740b 100644 --- a/FreeSql.DbContext/Repository/Repository/BaseRepository.cs +++ b/FreeSql.DbContext/Repository/Repository/BaseRepository.cs @@ -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 : BaseRepository, IBaseRepository diff --git a/FreeSql.DbContext/Repository/Repository/BaseRepositoryAsync.cs b/FreeSql.DbContext/Repository/Repository/BaseRepositoryAsync.cs index 0cfcba4d..f848f89d 100644 --- a/FreeSql.DbContext/Repository/Repository/BaseRepositoryAsync.cs +++ b/FreeSql.DbContext/Repository/Repository/BaseRepositoryAsync.cs @@ -36,7 +36,7 @@ namespace FreeSql async public virtual Task InsertAsync(TEntity entity) { await _dbset.AddAsync(entity); - _db.SaveChanges(); + await _db.SaveChangesAsync(); return entity; } async public virtual Task> InsertAsync(IEnumerable entitys) @@ -60,9 +60,15 @@ namespace FreeSql async public Task 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 diff --git a/FreeSql.DbContext/Repository/Repository/IBasicRepository.cs b/FreeSql.DbContext/Repository/Repository/IBasicRepository.cs index 6c56cd5c..24f7291c 100644 --- a/FreeSql.DbContext/Repository/Repository/IBasicRepository.cs +++ b/FreeSql.DbContext/Repository/Repository/IBasicRepository.cs @@ -29,6 +29,12 @@ namespace FreeSql int Update(IEnumerable entitys); TEntity InsertOrUpdate(TEntity entity); + /// + /// 保存实体的指定 ManyToMany 导航属性 + /// + /// 实体对象 + /// 属性名 + void SaveManyToMany(TEntity entity, string propertyName); IUpdate UpdateDiy { get; } @@ -43,6 +49,7 @@ namespace FreeSql Task UpdateAsync(TEntity entity); Task UpdateAsync(IEnumerable entitys); Task InsertOrUpdateAsync(TEntity entity); + Task SaveManyToManyAsync(TEntity entity, string propertyName); Task DeleteAsync(TEntity entity); Task DeleteAsync(IEnumerable entitys); diff --git a/FreeSql.Tests/FreeSql.Tests.DbContext/RepositoryTests.cs b/FreeSql.Tests/FreeSql.Tests.DbContext/RepositoryTests.cs index c16fda68..4fa4fbe5 100644 --- a/FreeSql.Tests/FreeSql.Tests.DbContext/RepositoryTests.cs +++ b/FreeSql.Tests/FreeSql.Tests.DbContext/RepositoryTests.cs @@ -415,7 +415,9 @@ namespace FreeSql.Tests } }; var repo = g.sqlite.GetRepository(); + //repo.DbContextOptions.EnableAddOrUpdateNavigateList = false; //ر湦 repo.Insert(ss); + repo.SaveManyToMany(ss[0], "Tags"); //ָ Tags Զ ss[0].Name = "һ.mp5"; ss[0].Tags.Clear();