Когда я сохраняю сущность с помощью структуры сущностей, я, естественно, предполагал, что она попытается сохранить только указанную сущность. Однако он также пытается сохранить дочерние сущности этой сущности. Это вызывает всевозможные проблемы с целостностью. Как заставить EF сохранять только тот объект, который я хочу сохранить, и, следовательно, игнорировать все дочерние объекты?
Если я вручную установил для свойств значение null, я получаю сообщение об ошибке «Операция завершилась неудачно: связь не может быть изменена, поскольку одно или несколько свойств внешнего ключа не допускают значения NULL». Это крайне контрпродуктивно, поскольку я специально установил для дочернего объекта значение null, чтобы EF оставил его в покое.
Почему я не хочу сохранять / вставлять дочерние объекты?
Поскольку это обсуждается в комментариях, я дам некоторое обоснование того, почему я хочу, чтобы мои дочерние объекты оставались в покое.
В приложении, которое я создаю, объектная модель EF не загружается из базы данных, а используется в качестве объектов данных, которые я заполняю при анализе плоского файла. В случае дочерних объектов многие из них относятся к таблицам поиска, определяющим различные свойства родительской таблицы. Например, географическое положение основного объекта.
Поскольку я сам заполнил эти объекты, EF предполагает, что это новые объекты, которые необходимо вставить вместе с родительским объектом. Однако эти определения уже существуют, и я не хочу создавать дубликаты в базе данных. Я использую объект EF только для поиска и заполнения внешнего ключа в моей основной таблице.
Даже с дочерними объектами, которые являются реальными данными, мне нужно сначала сохранить родительский и получить первичный ключ, иначе EF просто напутает. Надеюсь, это даст какое-то объяснение.
источник
Ответы:
Насколько я знаю, у вас есть два варианта.
Опция 1)
Обнулить все дочерние объекты, это гарантирует, что EF ничего не добавит. Он также ничего не удалит из вашей базы данных.
Вариант 2)
Установите дочерние объекты как отделенные от контекста, используя следующий код
Обратите внимание, что вы не можете отсоединить
List
/Collection
. Вам нужно будет перебрать ваш список и отсоединить каждый элемент в вашем списке вот такисточник
Короче говоря: используйте внешний ключ, и это спасет вас.
Предположим, у вас есть сущность « Школа» и сущность « Город» , и это отношение «многие к одному», в котором в городе много школ, а школа принадлежит городу. Предположим, что города уже существуют в таблице поиска, поэтому вы НЕ хотите, чтобы они снова вставлялись при вставке новой школы.
Первоначально вы можете определять свои сущности следующим образом:
И вы можете сделать вставку School следующим образом (предположим, что у вас уже есть свойство City, назначенное для newItem ):
Вышеупомянутый подход может отлично работать в этом случае, однако я предпочитаю подход с использованием внешнего ключа, который для меня более ясен и гибок. См. Обновленное решение ниже:
Таким образом, вы явно определяете, что школа имеет внешний ключ City_Id, и он относится к объекту City . Итак, когда дело доходит до вставки школы , вы можете:
В этом случае вы явно указываете City_Id новой записи и удаляете город из графика, чтобы EF не потрудился добавить его в контекст вместе со школой .
Хотя на первый взгляд подход с использованием внешнего ключа кажется более сложным, но поверьте мне, такой подход сэкономит вам много времени, когда дело доходит до вставки отношения многие-ко-многим (представляя, что у вас есть отношения между школой и учеником, и ученик имеет свойство City) и так далее.
Надеюсь, это поможет вам.
источник
[Range(1, int.MaxValue)]
атрибута?Если вы просто хотите сохранить изменения в родительском объекте и не сохранять изменения в любом из его дочерних объектов, то почему бы просто не сделать следующее:
Первая строка присоединяет родительский объект и весь граф его зависимых дочерних объектов к контексту в
Unchanged
состоянии.Вторая строка изменяет состояние только для родительского объекта, оставляя его дочерние элементы в этом
Unchanged
состоянии.Обратите внимание, что я использую только что созданный контекст, чтобы избежать сохранения любых других изменений в базе данных.
источник
Одно из предлагаемых решений - назначить свойство навигации из того же контекста базы данных. В этом решении свойство навигации, назначенное извне контекста базы данных, будет заменено. См. Следующий пример для иллюстрации.
Сохранение в базу данных:
Microsoft считает это функцией, но меня это раздражает. Если объект отдела, связанный с объектом компании, имеет идентификатор, который уже существует в базе данных, то почему EF просто не связывает объект компании с объектом базы данных? Почему мы должны сами заботиться об ассоциации? Забота о свойстве навигации при добавлении нового объекта - это что-то вроде переноса операций с базой данных с SQL на C #, что неудобно для разработчиков.
источник
Для начала вам нужно знать, что есть два способа обновить сущность в EF.
В приложении, которое я создаю, объектная модель EF не загружается из базы данных, а используется в качестве объектов данных, которые я заполняю при анализе плоского файла.
Это означает, что вы работаете с отключенным объектом, но неясно, используете ли вы независимую ассоциацию или ассоциацию внешнего ключа .
Добавить
При добавлении новой сущности к существующему дочернему объекту (объект, который существует в базе данных), если дочерний объект не отслеживается EF, дочерний объект будет повторно вставлен. Если вы сначала вручную не прикрепите дочерний объект.
Обновить
Вы можете просто пометить объект как измененный, тогда все скалярные свойства будут обновлены, а свойства навигации будут просто проигнорированы.
График Diff
Если вы хотите упростить код при работе с отключенным объектом, вы можете попробовать построить графическую библиотеку различий .
Вот введение, Знакомство с GraphDiff для Entity Framework Code First - Разрешение автоматического обновления графа отсоединенных сущностей .
Образец кода
Вставьте объект, если он не существует, в противном случае обновите.
Вставьте объект, если он не существует, в противном случае обновите И вставьте дочерний объект, если он не существует, в противном случае обновите.
источник
Лучший способ сделать это - переопределить функцию SaveChanges в вашем тексте данных.
источник
У меня такая же проблема, когда я пытаюсь сохранить профиль, я уже привожу приветствие и новый для создания профиля. Когда я вставляю профиль, он также вставляется в приветствие. Итак, я пробовал это до savechanges ().
db.Entry (Профиль.Salutation) .State = EntityState.Unchanged;
источник
Это сработало для меня:
источник
Что мы сделали, так это перед добавлением родительской коллекции к dbset отключили дочерние коллекции от родительской, убедившись, что существующие коллекции перешли в другие переменные, чтобы можно было работать с ними позже, а затем заменили текущие дочерние коллекции новыми пустыми коллекциями. Установка дочерних коллекций на null / ничего нам показалась неудачной. После этого добавьте родителя в dbset. Таким образом, дети не добавляются до тех пор, пока вы этого не захотите.
источник
Я знаю, что это старый пост, однако, если вы используете подход, ориентированный на код, вы можете достичь желаемого результата, используя следующий код в вашем файле сопоставления.
По сути, это укажет EF исключить свойство ChildObjectOrCollection из модели, чтобы оно не было сопоставлено с базой данных.
источник
У меня была аналогичная проблема с использованием Entity Framework Core 3.1.0, моя логика репо довольно общая.
Это сработало для меня:
Обратите внимание, что «ParentEntityId» - это имя столбца внешнего ключа дочерней сущности. Я добавил вышеупомянутую строку кода к этому методу:
источник