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.
2 Answers
Answers 1
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.
Answers 2
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.
0 comments:
Post a Comment