Извините за туманной названия, это трудно описать это в одной строке:Почему реляционные ограничения несовместимы после обновления внешнего ключа?
У меня есть 2 сущностей User
и UserAddress
, где пользователь имеет 2 внешних ключей DefaultInvoiceAddressId
и DefaultDeliveryAddressId
и UserAddress имеет UserId
внешний ключ.
Пользовательский объект имеет свойства навигации для адресов по умолчанию (DefaultInvoiceAddress
и DefaultDeliveryAddress
), а также один для всех его адресов: AllAddresses
.
Картография и т. Д. Работает, создавая и обновляя пользователей и адреса.
Что не работает, хотя и устанавливает существующий адрес пользователя, например, DefaultInvoiceAddress. В SQL-терминах я хочу, чтобы это было UPDATE USER SET DefaultInvoiceAddressId = 5 WHERE Id = 3
.
Я попытался это следующим образом:
private void MarkAs(User user, UserAddress address, User.AddressType type) {
if (context.Entry(user).State == EntityState.Detached)
context.Users.Attach(user);
// guess I don't really need this:
if (context.Entry(address).State == EntityState.Detached)
context.UserAddresses.Attach(address);
if (type.HasFlag(User.AddressType.DefaultInvoice)) {
user.DefaultInvoiceAddressId = address.Id;
user.DefaultInvoiceAddress = null;
context.Entry(user).Property(u => u.DefaultInvoiceAddressId).IsModified = true;
}
if (type.HasFlag(User.AddressType.DefaultDelivery)) {
user.DefaultDeliveryAddressId = address.Id;
user.DefaultDeliveryAddress = null;
context.Entry(user).Property(u => u.DefaultDeliveryAddressId).IsModified = true;
}
}
Этот метод вызывается как при создании новых UserAddresses, а также при обновлении адресов. Создать сценарий работает, как ожидалось, однако в случае обновления я получаю следующее сообщение об ошибке:
The changes to the database were committed successfully,
but an error occurred while updating the object context.
The ObjectContext might be in an inconsistent state.
Inner exception message: A referential integrity constraint violation occurred:
The property values that define the referential constraints are not consistent between principal and dependent objects in the relationship.
Я называю этот метод с объектом User I retrive из базы данных и DefaultDeliveryAddress он содержит, который я загружаю рядом с ним с помощью нетерпевая загрузка.
var user = mainDb.User.Get(UnitTestData.Users.Martin.Id, User.Include.DefaultAddresses);
var existingAddress = user.DefaultDeliveryAddress;
mainDb.User.Addresses.SetAs(user, existingAddress, User.AddressType.DefaultInvoice))
// the SetAs method verfies input parameters, calls MarkAs and then SaveChanges
В двух словах, я просто хочу, чтобы сделать DefaultDeliveryAddress пользователя, и его DefaultInvoiceAddress, который будет легко осуществить с помощью данной команды SQL Update, но я что-то с моей EF кода отсутствует. Я уже проверил, что:
- Только Id установлено свойство навигации (
DefaultInvoiceAddress
) повторно установить нулевое значение - UserAddress.UserId = User.Id (очевидно, так как он уже назначен пользователь)
- объект пользователя будет
Modified
(проверено с отладчиком), так как один из его свойств помечается как модифицированные - Я также попытался очистки и адреса по умолчанию навигационные свойства, но это не помогло
Я подозреваю, что эта проблема возникает из-за того, что пользовательский объект имеет 2 ссылки на UserAddress, и оба внешних ключа настроены так, чтобы ссылаться на один и тот же адрес - как я могу заставить EF работать с этим?
Update:
Вот отображения объекта пользователя:
// from UserMap.cs:
...
Property(t => t.DefaultInvoiceAddressId).HasColumnName("DefaultInvoiceAddressId");
Property(t => t.DefaultDeliveryAddressId).HasColumnName("DefaultDeliveryAddressId");
// Relationships
HasOptional(t => t.DefaultInvoiceAddress)
.WithMany()
.HasForeignKey(t => t.DefaultInvoiceAddressId);
HasOptional(t => t.DefaultDeliveryAddress)
.WithMany()
.HasForeignKey(t => t.DefaultDeliveryAddressId);
HasMany(t => t.AllAddresses)
.WithRequired()
.HasForeignKey(t => t.UserId)
.WillCascadeOnDelete();
UserAddress не имеет навигационных свойств обратно к пользователю; это только параметры HasMaxLength и HasColumnName (я исключаю их, чтобы вопрос был несколько читаемым).
Update 2
Вот выполнена команда из IntelliTrace:
The command text "update [TestSchema].[User]
set [DefaultInvoiceAddressId] = @0
where ([Id] = @1)
" was executed on connection "Server=(localdb)\..."
Выглядит хорошо для меня; кажется, только диспетчер состояний EF путается с помощью сопоставлений клавиш.
Опубликовать определения и конфигурации пользователя и адреса. Также опубликуйте фактические созданные statemnts SQL. –
Хм, SELECT можно просто получить из запроса, но для UPDATE/INSERT вам понадобится студия SQL Mgmt или профиль (мини-профайлер, кажется, стоит посмотреть). –
Я нашел способ получить утверждение с Intellitrace, я обновил свой вопрос командой. – enzi