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?
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
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