Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unidirectional One to One relationship entity framework, cascade delete doesn't work

I want to implement a unidirectional one to one relationship; however on cascade delete doesn't work.

I have the following classes:

public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Address Address { get; set; }
}

public class Address
{
    public int Id { get; set; }
    public string Street { get; set; }
    //I don't want the StudentId foreign key or the property of Student class here 
}

In my Context class, I'm mapping the relationship like this:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Student>()
        .HasRequired(s => s.Address)
        .WithOptional()
        .Map(m => m.MapKey("Address_Id"))
        .WillCascadeOnDelete();
}

For some reason, it's not deleting the address when, student object is deleted.

Moreover, I also want to add the foreign key property (i.e. AddressId) in the Student class like this:

[ForeignKey("Address")]
[Column("Address_Id")]
public string AddressId { get; set; }

However, I get this error when I try to add a new migration:

Address_Id: Name: Each property name in a type must be unique. Property name 'Address_Id' is already defined.

I do believe I'm mixing things up (with MapKey and the attributes of AddressId). However, I don't know how to fix this.


I went through this SO question and this article; however, no luck so far.

Link to DotNetFiddle. It won't work cause there is no database.

like image 725
Dumbledore Avatar asked Mar 30 '16 15:03

Dumbledore


People also ask

What is Cascade delete in Entity Framework?

Cascade delete automatically deletes dependent records or sets null to ForeignKey columns when the parent record is deleted in the database. Cascade delete is enabled by default in Entity Framework for all types of relationships such as one-to-one, one-to-many and many-to-many.

Why can't I delete a relationship in EF Core?

Since dependents/children are loaded, they are always deleted by EF Core, and never left for the database to delete. Severing a relationship is not valid here since the dependents/children are not loaded. The default for required relationships like this is Cascade.

Does the EF Core in-memory database support Cascade deletes?

The EF Core in-memory database does not currently support cascade deletes in the database. Do not configure cascade delete in the database when soft-deleting entities. This may cause entities to be accidentally really deleted instead of soft-deleted.

Do not configure Cascade delete in the database when soft-deleting?

Do not configure cascade delete in the database when soft-deleting entities. This may cause entities to be accidentally really deleted instead of soft-deleted. Some databases, most notably SQL Server, have limitations on the cascade behaviors that form cycles.


2 Answers

For some reason, it's not deleting the address when, student object is deleted.

That's the normal behavior for the relationship you have defined. It's not a matter of data annotations or fluent configuration. If you have different expectations, you'd better revisit your model.

Every relationship has a one side called principal and another side called dependent. The principal side (a.k.a. master, primary) is the one being referenced. The dependent side (a.k.a. detail, secondary) is the one that is referencing the principal. The foreign key is put on the dependent side and must always point to an existing principal or null when the relationship is optional. The cascade delete works by deleing all the dependent records when the principal record is deleted.

As explained in the How Code First Determines the Principal and Dependent Ends in an Association? section of the article mentioned by you, EF always uses the required side as principal and allows you to chose the one only when both are required.

With all that being said, let see what you have.

Address is required, Student is optional. Also you want to put FK in Student, i.e. Student references Address.

All that means that in your relationship, Address is the principal and Student is the dependent. Which means the Address may exists w/o Student referencing it. If cascade delete is turned on (as you did), deleting the Address will delete the Student, not the opposite.

I think all that should explain why it's is working the way it is now, and that no attributes or configuration can help to achieve what are you asking for. If you want it differently, the same article (and related from the same series) explains how to configure the relationship to either use Shared Primary Key Association or Foreign Key Association at the Address side. Whether it is unidirectional or bidirectional absolutely has nothing in common with the problem - see Should We Make the Associations Bidirectional? section in the article.

like image 172
Ivan Stoev Avatar answered Sep 28 '22 08:09

Ivan Stoev


You foreign key should be like this :

public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    [ForeignKey("AddressId")]
    public Address Address { get; set; }        
    [Column("Address_Id")]
    public int AddressId { get; set; }
}

In your fluent mapping you just need:

modelBuilder.Entity<Student>()
    .HasRequired(s => s.Address)
    .WillCascadeOnDelete(true);

Or you can force cascade delete with an annotation:

[Required]
[ForeignKey("AddressId")]
public Address Address { get; set; }

Now update your database and your mapping should be correct and the delete should cascade.

like image 41
James Dev Avatar answered Sep 28 '22 07:09

James Dev