Supprimer parents avec des enfants d'un à plusieurs " de la relation
J'ai un .NET4.0 application avec Entity Framework 5.0 e Sql Server CE 4.0.
J'ai deux entités avec un un-à-plusieurs (parent/enfant) de la relation. Je l'ai configuré pour effacer en cascade sur les parents de suppression, mais pour quelque raison il ne semble pas fonctionner.
Voici une version simplifiée de mon entités:
public class Account
{
public int AccountKey { get; set; }
public string Name { get; set; }
public ICollection<User> Users { get; set; }
}
internal class AccountMap : EntityTypeConfiguration<Account>
{
public AccountMap()
{
this.HasKey(e => e.AccountKey);
this.Property(e => e.AccountKey).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.Property(e => e.Name).IsRequired();
}
}
public class User
{
public int UserKey { get; set; }
public string Name { get; set; }
public Account Account { get; set; }
public int AccountKey { get; set; }
}
internal class UserMap : EntityTypeConfiguration<User>
{
public UserMap()
{
this.HasKey(e => e.UserKey);
this.Property(e => e.UserKey).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.Property(e => e.Name).IsRequired();
this.HasRequired(e => e.Account)
.WithMany(e => e.Users)
.HasForeignKey(e => e.AccountKey);
}
}
public class TestContext : DbContext
{
public TestContext()
{
this.Configuration.LazyLoadingEnabled = false;
}
public DbSet<User> Users { get; set; }
public DbSet<Account> Accounts { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); modelBuilder.Conventions.Remove<StoreGeneratedIdentityKeyConvention>();
modelBuilder.LoadConfigurations();
}
}
La chaîne de connexion:
<connectionStrings>
<add name="TestContext" connectionString="Data Source=|DataDirectory|\TestDb.sdf;" providerName="System.Data.SqlServerCe.4.0" />
</connectionStrings>
Et une version simplifiée de mon application de flux de travail:
static void Main(string[] args)
{
try
{
Database.SetInitializer(new DropCreateDatabaseAlways<TestContext>());
using (var context = new TestContext())
context.Database.Initialize(false);
Account account = null;
using (var context = new TestContext())
{
var account1 = new Account() { Name = "Account1^" };
var user1 = new User() { Name = "User1", Account = account1 };
context.Accounts.Add(account1);
context.Users.Add(user1);
context.SaveChanges();
account = account1;
}
using (var context = new TestContext())
{
context.Entry(account).State = EntityState.Deleted;
context.SaveChanges();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress any key to exit...");
Console.ReadLine();
}
Lorsque je tente de supprimer l'entité mère, il lance:
La relation ne peut pas être changé parce que l'un ou plusieurs des
clé étrangère propriétés est pas les valeurs null. Lorsqu'une modification est apportée à un
relation, la clé étrangère de la propriété est définie sur une valeur null.
Si la clé étrangère ne prend pas en charge les valeurs null, une nouvelle relation
doit être défini, la clé étrangère de la propriété doit être assigné à un autre
valeur non nulle, ou sans rapport avec l'objet doit être supprimé.
Je crois que ma relation de configuration est ok (suivi de la documentation). J'ai également recherché lignes directrices sur la suppression des entités détachées.
Je ne peux vraiment pas comprendre pourquoi cette suppression ne fonctionne pas. Je veux éviter le chargement de tous les enfants, de les supprimer un par un et leur de la suppression de la mère, parce qu'il doit y avoir une meilleure solution que celle.
OriginalL'auteur Arthur Nunes | 2013-05-15
Vous devez vous connecter pour publier un commentaire.
Réglage de l'état d'une entité à
Deleted
et de l'appel deDbSet<T>.Remove
pour cette entité ne sont pas les mêmes.La différence est que l'établissement de l'état ne change l'état de l'entité de la racine (celui que vous avez passer dans
context.Entry
) àDeleted
mais pas de l'état des entités liées, tandis queRemove
ne ce si la relation est configuré avec suppression en cascade.Si vous obtenez une exception dépend en réalité de la les enfants (tous ou seulement une partie) étant fixé au contexte ou non. Cela conduit à un comportement qui est un peu difficile à suivre:
Remove
vous n'obtenez pas une exception, peu importe si les enfants sont chargés ou non. Il y a toujours une différence:DELETE
déclaration pour chaque enfant, pour la mère (parce queRemove
n'marquer tous commeDeleted
)DELETE
instruction de la mère à la base de données et en raison de suppression en cascade est activée la base de données permettra de supprimer les enfants.Deleted
vous pouvez éventuellement obtenir une exception:Deleted
et de fe plaindre de ce que vous essayez de supprimer une entité (l'entité de la racine) dans une relation requise sans supprimer les personnes à charge (enfants) ou au moins sans mettre leur clés étrangères d'une autre racine entité qui n'est pas dansDeleted
état. C'est l'exception-vous eu:account
est la racine et lauser1
est une personne à charge deaccount
et de l'appel decontext.Entry(account).State = EntityState.Deleted;
sera également joindreuser1
en étatUnchanged
le contexte (ou la détection de changement dansSaveChanges
va le faire, je ne suis pas sûr de buter).user1
fait partie de laaccount.Users
de collecte en raison de la relation de correction de l'ajouter à la collection dans votre premier contexte bien que vous n'avez pas l'ajouter explicitement dans votre code.Deleted
enverra unDELETE
déclaration de la base de données et de nouveau de suppression en cascade dans la base de données permettra de supprimer les enfants. Cela fonctionne sans exception. Votre code alors travailler par exemple, si vous définissezaccount.Users = null
avant de définir l'état deDeleted
dans le deuxième contexte ou avant d'entrer dans le deuxième contexte.À mon avis, à l'aide de
Remove
......c'est clairement la préférence façon, parce que le comportement de
Remove
est beaucoup plus que vous pouvez attendre d'un lien nécessaire avec la suppression en cascade (ce qui est le cas dans votre modèle). La dépendance du comportement d'un manuel de changement d'état des états, d'autres entités qui le rend plus difficile à utiliser. Je pense qu'il serait comme l'utilisation avancée seulement pour des cas particuliers.La différence n'est pas très connu ou documentée. J'ai vu très peu de posts à ce sujet. Le seul que j'ai pu trouver à droite maintenant, encore une fois, est ce un par Zeeshan Hirani.
Il semble que beaucoup de gens ont des problèmes lorsque vous essayez de faire de parent-enfant, les opérations de travail en EF telles que insert, update et delete que chaque fois que j'ai lu plus sur EF, le plus déçu que je reçois.
OriginalL'auteur Slauma
J'ai essayé une légère approche différente et, étrangement, il a travaillé. Si je remplace ce code:
Par celui-ci:
Il travaille avec plus de problèmes. Vous ne savez pas si c'est un bug ou si je suis en manque de quelque chose. Je voudrais vraiment apprécier un peu de lumière sur la question, parce que j'étais à peu près sûr que le premier moyen (EntityState.Supprimé) a été le recommandé.
OriginalL'auteur Arthur Nunes