Cascading deletes - CascadeAllDeleteOrphan

Topics: Writing modules
Jun 6, 2011 at 4:57 PM

I have a custom table that has a 1-N relationship to the Orchard_Roles_RoleRecord. When I delete a RoleRecord, I would like the delete to cascade down to the custom table I created.  I've seen CascadeAllDeleteOrphan mentioned.  Is this an attribute? Where does it go? Do I decorate my model with it? The property on the model I want cascaded?

Jun 6, 2011 at 4:58 PM

P.S. I'm not using contentpart, it's just a straight up entity the represents a record in the back-end.

Coordinator
Jun 6, 2011 at 7:34 PM

You have to decorate the property in your class which links to Orchard_Roles_RoleRecord with it.

[CascadeAllDeleteOrphan]
public virtual IList<RolesPermissionsRecord> RolesPermissions { get; set; }

 It's in the namespace

Orchard.Data.Conventions
Jun 6, 2011 at 7:38 PM

That's what I'm doing, but it doesn't seem to want to delete when I delete the role:

public class RegistrationRecord
    {
        public virtual int Id { get; set; }

        [Display(Name="Friendly Name")]
        [Required(ErrorMessage = "Friendly name is required")]
        public virtual string FriendlyName { get; set; }

        [CascadeAllDeleteOrphan]
        public virtual RoleRecord RoleRecord { get; set; }
    }

Jun 6, 2011 at 10:57 PM

Is there more to it then just adding this attribute?  Am I correct in saying that by adding this attribute to a property in my model, when I delete a role from the admin section, the table that represents this module will have any records tied to that role deleted?  Do I have to declare anything in my migration file, maybe something specifying that it is in fact a foreign key to the Orchard_Roles_RoleRecord table?

Jun 7, 2011 at 5:52 AM

There's been some discussion on this elsewhere in these forums. As far as I know there is currently no way to delete records from a database table in Orchard, these delete attributes just remove the items from the Orchard system, but I could be wrong.

Jun 7, 2011 at 1:48 PM

I've read some of those discussions and assumed what you're saying is true.  Bertrand/Sebastion, can you guys confirm this? Are we left to making our code aware of orphaned records and to filter them out on our own?

Jun 7, 2011 at 2:19 PM

No no no - you can't delete Content Items from the database. Records can be deleted fine from other tables that aren't parts or content.

Jun 7, 2011 at 2:29 PM

randompete, do you have any feedback on the previous post I made on Monday (3 posts back)?

Jun 7, 2011 at 3:15 PM

You probably have to specify the CascadeAllDelete somehow in the Migration, but I'm not sure - haven't tried this myself.

Jun 7, 2011 at 3:17 PM

That's kind of what I thought too...I'll have to dig through some of the other modules to see how its done. I only did that a little bit yesterday...in the meantime, if anyone else has done it, I'd appreciate it. Otherwise, if I figure it out, I'll be sure to post my findings...

Jul 16, 2012 at 10:49 PM

I'm curious about how to do this as well...I decorated the property in my child model class that joins to the parent record with 

[CascadeAllDeleteOrphan]

but removing the parent Content Item doesn't remove the child Content Item.

I suppose it's not horrible to leave orphaned Content Items out there, but it would be nice to clean them up...especially since I wired up my handler to delete the part record from my table as well.

Coordinator
Jul 16, 2012 at 11:28 PM

Do it from code. The attribute won't work if there isn't a hard relationship between the tables.

Jul 17, 2012 at 12:36 AM
Edited Jul 17, 2012 at 12:44 AM

When you say "hard relationship between the tables", do you mean specifying some sort of join between the tables in the Migration?

Is there an example in Core or another module on how to do that?

Thanks!

EDIT: Found this in another post...is this what you mean?

SchemaBuilder.CreateForeignKey(
    "FK_ChildRecord__ParentRecord"
    , "ChildRecord", new string[] { "ParentRecord_Id" }
    , "ParentRecord", new string[] { "Id" }
); 

Coordinator
Jul 17, 2012 at 12:47 AM

Yes, but I don't necessarily recommend it.

Jul 17, 2012 at 7:06 PM
Edited Jul 17, 2012 at 8:50 PM

Well...the good thing is the Foreign Key Constraint works. The bad thing is, the delete method now fails with the error:

 

The primary key value cannot be deleted because references to this key still exist.

 

My guess is that it's trying to delete the ParentRecord before the ChildRecords

I'm using

 

_orchardServices.ContentManager.Remove(ParentRecord);

 

in my controller where ParentRecord is defined as

 

var ParentRecord = _orchardServices.ContentManager.Get(ParentRecordId);

 

Is there possibly a different way to remove the Content Item that triggers the deletion of all ChildRecords before attempting to remove the ParentRecord?

Thanks for any help

 

EDIT
-------

btw...my handler has an OnRemoved function that deletes the ContentPart from the Repository...this is apparently where the Foreign Key constraint was blowing up the delete. I removed this and attempted the Delete again.

It marks the VersionRecord for the Parent item as Published = false, but does NOT mark the Published property of the Child item's VersionRecord as false or do anything with the Child item whatsoever.

And of course my PartRecords are still in my table since I commented out the OnRemoved part in the Handler.

The Foreign Key Constraint only seems to come into play when attempting to delete the ContentParts from my table.

Not sure if any of that info helps

I suppose if I can just simply mark any Child items as Published = false in the VersionRecord and delete the ContentParts from my table, that would work. I could then just come up with something that deletes any ContentItems that aren't Published later on if I need to delete them.