So I've got this code:
...
modelBuilder.Entity<Person>(builder => {
builder.ToTable("person");
builder.Property(x => x.PersonId).HasColumnName("nconst");
builder.Property(x => x.FirstName).HasColumnName("firstname");
builder.Property(x => x.LastName).HasColumnName("lastname");
builder.Property(x => x.BirthYear).HasColumnName("birthyear");
builder.HasKey(x => x.PersonId);
builder.HasMany(x => x.Works).WithOne().HasForeignKey(x => x.PersonId);
builder.HasOne(x => x.Death).WithOne().HasForeignKey<Death>(x => x.PersonId);
});
modelBuilder.Entity<PersonBookmark>(builder => {
builder.ToTable("personbookmark");
builder.Property(x => x.PersonId).HasColumnName("nconst");
builder.Property(x => x.UserId).HasColumnName("user_id");
builder.Property(x => x.Date).HasColumnName("date");
builder.Property(x => x.Label).HasColumnName("label");
builder.HasKey(x => new { x.UserId, x.PersonId });
builder.HasOne(x => x.User).WithMany(x => x.PersonBookmarks).HasForeignKey(x => x.UserId);
builder.HasOne(x => x.Person).WithOne().HasPrincipalKey<PersonBookmark>(x => x.PersonId).HasForeignKey<Person>(x => x.PersonId);
});
...
namespace DataService.Domain {
public class PersonBookmark {
public int UserId { get; set; }
public DateTime Date { get; set; }
[StringLength(100, MinimumLength = 1)]
public string Label { get; set; }
[StringLength(10, MinimumLength = 10)]
public string PersonId { get; set; }
[NotMapped]
public virtual User User { get; set; }
[NotMapped]
public virtual Person Person { get; set; }
}
}
namespace DataService.Domain {
public class Person {
public Person() {
Works = new HashSet<Work>();
}
[StringLength(10, MinimumLength = 10)]
public string PersonId { get; set; }
[StringLength(100, MinimumLength = 1)]
public string LastName { get; set; }
[StringLength(100, MinimumLength = 1)]
public string FirstName { get; set; }
[StringLength(4, MinimumLength = 4)]
public string BirthYear { get; set; }
[NotMapped]
public virtual ICollection<Work> Works { get; set; }
[NotMapped]
public virtual Death Death { get; set; }
}
}
public bool DeletePersonBookmark(int UserId, string PersonId) {
var personBookmark = Context.PersonBookmarks.FirstOrDefault(x => x.UserId == UserId && x.PersonId == PersonId);
var found = personBookmark != null;
if (found) {
Context.PersonBookmarks.Remove(personBookmark);
Context.SaveChanges();
}
return found;
}
and when I'm trying to remove a PersonBookmark
from the database, I've got this Exception:
Microsoft.EntityFrameworkCore.DbUpdateException : An error occurred while updating the entries. See the inner exception for details.
---- Npgsql.PostgresException : 23503: update or delete on table "person" violates foreign key constraint "personbookmark_nconst_fkey" on table "personbookmark"
It looks like entity framework is trying to remove the associated Person
row, but I don't know where I told him to do this...
I just want the PersonBookmark
row to be deleted. Maybe I'm not understanding something obvious but as I view things the Person
shadow property does not mean the associated Person
should disappear with its reference owner.
Can someone help me?
Thank you in advance
CodePudding user response:
It looks like entity framework is trying to remove the associated Person row, but I don't know where I told him to do this...
Right here
builder.HasOne(x => x.Person).WithOne()
.HasPrincipalKey<PersonBookmark>(x => x.PersonId) // <--
.HasForeignKey<Person>(x => x.PersonId);
For one-to-one relationships the generic type argument of HasPrincipalKey
/ HasForeignKey
is used to specify who is the principal and who is the dependent in the relationship (docs). And cascade delete works from principal to dependent direction, i.e. deleting principal cascade deletes dependent(s).
What you need here is to exchange Person
and PersonBookmark
roles:
builder.HasOne(x => x.Person).WithOne()
.HasPrincipalKey<Person>(x => x.PersonId)
.HasForeignKey<PersonBookmark>(x => x.PersonId);
Make sure to regenerate the migration and apply it to the database.