Mam modelu Podmiot o User
i Person
podmiotów, tak, że każdy User
musi być powiązany z dokładnie 1 Person
i każdy Person
może być związane zero lub 1 User
.DbUpdateException z podmiotami, które nie narazić klucz obcy właściwości
User (0..1) <-------> (1) Person
Stowarzyszenie jest mapowane płynnie. Początkowo miałem tylko on podany na stronie Person
:
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)
;
Odkąd napotkał ten błąd, ja również dodaje ten sam mapowanie do boku User
:
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);
Jest to scenariusz w aplikacji, w której nowy User
może zostać utworzony i powiązany z istniejącym Person
. Właśnie w tym momencie mam trudności. EF bierze pod uwagę User
jako zależną stronę relacji i umieszcza kolumnę PersonId (FK, int, not null)
na tabeli . Nie wierzę, że można użyć własności klucza obcego w obu jednostkach, aby pomóc EF zarządzać powiązaniem (czy tak?).
Oto kod wadą, która próbuje poradzić sobie scenariusz:
// 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();
}
Ten kod działa poprawnie, gdy person
jest zerowy (nie istnieją już w db). Jednak gdy person
nie jest null (już istnieje w db) i user
ma wartość null, kod próbuje utworzyć nowy User
i skojarzyć go z istniejącym Person
. Podczas wywoływania SaveChanges()
, otrzymuję DbUpdateException
:
Wystąpił błąd podczas zapisywania podmioty, które nie narażają klucz obcy właściwości ich relacji. Właściwość EntityEntries zwróci wartość null , ponieważ nie można zidentyfikować pojedynczej encji jako źródła wyjątku. Obsługa wyjątków podczas zapisywania może być łatwiejsza dzięki ujawnieniu właściwości klucza obcego w typach jednostek. Szczegółowe informacje można znaleźć w artykule InnerException pod adresem .
Wewnętrzna wyjątek:
Związek z określenia 'User_Person' AssociationSet jest w stanie 'usunięta. Biorąc pod uwagę ograniczenia wielokrotności, odpowiedni " " User_Person_Source "również musi znajdować się w stanie" Usunięte ".
To nie ma żadnego sensu dla mnie, bo ja nie próbuję niczego usuwać, i sprawdzanie EntityState
zarówno User
i Person
pokazuje, że User
jest w stanie Added
, natomiast Person
jest w stanie Unchanged
. Mam nadpisane SaveChanges()
wykazać:
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();
}
Po wykonaniu tego kodu, ani InvalidOperationException
jest wyrzucane.Ponownie userChanges
znajduje się w stanie Added
, a personChanges
znajduje się w stanie .
Co robię źle?
Jak sobie z tym poradzić? Mam podobny problem z tematem, który ma ostatnie skojarzenie postu. Jeśli ustawisz ostatni post na inny post, spróbuje usunąć poprzednie! WTF o to chodzi? – leen3o
To * około * czasu na przełączenie ORM z EF na NHibernate! J/K ... W moim przypadku wynikało to z ograniczeń wielokrotności. Każdy użytkownik ** MUSI MIEĆ ** Osobę, ale Osoba może mieć NULL Użytkownika. Kiedy ustawię Person.User na null, EF najpierw sprawdza ograniczenia, aby sprawdzić, czy druga strona związku (User.Person) może być ustawiona na wartość null. Ponieważ nie może, EF umieszcza Użytkownika w usuniętym stanie. Gdybym ustawił użytkownika na wartość null, osoba ** nie ** zostałaby umieszczona w stanie usuniętym, ponieważ może mieć 0..1 użytkownika. Jeśli twoje ograniczenia są różne, wyślij pytanie, a ja popatrzę. – danludwig