Skip to content

Commit ffe5f5f

Browse files
committed
- 增加 DbSet/Repository DeleteCascadeAsync 异步方法;
1 parent 5a27afe commit ffe5f5f

File tree

4 files changed

+167
-0
lines changed

4 files changed

+167
-0
lines changed

FreeSql.DbContext/DbSet/DbSetAsync.cs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using FreeSql.Extensions.EntityUtil;
2+
using FreeSql.Internal.Model;
23
using System;
34
using System.Collections;
45
using System.Collections.Concurrent;
@@ -493,6 +494,159 @@ async public Task AddOrUpdateAsync(TEntity data, CancellationToken cancellationT
493494
}
494495
}
495496
#endregion
497+
498+
#region RemoveCascadeAsync
499+
public Task<List<object>> RemoveCascadeAsync(TEntity data, CancellationToken cancellationToken = default) => RemoveRangeCascadeAsync(new[] { data }, cancellationToken);
500+
public Task<List<object>> RemoveCascadeAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default) => RemoveRangeCascadeAsync(Select.Where(predicate).ToList(), cancellationToken);
501+
async public Task<List<object>> RemoveRangeCascadeAsync(IEnumerable<TEntity> data, CancellationToken cancellationToken = default)
502+
{
503+
var returnDeleted = new List<object>();
504+
if (data?.Any() != true) return returnDeleted;
505+
await DbContextFlushCommandAsync(cancellationToken);
506+
var fsql = _db.Orm;
507+
if (LocalGetNavigates(_table).Any() == false)
508+
{
509+
if (CanRemove(data, true) == false) return returnDeleted;
510+
foreach (var item in data) //防止清除 Identity/Guid
511+
{
512+
var state = CreateEntityState(item);
513+
_states.TryRemove(state.Key, out var trystate);
514+
515+
EnqueueToDbContext(DbContext.EntityChangeType.Delete, state);
516+
}
517+
await DbContextFlushCommandAsync(cancellationToken);
518+
returnDeleted.AddRange(data.Select(a => (object)a));
519+
return returnDeleted;
520+
}
521+
522+
var commonUtils = (fsql.Select<object>() as Internal.CommonProvider.Select0Provider)._commonUtils;
523+
var eachdic = new Dictionary<string, bool>();
524+
var rootItems = data.Select(a => (object)a).ToArray();
525+
var rootDbSet = _db.Set<object>();
526+
rootDbSet.AsType(_table.Type);
527+
rootDbSet.AttachRange(rootItems);
528+
await LocalEachAsync(rootDbSet, rootItems, true);
529+
return returnDeleted;
530+
531+
List<NativeTuple<TableRef, PropertyInfo>> LocalGetNavigates(TableInfo tb)
532+
{
533+
return tb.Properties.Where(a => tb.ColumnsByCs.ContainsKey(a.Key) == false)
534+
.Select(a => new NativeTuple<TableRef, PropertyInfo>(tb.GetTableRef(a.Key, false), a.Value))
535+
.Where(a => a.Item1 != null && a.Item1.RefType != TableRefType.ManyToOne)
536+
.ToList();
537+
}
538+
async Task LocalEachAsync(DbSet<object> dbset, IEnumerable<object> items, bool isOneToOne)
539+
{
540+
items = items?.Where(item =>
541+
{
542+
var itemkeyStr = FreeSql.Extensions.EntityUtil.EntityUtilExtensions.GetEntityKeyString(fsql, dbset.EntityType, item, false);
543+
var eachdicKey = $"{dbset.EntityType.FullName},{itemkeyStr}";
544+
if (eachdic.ContainsKey(eachdicKey)) return false;
545+
eachdic.Add(eachdicKey, true);
546+
return true;
547+
}).ToList();
548+
if (items?.Any() != true) return;
549+
550+
var tb = fsql.CodeFirst.GetTableByEntity(dbset.EntityType);
551+
var navs = LocalGetNavigates(tb);
552+
553+
var otos = navs.Where(a => a.Item1.RefType == TableRefType.OneToOne).ToList();
554+
if (isOneToOne && otos.Any())
555+
{
556+
foreach (var oto in otos)
557+
{
558+
var childTable = fsql.CodeFirst.GetTableByEntity(oto.Item1.RefEntityType);
559+
var childDbSet = _db.Set<object>();
560+
childDbSet.AsType(oto.Item1.RefEntityType);
561+
var refitems = items.Select(item =>
562+
{
563+
var refitem = oto.Item1.RefEntityType.CreateInstanceGetDefaultValue();
564+
for (var a = 0; a < oto.Item1.Columns.Count; a++)
565+
{
566+
var colval = FreeSql.Extensions.EntityUtil.EntityUtilExtensions.GetPropertyValue(tb, item, oto.Item1.Columns[a].CsName);
567+
FreeSql.Extensions.EntityUtil.EntityUtilExtensions.SetPropertyValue(childTable, refitem, oto.Item1.RefColumns[a].CsName, colval);
568+
}
569+
return refitem;
570+
}).ToList();
571+
var childs = await childDbSet.Select.Where(commonUtils.WhereItems(oto.Item1.RefColumns.ToArray(), "a.", refitems)).ToListAsync(false, cancellationToken);
572+
await LocalEachAsync(childDbSet, childs, false);
573+
}
574+
}
575+
576+
var otms = navs.Where(a => a.Item1.RefType == TableRefType.OneToMany).ToList();
577+
if (otms.Any())
578+
{
579+
foreach (var otm in otms)
580+
{
581+
var childTable = fsql.CodeFirst.GetTableByEntity(otm.Item1.RefEntityType);
582+
var childDbSet = _db.Set<object>();
583+
childDbSet.AsType(otm.Item1.RefEntityType);
584+
var refitems = items.Select(item =>
585+
{
586+
var refitem = otm.Item1.RefEntityType.CreateInstanceGetDefaultValue();
587+
for (var a = 0; a < otm.Item1.Columns.Count; a++)
588+
{
589+
var colval = FreeSql.Extensions.EntityUtil.EntityUtilExtensions.GetPropertyValue(tb, item, otm.Item1.Columns[a].CsName);
590+
FreeSql.Extensions.EntityUtil.EntityUtilExtensions.SetPropertyValue(childTable, refitem, otm.Item1.RefColumns[a].CsName, colval);
591+
}
592+
return refitem;
593+
}).ToList();
594+
var childs = await childDbSet.Select.Where(commonUtils.WhereItems(otm.Item1.RefColumns.ToArray(), "a.", refitems)).ToListAsync(false, cancellationToken);
595+
await LocalEachAsync(childDbSet, childs, true);
596+
}
597+
}
598+
599+
var mtms = navs.Where(a => a.Item1.RefType == TableRefType.ManyToMany).ToList();
600+
if (mtms.Any())
601+
{
602+
foreach (var mtm in mtms)
603+
{
604+
var childTable = fsql.CodeFirst.GetTableByEntity(mtm.Item1.RefMiddleEntityType);
605+
var childDbSet = _db.Set<object>();
606+
childDbSet.AsType(mtm.Item1.RefMiddleEntityType);
607+
var miditems = items.Select(item =>
608+
{
609+
var refitem = mtm.Item1.RefMiddleEntityType.CreateInstanceGetDefaultValue();
610+
for (var a = 0; a < mtm.Item1.Columns.Count; a++)
611+
{
612+
var colval = FreeSql.Extensions.EntityUtil.EntityUtilExtensions.GetPropertyValue(tb, item, mtm.Item1.Columns[a].CsName);
613+
FreeSql.Extensions.EntityUtil.EntityUtilExtensions.SetPropertyValue(childTable, refitem, mtm.Item1.MiddleColumns[a].CsName, colval);
614+
}
615+
return refitem;
616+
}).ToList();
617+
var childs = await childDbSet.Select.Where(commonUtils.WhereItems(mtm.Item1.MiddleColumns.Take(mtm.Item1.Columns.Count).ToArray(), "a.", miditems)).ToListAsync(false, cancellationToken);
618+
await LocalEachAsync(childDbSet, childs, true);
619+
}
620+
}
621+
622+
if (dbset == rootDbSet)
623+
{
624+
if (CanRemove(data, true) == false) return;
625+
foreach (var item in data) //防止清除 Identity/Guid
626+
{
627+
var state = CreateEntityState(item);
628+
_states.TryRemove(state.Key, out var trystate);
629+
630+
EnqueueToDbContext(DbContext.EntityChangeType.Delete, state);
631+
}
632+
await DbContextFlushCommandAsync(cancellationToken);
633+
}
634+
else
635+
{
636+
if (dbset.CanRemove(items, true) == false) return;
637+
foreach (var item in items) //防止清除 Identity/Guid
638+
{
639+
var state = dbset.CreateEntityState(item);
640+
dbset._states.TryRemove(state.Key, out var trystate);
641+
642+
dbset.EnqueueToDbContext(DbContext.EntityChangeType.Delete, state);
643+
}
644+
await DbContextFlushCommandAsync(cancellationToken);
645+
}
646+
returnDeleted.AddRange(items);
647+
}
648+
}
649+
#endregion
496650
}
497651
}
498652
#endif

FreeSql.DbContext/FreeSql.DbContext.xml

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

FreeSql.DbContext/Repository/Repository/BaseRepositoryAsync.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ public virtual Task<int> DeleteAsync(IEnumerable<TEntity> entitys, CancellationT
3232
_dbset.RemoveRange(entitys);
3333
return _db.SaveChangesAsync(cancellationToken);
3434
}
35+
public virtual Task<List<object>> DeleteCascade(TEntity entity, CancellationToken cancellationToken = default) => _dbset.RemoveCascadeAsync(entity, cancellationToken);
36+
public virtual Task<List<object>> DeleteCascade(IEnumerable<TEntity> entitys, CancellationToken cancellationToken = default) => _dbset.RemoveRangeCascadeAsync(entitys, cancellationToken);
37+
public virtual Task<List<object>> DeleteCascade(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default) => _dbset.RemoveCascadeAsync(predicate, cancellationToken);
3538

3639
async public virtual Task<TEntity> InsertAsync(TEntity entity, CancellationToken cancellationToken = default)
3740
{
@@ -73,6 +76,7 @@ async public Task SaveManyAsync(TEntity entity, string propertyName, Cancellatio
7376

7477
partial class BaseRepository<TEntity, TKey>
7578
{
79+
public virtual Task<List<object>> DeleteCascadeAsync(TKey id, CancellationToken cancellationToken = default) => _dbset.RemoveCascadeAsync(Find(id), cancellationToken);
7680
public virtual Task<int> DeleteAsync(TKey id, CancellationToken cancellationToken = default) => DeleteAsync(CheckTKeyAndReturnIdEntity(id), cancellationToken);
7781
public virtual Task<TEntity> FindAsync(TKey id, CancellationToken cancellationToken = default) => _dbset.OrmSelectInternal(CheckTKeyAndReturnIdEntity(id)).ToOneAsync(cancellationToken);
7882
public Task<TEntity> GetAsync(TKey id, CancellationToken cancellationToken = default) => _dbset.OrmSelectInternal(CheckTKeyAndReturnIdEntity(id)).ToOneAsync(cancellationToken);

FreeSql.DbContext/Repository/Repository/IBaseRepository.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ public interface IBaseRepository<TEntity> : IBaseRepository
124124
Task<int> DeleteAsync(TEntity entity, CancellationToken cancellationToken = default);
125125
Task<int> DeleteAsync(IEnumerable<TEntity> entitys, CancellationToken cancellationToken = default);
126126
Task<int> DeleteAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);
127+
Task<List<object>> DeleteCascade(TEntity entity, CancellationToken cancellationToken = default);
128+
Task<List<object>> DeleteCascade(IEnumerable<TEntity> entitys, CancellationToken cancellationToken = default);
129+
Task<List<object>> DeleteCascade(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);
127130
#endif
128131
}
129132

@@ -140,6 +143,7 @@ public interface IBaseRepository<TEntity, TKey> : IBaseRepository<TEntity>
140143
Task<TEntity> GetAsync(TKey id, CancellationToken cancellationToken = default);
141144
Task<TEntity> FindAsync(TKey id, CancellationToken cancellationToken = default);
142145
Task<int> DeleteAsync(TKey id, CancellationToken cancellationToken = default);
146+
Task<List<object>> DeleteCascadeAsync(TKey id, CancellationToken cancellationToken = default);
143147
#endif
144148
}
145149
}

0 commit comments

Comments
 (0)