11using FreeSql . Extensions . EntityUtil ;
2+ using FreeSql . Internal . Model ;
23using System ;
34using System . Collections ;
45using 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
0 commit comments