Im Anschluss an den Abschnitt "Code First Modeling" des Kurses Pluralsight "Erste Schritte mit Entity Framework 5" von Julie Lerman erstellte ich zwei POCO-Klassen mit einem Eins-zu-Eins -Zero-or-One-Beziehung : ein Elternteil (Benutzer) und ein optionales Kind (UserDetail).
Benutzer- und UserDetail-Datenmodelldiagramm (zum Anzeigen anklicken).
Beachten Sie im Diagramm, dass die UserId-Eigenschaft ein Primärschlüssel und ein Fremdschlüssel für UserDetail ist .
Relevanter Code:
public class User
{
//...
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
/* Has a 1:0..1 relationship with UserDetail */
public virtual UserDetail UserDetail { get; set; }
//...
}
public class UserDetail
{
//...
/* Has a 0..1:1 relationship with User */
public virtual User User { get; set; }
[Key, ForeignKey("User")]
public int UserId { get; set; }
//...
}
public class EFDbContext : DbContext
{
public DbSet<User> Users { get; set; }
//public DbSet<UserDetail> UserDetails { get; set; } /* Explicit declaration not necessary. Context is aware of UserDetail entity due to 0..1:1 relationship with User */
public EFDbContext()
{
Configuration.ProxyCreationEnabled = true;
Configuration.LazyLoadingEnabled = true;
}
}
public class UserRepository : IUserRepository
{
private EFDbContext _context = new EFDbContext();
public void Delete(User entity)
{
entity = _context.Users.Find(entity.UserId);
//...
_context.Users.Remove(entity);
_context.SaveChanges();
//...
}
}
Wenn die Delete () -Methode in der UserRepository-Klasse aufgerufen wird, wird der Benutzerdatensatz in der Datenbank nicht gelöscht, da für den Fremdschlüssel in UserDetail die Kaskadenlöschung nicht aktiviert ist.
Die DELETE-Anweisung stand in Konflikt mit der REFERENCE-Einschränkung "FK_dbo.UserDetail_dbo.User_UserId".
Wie würden Sie kaskadierende Löschvorgänge für Eins-zu-Null-oder-Eins-Beziehungen aktivieren, indem Sie zuerst den Entity Framework-Code verwenden (sodass beim Löschen eines Benutzers UserDetail automatisch gelöscht wird)? ?
Dazu müssen Sie die flüssige API verwenden.
Fügen Sie Ihrem DbContext
Folgendes hinzu:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasOptional(a => a.UserDetail)
.WithOptionalDependent()
.WillCascadeOnDelete(true);
}
Sie können auch die Kaskadenlöschkonvention im globalen Bereich Ihrer Anwendung deaktivieren, indem Sie dies tun:
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>()
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>()
Dieser Code hat bei mir funktioniert
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<UserDetail>()
.HasRequired(d => d.User)
.WithOptional(u => u.UserDetail)
.WillCascadeOnDelete(true);
}
Der Migrationscode war:
public override void Up()
{
AddForeignKey("UserDetail", "UserId", "User", "UserId", cascadeDelete: true);
}
Und es hat gut funktioniert. Als ich das erste Mal benutzt habe
modelBuilder.Entity<User>()
.HasOptional(a => a.UserDetail)
.WithOptionalDependent()
.WillCascadeOnDelete(true);
Der Migrationscode war:
AddForeignKey("User", "UserDetail_UserId", "UserDetail", "UserId", cascadeDelete: true);
es entspricht jedoch keiner der beiden verfügbaren Überladungen (in EntityFramework 6).