1

I have been working on a project and I'm trying to get the cascade delete to kick in. I have a model below I use for comments. These comments can have replies that come off of them that call the comment class. What I'm trying to do is to make it delete all the replies that can flow off the comment.

Comment -> Reply -> Reply -> Reply -> so on.

If I'm going about this in the wrong direction, please let me know. I have tried to research into this but all I come up with is One-to-One and One-Many cascade codes. I'm using CodeFirst with MVC 4 to build my project.

Edited

public class Comment
    {
        // Properties
        public long Id { get; set; }

        [Required]
        [StringLength(250, ErrorMessage = "{0} must be between {1} and {2} characters", MinimumLength = 2)]
        public string Body { get; set; }

        [Required]
        public DateTime CreateDate { get; set; }

        [Required]
        [InverseProperty("Comments")]
        public User Author { get; set; }

        [InverseProperty("CommentCount")]
        public Blog Blog { get; set; }

        public bool Hidden { get; set; }

        public long RepliesId { get; set; }

        [InverseProperty("Replies")]
        public virtual Comment Comments { get; set; }

        [InverseProperty("Comments")]
        public virtual ICollection<Comment> Replies { get; set; }

        public virtual ICollection<Vote> Votes { get; set; }

        public Comment()
        {
            CreateDate = DateTime.UtcNow;
            Hidden = false;
        }
    }

Here is my DataContextInitializer

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Comment>().HasMany(i => i.Replies)
            .WithOptional(i => i.Comments)
            .HasForeignKey(i => i.RepliesId)
            .WillCascadeOnDelete();
    }
tereško
  • 58,060
  • 25
  • 98
  • 150
Random Kid
  • 25
  • 1
  • 7

1 Answers1

2

You could enable cascade delete with something like this (i.e. you need to manually set the relationship)...

modelBuilder.Entity<Comment>()
    .HasOptional(x => x.Replies)
    .WithOptionalDependent()
    .WillCascadeOnDelete(true);

However, it won't do you much good - as Update-Database will fail with something like...

A foreign key constraint that has an UPDATE or a DELETE CASCADE rule, and self-references a column in the same table, is not allowed.

i.e. that works on FK-s that are connecting different tables - but not if self-referencing.

See this post with some more relevant info - especially the comment that mentions

"you need to drop the FK and manually create it with cascade delete in your DatabaseInitializer"

EF4 Code first - delete all children when deleting parent from db?

In short, I don't think there is a straight-forward solution - but some manual setup (initializer etc.) is required (I haven't tried it). Or try to reorganize, flatten the relationships a bit (I haven't thought much, just throwing here some pretty general approaches).


Just FYI - even though I think it's not going to get you anywhere (see above)...
public class Comment
{
    // Properties
    public long Id { get; set; }

    //[Required]
    //[StringLength(250, ErrorMessage = "{0} must be between {1} and {2} characters", MinimumLength = 2)]
    public string Body { get; set; }

    [Required]
    public DateTime CreateDate { get; set; }

    // [Required]
    // [InverseProperty("Comments")]
    public MyUser Author { get; set; }

    // [InverseProperty("CommentCount")]
    public Blog Blog { get; set; }

    public bool Hidden { get; set; }

    public virtual ICollection<Comment> Replies { get; set; }
    public virtual ICollection<Vote> Votes { get; set; }

    public Comment()
    {
        CreateDate = DateTime.UtcNow;
        Hidden = false;
    }
}

modelBuilder.Entity<Comment>()
    .HasOptional(x => x.Replies)
    .WithOptionalDependent()
    .WillCascadeOnDelete(true);

This should work fine if you let it 'not cascade'. Otherwise fails.

Community
  • 1
  • 1
NSGaga-mostly-inactive
  • 14,052
  • 3
  • 41
  • 51
  • I think I almost have it. I get a \tSystem.Data.Entity.Edm.EdmAssociationType: : Multiplicity conflicts with the referential constraint in Role 'Comment_Replies_Source' in relationship 'Comment_Replies'. Because all of the properties in the Dependent Role are non-nullable, multiplicity of the Principal Role must be '1'. error – Random Kid Apr 02 '13 at 22:05
  • I think you can remove the 'Inverse' as it should get it right w/o it (and + Required). But it's still 'futile' attempt - unless you reorganized it (I can edit in the code that works up to that error). – NSGaga-mostly-inactive Apr 02 '13 at 22:12
  • I'm still receiving the same error. I think it may be due to replies being a nullable entity. Since its an optional field it may be failing on that part. I'm not sure. – Random Kid Apr 02 '13 at 22:39
  • Ya that works along with the first answer as long as I have no Cascade Delete. What i was try to accomplish with all this is in the event i need to delete a user. It will cascade and delete all there comments and all there child comments as well. – Random Kid Apr 02 '13 at 23:43
  • well, as I told you - it's a 'no go' like that - if you'd like you can try the suggested work-around (initializer). On other side - deletes are not that often - so you can 'mark' them - and offload that for some cleanup. I know it's a pain - but I think that's as best as it gets unfortunately. – NSGaga-mostly-inactive Apr 02 '13 at 23:53
  • Ya that's what i was thinking. Might be best anyways to keep my indexing from becoming corrupted. – Random Kid Apr 03 '13 at 00:08
  • Normally, I always recommend 'no cascade deletes' - but hierarchies like this are pain. You shouldn't worry of corruption as such. There is another way to approach this maybe - you could organize this via index/join table - and 'flatten' the whole structure a bit. You can post another question w/ that (and it's good for your points:) - and just @ me here so I know. Or for that 'initializer'. Cheers Kodi. – NSGaga-mostly-inactive Apr 03 '13 at 00:21