Вставка EF не использует правильный идентификатор для таблицы внешних ссылок «многие ко многим»C#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Гость
 Вставка EF не использует правильный идентификатор для таблицы внешних ссылок «многие ко многим»

Сообщение Гость »


Я создаю интеграционные тесты для репозитория, написанного на основе EF. Во время настройки моего тестового примера я получаю SqlException о нарушении FK.
Сущности и конфигурация таблицы сущностей
В целом идея состоит в том, что у меня есть таблица Contact, записи которой могут содержать ноль или более элементов ContactType. Типы фиксированы в перечислении в коде, но для обеспечения ссылочной целостности у меня есть таблица для них.

Вот некоторый контекст рассматриваемых сущностей:

публичный класс Контакт: EntityBase { общедоступная строка? Имя {получить; набор; } общедоступная строка? Адрес1 {получить; набор; } общедоступная строка? Город {получить; набор; } общедоступная строка? Состояние {получить; набор; } общедоступная строка? Почтовый индекс {получить; набор; } // Отрезаем... все основные типы общественный виртуальный IList ContactTypes {get; набор; } = новый список(); } общедоступный класс ContactType { общественный идентификатор ContactTypeEnum {получить; набор; } общедоступная строка Имя {get; набор; } = строка.Пусто; } общедоступный класс ContactTypeXref { общественный ИНТ Id {получить; набор; } общественный ИНТ ContactId {получить; набор; } общественный ContactTypeEnum ContactTypeId {получить; набор; } общественный DateTimeOffset Created {get; набор; } } Каждая сущность также имеет свою собственную конфигурацию для настройки таблиц в базе данных:

public void Configuration (построитель EntityTypeBuilder) { // Основной ключ builder.HasKey(x => x.Id); builder.Property(x => x.Id) .HasColumnOrder(0); // Snip - индексы карты, столбцы аудита, свойства... // Связь «многие ко многим» между контактами и типами контактов builder.HasMany(x => x.ContactTypes) .Со многими() .UsingEntity( ContactTypeXrefTableName, l => l.HasOne().WithMany().HasForeignKey(e => e.ContactTypeId), r => r.HasOne().WithMany().HasForeignKey(e => e.ContactId), г => { // Настройка свойства полезной нагрузки z.Property(e => e.Created).HasDefaultValueSql(SqlServerSysDatetimeOffset); }); } public void Configure (строитель EntityTypeBuilder) { builder.ToTable( Имя Таблицы, x => x.HasComment( «Табличное представление ContactTypeEnum для ссылочной целостности. Не редактируйте без соответствия изменениям Enum в коде.")); builder.Property(x => x.Id) .ValueGeneratedNever(); строитель.HasData( новый список { new() { Id = ContactTypeEnum.Carrier, Name = "Carrier" }, new() { Id = ContactTypeEnum.Customer, Name = "Клиент" }, new() { Id = ContactTypeEnum.Shipper, Name = "Отправитель" }, new() { Id = ContactTypeEnum.Vendor, Name = "Vendor" }, }); } Все, что репозиторий делает внутри AddAsync, заключается в следующем:

public async Task AddAsync (Tentity) { ждут AppContext.Set().AddAsync(entity); дождитесь AppContext.SaveChangesAsync(); возврат объекта; } Проблемный интеграционный тест [Факт] public async Task ListAsync_ShouldOnlyReturnCarrierContacts_WhenListContainsManyDifferentTypes() { ожидайте ExecuteInAsyncTransaction(async () => { // Договариваться var CarrierContactType = Context.ContactTypes.FirstOrDefault(ct => ct.Id == ContactTypeEnum.Carrier); var CarrierContact = новый контакт { Имя = «Контакт оператора связи», Адрес1 = "456 Какая-то улица", Актив = правда, ContactTypes = новый список() { операторContactType, }, }; ждут _contactRepository.AddAsync(carrierContact); // ПРИМЕЧАНИЕ: эта вставка успешна varvendorContactType = Context.ContactTypes.FirstOrDefault(ct => ct.Id == ContactTypeEnum.Vendor); варvendorContact = новый контакт() { Имя = «Контактное лицо поставщика тестов», Адрес1 = "Другая улица, 123", Актив = правда, ContactTypes = новый список() { вендорКонтактТип, }, }; ждут _contactRepository.AddAsync(vendorContact); // ПРИМЕЧАНИЕ: эта вставка не удалась // ПРИМЕЧАНИЕ. Это не позволит системе отслеживания изменений узнать // об объекте Contact, чтобы мы могли использовать тот же контекст // для повторного запроса элемента. Контекст.ChangeTracker.Очистить(); // Действовать результат вар = ждут _sut.ListAsync (новый ListCarriersRequest()); // Утверждать результат.ShouldNotBeNull(); result.Carriers.ShouldHaveSingleItem(); result.Carriers.ShouldContain(x => x.Id == CarrierContact.Id); }); } Я получаю следующую ошибку:

Инструкция INSERT конфликтовала с ограничением FOREIGN KEY «FK_ContactTypeXrefs_Contacts_ContactId». Конфликт произошел в базе данных «VF_BillOfLading», таблица «dbo.Contacts», столбец «Id».

Выполненный SQL:

информация: 20.09.2023 09:40:49.439 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command) Выполнено DbCommand (18 мс) [Parameters=[@p0='456 Some Street' (Размер = 450), @p1=NULL (Размер = 450), @p2=NULL (Размер = 450), @p3=NULL (Размер = 450), @p4='2023-09-20T14:40:49.3570311+00:00', @p5='testuser@volflex.com' (Nullable = false) (Размер = 4000), @p6=NULL (Размер = 4000), @p7=NULL (Размер = 4000), @p8='True', @p9='False', @p10='False', @p11='2023-09-20T14:40:49.3570311+00: 00', @p12='testuser@volflex.com' (Nullable = false) (Размер = 4000), @p13='Тестовый контакт с оператором связи' (Размер = 450), @p14=NULL (Размер = 4000), @p15 =NULL (Размер = 450), @p16=NULL (Размер = 4000), @p17=NULL (Размер = 450), @p18=NULL (Размер = 4000)], CommandType='Text', CommandTimeout='30' ] ВЫКЛЮЧИТЬ IMPLICIT_TRANSACTIONS; УСТАНОВИТЬ NOCOUNT ON; INSERT INTO [Контакты] ([Адрес1], [Адрес2], [Адрес3], [Город], [Создано], [Создано], [Электронная почта], [Факс], [Активен], [Настраиваемыйконтакт], [Удален], [Изменено], [ModifiedBy], [Имя], [Телефон], [Почтовый индекс], [Scac], [Штат], [URL-адрес]) ВЫХОД ВСТАВЛЕН.[Идентификатор], ВСТАВЛЕН.[Версия] ЗНАЧЕНИЯ (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14, @p15, @p16, @p17, @p18); информация: 20.09.2023 09:40:49.461 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command) Выполнено DbCommand (3 мс) [Parameters=[@p19='69', @p20='2'], CommandType='Text', CommandTimeout='30'] ВЫКЛЮЧИТЬ IMPLICIT_TRANSACTIONS; УСТАНОВИТЬ NOCOUNT ON; ВСТАВИТЬ В [ContactTypeXrefs] ([ContactId], [ContactTypeId]) ВЫХОД ВСТАВЛЕН.[Идентификатор], ВСТАВЛЕН.[Создан] ЗНАЧЕНИЯ (@p19, @p20); информация: 20.09.2023 09:40:49.482 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command) Выполнена команда DbCommand (3 мс) [Parameters=[], CommandType='Text', CommandTimeout='30'] SELECT TOP(1) [c].[Id], [c].[Имя] ИЗ [ContactTypes] КАК [c] ГДЕ [c].[Id] = 0 информация: 20.09.2023 09:40:49.492 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command) Выполнено DbCommand (2 мс) [Parameters=[@p0='123 Другая улица' (Размер = 450), @p1=NULL (Размер = 450), @p2=NULL (Размер = 450), @p3=NULL (Размер = 450), @p4='2023-09-20T14:40:49.4864373+00:00', @p5='testuser@volflex.com' (Nullable = false) (Размер = 4000), @p6=NULL (Размер = 4000), @p7=NULL (Размер = 4000), @p8='True', @p9='False', @p10='False', @p11='2023-09-20T14:40:49.4864373+00: 00', @p12='testuser@volflex.com' (Nullable = false) (Размер = 4000), @p13='Тестовый контакт с поставщиком' (Размер = 450), @p14=NULL (Размер = 4000), @p15 =NULL (Размер = 450), @p16=NULL (Размер = 4000), @p17=NULL (Размер = 450), @p18=NULL (Размер = 4000)], CommandType='Text', CommandTimeout='30' ] ВЫКЛЮЧИТЬ IMPLICIT_TRANSACTIONS; УСТАНОВИТЬ NOCOUNT ON; INSERT INTO [Контакты] ([Адрес1], [Адрес2], [Адрес3], [Город], [Создано], [Создано], [Электронная почта], [Факс], [Активен], [Настраиваемыйконтакт], [Удален], [Изменено], [ModifiedBy], [Имя], [Телефон], [Почтовый индекс], [Scac], [Штат], [URL-адрес]) ВЫХОД ВСТАВЛЕН.[Идентификатор], ВСТАВЛЕН.[Версия] ЗНАЧЕНИЯ (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14, @p15, @p16, @p17, @p18); информация: 20.09.2023 09:40:49.494 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command) Выполнено DbCommand (2 мс) [Parameters=[@p19='-2147482646', @p20='0'], CommandType='Text', CommandTimeout='30'] ВЫКЛЮЧИТЬ IMPLICIT_TRANSACTIONS; УСТАНОВИТЬ NOCOUNT ON; ВСТАВИТЬ В [ContactTypeXrefs] ([ContactId], [ContactTypeId]) ВЫХОД ВСТАВЛЕН.[Идентификатор], ВСТАВЛЕН.[Создан] ЗНАЧЕНИЯ (@p19, @p20); сбой: 20.09.2023 09:40:49.512 CoreEventId.SaveChangesFailed[10000] (Microsoft.EntityFrameworkCore.Update) В базе данных произошло исключение при сохранении изменений для типа контекста BillOfLading.DataAccess.SqlServer.BillOfLadingDbContext. Microsoft.EntityFrameworkCore.DbUpdateException: произошла ошибка при сохранении изменений сущности. Подробности смотрите во внутреннем исключении. ---> Microsoft.Data.SqlClient.SqlException (0x80131904): оператор INSERT confl Что мне кажется странным, так это то, что первая запись вставляется нормально вместе с записью ContactTypeXref:

Выполнена команда DbCommand (3 мс) [Parameters=[@p19='69', @p20='2'], CommandType='Text', CommandTimeout='30 '] ВЫКЛЮЧИТЬ IMPLICIT_TRANSACTIONS; УСТАНОВИТЬ NOCOUNT ON; ВСТАВИТЬ В [ContactTypeXrefs] ([ContactId], [ContactTypeId]) ВЫХОД ВСТАВЛЕН.[Идентификатор], ВСТАВЛЕН.[Создан] ЗНАЧЕНИЯ (@p19, @p20); Однако вторая запись, похоже, использует некоторый временный ContactId (@p19=-2147482646) с момента создания контакта с поставщиком:

Выполнение DbCommand [Parameters=[@p19='-2147482646', @p20='0'], CommandType='Text', CommandTimeout='30'] ВЫКЛЮЧИТЬ IMPLICIT_TRANSACTIONS; УСТАНОВИТЬ NOCOUNT ON; ВСТАВИТЬ В [ContactTypeXrefs] ([ContactId], [ContactTypeId]) ВЫХОД ВСТАВЛЕН.[Идентификатор], ВСТАВЛЕН.[Создан] ЗНАЧЕНИЯ (@p19, @p20); Мне кажется, что это связано либо с тем, как я настроил тест, либо с соглашением EF, о котором я не знаю.

Есть мысли о том, почему выполнение нескольких вставок в тесте может вызвать проблемы?
Ответить Пред. темаСлед. тема

Быстрый ответ, комментарий, отзыв

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»