Suite à la section "Code First Modeling" du cours Pluralsight "Initiation à Entity Framework 5" de Julie Lerman , j'ai créé deux classes POCO avec un one-to-zero-or- un relation: un parent (utilisateur) et un facultatif enfant (UserDetail).
Diagramme de modèle de données utilisateur et utilisateur (Cliquez pour visualiser).
Notez dans le diagramme que la propriété UserId est une clé primaire et une clé étrangère pour UserDetail.
Code pertinent:
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();
//...
}
}
Lorsque la méthode Delete () de la classe UserRepository est appelée, elle ne supprime pas l'enregistrement User de la base de données car la suppression de la cascade n'est pas activée dans UserDetail.
L'instruction DELETE était en conflit avec la contrainte REFERENCE "FK_dbo.UserDetail_dbo.User_UserId".
Comment activeriez-vous les suppressions en cascade pour relations un à zéro ou un en utilisant Entity Framework Code First (pour que la suppression d'un utilisateur supprime automatiquement UserDetail)?
Pour ce faire, vous devrez utiliser l’API fluide.
Essayez d’ajouter ce qui suit à votre DbContext
:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasOptional(a => a.UserDetail)
.WithOptionalDependent()
.WillCascadeOnDelete(true);
}
Vous pouvez également désactiver la convention de suppression en cascade dans la portée globale de votre application en procédant comme suit:
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>()
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>()
Ce code a fonctionné pour moi
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<UserDetail>()
.HasRequired(d => d.User)
.WithOptional(u => u.UserDetail)
.WillCascadeOnDelete(true);
}
Le code de migration était:
public override void Up()
{
AddForeignKey("UserDetail", "UserId", "User", "UserId", cascadeDelete: true);
}
Et ça a bien fonctionné. Quand j'ai utilisé pour la première fois
modelBuilder.Entity<User>()
.HasOptional(a => a.UserDetail)
.WithOptionalDependent()
.WillCascadeOnDelete(true);
Le code de migration était:
AddForeignKey("User", "UserDetail_UserId", "UserDetail", "UserId", cascadeDelete: true);
mais cela ne correspond à aucune des deux surcharges disponibles (dans EntityFramework 6)