@@ -221,16 +221,26 @@ void AddOrUpdateNavigateList(TEntity item, bool isAdd, string propertyName)
221221
222222 var tref = _table . GetTableRef ( prop . Name , false ) ; //防止非正常的导航属性报错
223223 if ( tref == null ) return ;
224+ DbSet < object > refSet = null ;
224225 switch ( tref . RefType )
225226 {
226227 case Internal . Model . TableRefType . OneToOne :
228+ //var propValItem = GetItemValue(item, prop);
229+ //for (var colidx = 0; colidx < tref.Columns.Count; colidx++)
230+ //{
231+ // var val = FreeSql.Internal.Utils.GetDataReaderValue(tref.RefColumns[colidx].CsType, _db.OrmOriginal.GetEntityValueWithPropertyName(_table.Type, item, tref.Columns[colidx].CsName));
232+ // _db.OrmOriginal.SetEntityValueWithPropertyName(tref.RefEntityType, propValItem, tref.RefColumns[colidx].CsName, val);
233+ //}
234+ //if (isAdd) refSet.Add(propValItem);
235+ //else refSet.AddOrUpdate(propValItem);
236+ //return;
227237 case Internal . Model . TableRefType . ManyToOne :
228238 return ;
229239 }
230240
231241 var propValEach = GetItemValue ( item , prop ) as IEnumerable ;
232242 if ( propValEach == null ) return ;
233- DbSet < object > refSet = GetDbSetObject ( tref . RefEntityType ) ;
243+ refSet = GetDbSetObject ( tref . RefEntityType ) ;
234244 switch ( tref . RefType )
235245 {
236246 case Internal . Model . TableRefType . ManyToMany :
@@ -641,5 +651,163 @@ public int EndEdit(List<TEntity> data = null)
641651 return _db . _affrows - beforeAffrows ;
642652 }
643653 #endregion
654+
655+ #region RemoveCascade
656+ /// <summary>
657+ /// 根据设置的导航属性,递归查询删除 OneToOne/OneToMany/ManyToMany 数据,并返回已删除的数据
658+ /// </summary>
659+ /// <param name="data"></param>
660+ /// <returns></returns>
661+ public List < object > RemoveCascade ( TEntity data ) => RemoveRangeCascade ( new [ ] { data } ) ;
662+ public List < object > RemoveCascade ( Expression < Func < TEntity , bool > > predicate ) => RemoveRangeCascade ( Select . Where ( predicate ) . ToList ( ) ) ;
663+ public List < object > RemoveRangeCascade ( IEnumerable < TEntity > data )
664+ {
665+ var returnDeleted = new List < object > ( ) ;
666+ if ( data ? . Any ( ) != true ) return returnDeleted ;
667+ DbContextFlushCommand ( ) ;
668+ var fsql = _db . Orm ;
669+ if ( LocalGetNavigates ( _table ) . Any ( ) == false )
670+ {
671+ if ( CanRemove ( data , true ) == false ) return returnDeleted ;
672+ foreach ( var item in data ) //防止清除 Identity/Guid
673+ {
674+ var state = CreateEntityState ( item ) ;
675+ _states . TryRemove ( state . Key , out var trystate ) ;
676+
677+ EnqueueToDbContext ( DbContext . EntityChangeType . Delete , state ) ;
678+ }
679+ DbContextFlushCommand ( ) ;
680+ returnDeleted . AddRange ( data . Select ( a => ( object ) a ) ) ;
681+ return returnDeleted ;
682+ }
683+
684+ var commonUtils = ( fsql . Select < object > ( ) as Internal . CommonProvider . Select0Provider ) . _commonUtils ;
685+ var eachdic = new Dictionary < string , bool > ( ) ;
686+ var rootItems = data . Select ( a => ( object ) a ) . ToArray ( ) ;
687+ var rootDbSet = _db . Set < object > ( ) ;
688+ rootDbSet . AsType ( _table . Type ) ;
689+ rootDbSet . AttachRange ( rootItems ) ;
690+ LocalEach ( rootDbSet , rootItems , true ) ;
691+ return returnDeleted ;
692+
693+ List < NativeTuple < TableRef , PropertyInfo > > LocalGetNavigates ( TableInfo tb )
694+ {
695+ return tb . Properties . Where ( a => tb . ColumnsByCs . ContainsKey ( a . Key ) == false )
696+ . Select ( a => new NativeTuple < TableRef , PropertyInfo > ( tb . GetTableRef ( a . Key , false ) , a . Value ) )
697+ . Where ( a => a . Item1 != null && a . Item1 . RefType != TableRefType . ManyToOne )
698+ . ToList ( ) ;
699+ }
700+ void LocalEach ( DbSet < object > dbset , IEnumerable < object > items , bool isOneToOne )
701+ {
702+ items = items ? . Where ( item =>
703+ {
704+ var itemkeyStr = FreeSql . Extensions . EntityUtil . EntityUtilExtensions . GetEntityKeyString ( fsql , dbset . EntityType , item , false ) ;
705+ var eachdicKey = $ "{ dbset . EntityType . FullName } ,{ itemkeyStr } ";
706+ if ( eachdic . ContainsKey ( eachdicKey ) ) return false ;
707+ eachdic . Add ( eachdicKey , true ) ;
708+ return true ;
709+ } ) . ToList ( ) ;
710+ if ( items ? . Any ( ) != true ) return ;
711+
712+ var tb = fsql . CodeFirst . GetTableByEntity ( dbset . EntityType ) ;
713+ var navs = LocalGetNavigates ( tb ) ;
714+
715+ var otos = navs . Where ( a => a . Item1 . RefType == TableRefType . OneToOne ) . ToList ( ) ;
716+ if ( isOneToOne && otos . Any ( ) )
717+ {
718+ foreach ( var oto in otos )
719+ {
720+ var childTable = fsql . CodeFirst . GetTableByEntity ( oto . Item1 . RefEntityType ) ;
721+ var childDbSet = _db . Set < object > ( ) ;
722+ childDbSet . AsType ( oto . Item1 . RefEntityType ) ;
723+ var refitems = items . Select ( item =>
724+ {
725+ var refitem = oto . Item1 . RefEntityType . CreateInstanceGetDefaultValue ( ) ;
726+ for ( var a = 0 ; a < oto . Item1 . Columns . Count ; a ++ )
727+ {
728+ var colval = FreeSql . Extensions . EntityUtil . EntityUtilExtensions . GetPropertyValue ( tb , item , oto . Item1 . Columns [ a ] . CsName ) ;
729+ FreeSql . Extensions . EntityUtil . EntityUtilExtensions . SetPropertyValue ( childTable , refitem , oto . Item1 . RefColumns [ a ] . CsName , colval ) ;
730+ }
731+ return refitem ;
732+ } ) . ToList ( ) ;
733+ var childs = childDbSet . Select . Where ( commonUtils . WhereItems ( oto . Item1 . RefColumns . ToArray ( ) , "a." , refitems ) ) . ToList ( ) ;
734+ LocalEach ( childDbSet , childs , false ) ;
735+ }
736+ }
737+
738+ var otms = navs . Where ( a => a . Item1 . RefType == TableRefType . OneToMany ) . ToList ( ) ;
739+ if ( otms . Any ( ) )
740+ {
741+ foreach ( var otm in otms )
742+ {
743+ var childTable = fsql . CodeFirst . GetTableByEntity ( otm . Item1 . RefEntityType ) ;
744+ var childDbSet = _db . Set < object > ( ) ;
745+ childDbSet . AsType ( otm . Item1 . RefEntityType ) ;
746+ var refitems = items . Select ( item =>
747+ {
748+ var refitem = otm . Item1 . RefEntityType . CreateInstanceGetDefaultValue ( ) ;
749+ for ( var a = 0 ; a < otm . Item1 . Columns . Count ; a ++ )
750+ {
751+ var colval = FreeSql . Extensions . EntityUtil . EntityUtilExtensions . GetPropertyValue ( tb , item , otm . Item1 . Columns [ a ] . CsName ) ;
752+ FreeSql . Extensions . EntityUtil . EntityUtilExtensions . SetPropertyValue ( childTable , refitem , otm . Item1 . RefColumns [ a ] . CsName , colval ) ;
753+ }
754+ return refitem ;
755+ } ) . ToList ( ) ;
756+ var childs = childDbSet . Select . Where ( commonUtils . WhereItems ( otm . Item1 . RefColumns . ToArray ( ) , "a." , refitems ) ) . ToList ( ) ;
757+ LocalEach ( childDbSet , childs , true ) ;
758+ }
759+ }
760+
761+ var mtms = navs . Where ( a => a . Item1 . RefType == TableRefType . ManyToMany ) . ToList ( ) ;
762+ if ( mtms . Any ( ) )
763+ {
764+ foreach ( var mtm in mtms )
765+ {
766+ var childTable = fsql . CodeFirst . GetTableByEntity ( mtm . Item1 . RefMiddleEntityType ) ;
767+ var childDbSet = _db . Set < object > ( ) ;
768+ childDbSet . AsType ( mtm . Item1 . RefMiddleEntityType ) ;
769+ var miditems = items . Select ( item =>
770+ {
771+ var refitem = mtm . Item1 . RefMiddleEntityType . CreateInstanceGetDefaultValue ( ) ;
772+ for ( var a = 0 ; a < mtm . Item1 . Columns . Count ; a ++ )
773+ {
774+ var colval = FreeSql . Extensions . EntityUtil . EntityUtilExtensions . GetPropertyValue ( tb , item , mtm . Item1 . Columns [ a ] . CsName ) ;
775+ FreeSql . Extensions . EntityUtil . EntityUtilExtensions . SetPropertyValue ( childTable , refitem , mtm . Item1 . MiddleColumns [ a ] . CsName , colval ) ;
776+ }
777+ return refitem ;
778+ } ) . ToList ( ) ;
779+ var childs = childDbSet . Select . Where ( commonUtils . WhereItems ( mtm . Item1 . MiddleColumns . Take ( mtm . Item1 . Columns . Count ) . ToArray ( ) , "a." , miditems ) ) . ToList ( ) ;
780+ LocalEach ( childDbSet , childs , true ) ;
781+ }
782+ }
783+
784+ if ( dbset == rootDbSet )
785+ {
786+ if ( CanRemove ( data , true ) == false ) return ;
787+ foreach ( var item in data ) //防止清除 Identity/Guid
788+ {
789+ var state = CreateEntityState ( item ) ;
790+ _states . TryRemove ( state . Key , out var trystate ) ;
791+
792+ EnqueueToDbContext ( DbContext . EntityChangeType . Delete , state ) ;
793+ }
794+ DbContextFlushCommand ( ) ;
795+ }
796+ else
797+ {
798+ if ( dbset . CanRemove ( items , true ) == false ) return ;
799+ foreach ( var item in items ) //防止清除 Identity/Guid
800+ {
801+ var state = dbset . CreateEntityState ( item ) ;
802+ dbset . _states . TryRemove ( state . Key , out var trystate ) ;
803+
804+ dbset . EnqueueToDbContext ( DbContext . EntityChangeType . Delete , state ) ;
805+ }
806+ dbset . DbContextFlushCommand ( ) ;
807+ }
808+ returnDeleted . AddRange ( items ) ;
809+ }
810+ }
811+ #endregion
644812 }
645813}
0 commit comments