6

aussetzen habe ich ein Unternehmen Modell mit User und Person Einheiten, so dass jeder User muss mit genau 1 Person in Verbindung gebracht werden, und jeder Person kann null oder 1 User zugeordnet werden.DbUpdateException mit Entitäten, die keine Fremdschlüsseleigenschaften

User (0..1) <-------> (1) Person 

Die Zuordnung wird fließend abgebildet. Ursprünglich nur ich hatte es auf der Person Seite erklärt:

private class PersonOrm : EntityTypeConfiguration<Person> 
{ 
    internal PersonOrm() 
    { 
     ToTable(typeof(Person).Name, DbSchemaName.People); 

     // has zero or one User 
     HasOptional(p => p.User) 
      .WithRequired(d => d.Person) 
      .Map(d => d.MapKey("PersonId")) 
      .WillCascadeOnDelete(false) 
     ; 

Da ich diesen Fehler aufgetreten ist, habe ich auch die gleiche Abbildung auf die User Seite:

private class UserOrm : EntityTypeConfiguration<User> 
{ 
    internal UserOrm() 
    { 
     ToTable(typeof(User).Name, DbSchemaName.Identity); 

     // has exactly 1 Person 
     HasRequired(p => p.Person) 
      .WithOptional(d => d.User) 
      .Map(d => d.MapKey("PersonId")) 
      .WillCascadeOnDelete(false); 

Es ist ein Szenario, in der Anwendung, Eine neue User kann erstellt und einer bestehenden Person zugeordnet werden. Hier habe ich momentan Schwierigkeiten. EF betrachtet User als die abhängige Seite der Beziehung und setzt eine PersonId (FK, int, not null) Spalte auf die User Tabelle. Ich glaube nicht, dass es möglich ist, eine fremde Schlüsseleigenschaft in einer Entität zu verwenden, um EF dabei zu helfen, die Verknüpfung zu verwalten (oder?).

Hier einige andernfalls Code, der das Szenario zu behandeln versucht:

// find out if Person already exists 
var person = context.People.SingleOrDefault(p => p.Emails.Any(
    e => e.Value.Equals(emailAddress, StringComparison.OrdinalIgnoreCase))); 

// find out if User already exists 
var user = context.Users.SingleOrDefault(
    u => u.Name.Equals(emailAddress, StringComparison.OrdinalIgnoreCase)); 

if (user == null) 
{ 
    user = new User 
    { 
     Name = emailAddress, 
     IsRegistered = isRegistered, 
     Person = person ?? PersonFactory.Create(emailAddress), 
     // ignore the PersonFactory.Create, that part works 
    }; 

    context.Entry(user).State = EntityState.Added; 
    context.SaveChanges(); 
} 

Dieser Code funktioniert gut, wenn person null ist (existiert nicht bereits in der db). Wenn person jedoch nicht null ist (bereits in db vorhanden) und user null ist, versucht der Code, einen neuen User zu erstellen und ihn dem vorhandenen Person zuzuordnen. Wenn SaveChanges() Aufruf, erhalte ich eine DbUpdateException:

Fehler beim Entitäten speichern, die Fremdschlüssel Eigenschaften nicht für ihre Beziehungen aus. Die EntityEntries-Eigenschaft gibt null zurück, da eine einzelne Entität nicht als Quelle der Ausnahme identifiziert werden kann. Die Behandlung von Ausnahmen während des Speicherns kann vereinfacht werden, indem Sie die Fremdschlüsseleigenschaften in Ihren Entitätstypen angeben. Details finden Sie unter InnerException.

die innere Ausnahme ist:

Eine Beziehung von der 'User_Person' AssociationSet im 'Gelöscht' -Zustand. Bei Multiplizität-Constraints muss eine entsprechende 'User_Person_Source' ebenfalls im Status 'Gelöscht' sein.

Das macht keinen Sinn für mich, weil ich nicht bin versucht, etwas zu löschen, und die EntityState sowohl User und Person Überprüfung zeigt, dass User im Added Zustand befindet, während Person im Unchanged Zustand .

public override int SaveChanges() 
{ 
    var userChanges = ChangeTracker.Entries<User>().Single(); 
    var personChanges = ChangeTracker.Entries<Person>().Single(); 

    if (userChanges.State == EntityState.Deleted) 
     throw new InvalidOperationException("wtf?"); 

    if (personChanges.State == EntityState.Deleted) 
     throw new InvalidOperationException("wtf?"); 

    return base.SaveChanges(); 
} 

Wenn dieser Code ausgeführt wird, weder InvalidOperationException geworfen wird: Ich habe SaveChanges() zu demonstrieren, außer Kraft gesetzt.Wiederum befindet sich userChanges im Zustand Added, und personChanges befindet sich im Zustand Unchanged.

Was mache ich falsch?

Antwort

6

Ich fühle mich jetzt wirklich dumm. Nach dem Schreiben dieser sorgfältigen Frage ist es jetzt offensichtlich.

Die Person Ich teste mit bereits existiert, und hat bereits eine User Assoziation mit einem anderen User.Name. Deshalb kommt user auf Null. Das Setzen der Person.User-Eigenschaft auf eine neue User führt dazu, dass die alte User in den Zustand Deleted versetzt wird. Do.

Entschuldigung, dass Sie Ihre Zeit verschwendet haben. Ich werde die Frage aufheben, es sei denn, es wird vereinbart, dass es besser wäre, sie zu löschen.

+0

Also, wie kommst du rum? Ich habe ein ähnliches Problem mit einem Thema, das eine letzte Postassoziation hat. Wenn der letzte Post auf einen anderen Post gesetzt wurde, versucht er den vorherigen zu löschen !! WTF ist das? – leen3o

+2

Es ist * ungefähr * Zeit, ORM von EF zu NHibernate zu wechseln! J/K ... In meinem Fall war es wegen der Beschränkungen der Vielfalt. Jeder Benutzer ** muss eine Person haben, aber eine Person kann einen Null Benutzer haben. Wenn ich Person.User auf null setze, überprüft EF zuerst die Einschränkungen, um festzustellen, ob die andere Seite der Beziehung (User.Person) auf null gesetzt werden kann. Da dies nicht möglich ist, versetzt EF den Benutzer in den gelöschten Zustand. Hätte ich die User.Person auf null gesetzt, wäre Person ** nicht ** in den gelöschten Zustand versetzt worden, da sie 0..1 User haben könnte. Wenn Ihre Einschränkungen anders sind, schreiben Sie eine Frage und ich werde einen Blick darauf werfen. – danludwig

0

Stellen Sie sicher, dass die Beziehung in Ihrem Mapping (Entity-Typ-Konfiguration)

Zum Beispiel definiert haben:

this.HasRequired (t => t.QuoteResponse) .WithMany (t => t.QuoteResponseItems) .HasForeignKey (d => d.QuoteResponseID);