44

When using data annotations with EF4.1 RC is there an annotation to cause cascade deletes?

public class Category
{
    public int Id { get; set; }
    [Required]
    public string Name { get; set; }
    public ICollection<Product> Products { get; set; }
}

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Category Category { get; set; }
}

Using this model the constraint generated is:

ALTER TABLE [Product] ADD CONSTRAINT [Product_Category] 
FOREIGN KEY ([Category_Id]) REFERENCES [Categorys]([Id]) 
ON DELETE NO ACTION ON UPDATE NO ACTION;

If not how is it achieved?

Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
Bender
  • 1,688
  • 2
  • 14
  • 20

4 Answers4

61

Putting required on the Product table Category relationship field solves this

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }

    [Required]  //<======= Forces Cascade delete
    public Category Category { get; set; }
}
Bender
  • 1,688
  • 2
  • 14
  • 20
51

I like to turn off cascade delete by default (by removing the OneToManyCascadeDeleteConvention)

I was then hoping to add them back in via annotations, but was surprised that EF doesn't include a CascadeDeleteAttribute.

After spending way too long working around EF's ridiculous internal accessor levels, the code in this gist adds a convention that allows attributes to be used: https://gist.github.com/tystol/20b07bd4e0043d43faff

To use, just stick the [CascadeDelete] on either end of the navigation properties for the relationship, and add the convention in your DbContext's OnModeCreating callback. eg:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
    modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
    modelBuilder.Conventions.Add<CascadeDeleteAttributeConvention>();
}  

And in your model:

public class BlogPost
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    [CascadeDelete]
    public List<BlogPostComment> Comments { get; set; } 
}
Tyson
  • 14,726
  • 6
  • 31
  • 43
  • 3
    This is better than the chosen answer because the Requiered attribute imples a not-nullable foreign key. And it works with EF 6. Thanks! – Rafael Dec 11 '15 at 18:59
  • 3
    Great solution, also, please note that the Convention class should be added to the `modelBuilder.Conventions` in `OnModelCreating` method. – Alireza Jun 26 '16 at 13:52
  • This only seems to work on [Required] relationships, so in my case I modified CascadeDeleteAttribute to inherit from RequiredAttribute for clarity – Derrick Mar 24 '18 at 00:36
3

Not sure on Data Annotations, but you can add it in the database by modifying the actual relationship.

Looks like the answer is no for data annotations: http://social.msdn.microsoft.com/Forums/en-US/adonetefx/thread/394821ae-ab28-4b3f-b554-184a6d1ba72d/

This question appears to show how to do it with the fluent syntax, but not sure if that applies for 4.1 RC EF 4.1 RC: Weird Cascade Delete

Community
  • 1
  • 1
taylonr
  • 10,732
  • 5
  • 37
  • 66
2

As an additional example to Tyson's answer, I use the [CascadeDelete] attribute like follows in an entity, which successfully adds the "Cascade" delete rule to the Parent-Child relation.

public class Child
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Key]
    [SkipTracking]
    public Guid Id { get; set; }

    [CascadeDelete]
    public virtual Parent Parent { get; set; }

    [Required]
    [ForeignKey("Parent")]
    public Guid ParentId { get; set; }
}
Community
  • 1
  • 1
j00hi
  • 5,420
  • 3
  • 45
  • 82