Entity Framework вставка сущности дважды в двух разных контекстах - PullRequest
0 голосов
/ 12 декабря 2018

Я использую Entity Framework Core для хранения графа объектов в базе данных.В разное время, пока я строю график, я создаю сущность, сохраняю ее в базе данных и высвобождаю контекст.Однако я сталкиваюсь с проблемой, когда EFC пытается вставить объект, который уже был вставлен, когда он подключен к новому объекту.Это лучше всего объяснить с помощью кода.Вот небольшой фрагмент кода (это прямой код, но два использования контекстов происходят в разное время и в разных местах кода).

Во втором вызове context.SaveChanges() я получаю следующееисключение:

SqlException:

Невозможно вставить явное значение для столбца идентификаторов в таблице 'Пространство имен', когда для IDENTITY_INSERT установлено значение OFF.

Когда я смотрюво время выполнения SQL он пытается снова вставить сущность пространства имен, возможно потому, что myType сохраняется в БД и имеет ссылку на сущность dbNamespace.

// see if namespace is in the db and add it if not
string someNamespaceString = "foobar";
CodeDatabase.Models.Namespace dbNamespace;
using (var context = new CodeFactsContext())
{
    dbNamespace = context.Namespace.FirstOrDefault(ns => ns.Namespace1 == someNamespaceString);
    if (dbNamespace == null)
    {
        dbNamespace = new Namespace() { Namespace1 = someNamespaceString };
        context.Namespace.Add(dbNamespace);
    }
    context.SaveChanges();
}

// Type entity created somewhere from the code
var myType = new CodeDatabase.Models.Type()
{
    FullName = "foobar.mytype",
    ShortName = "mytype",
    Namespace = dbNamespace // this is already in the DB
};

// check if myType is in the db and add it if not
using (var context = new CodeFactsContext())
{
    var dbType = context.Type.FirstOrDefault(t => t.FullName == myType.FullName);
    if (dbType == null)
    {
        dbType = myType;
        context.Add(dbType);
    }
    context.SaveChanges(); // throws exception
}

Любая идея, какзаставить EF Core распознать (во втором context.SaveChanges()), что myType должен быть вставлен в базу данных, а myType.Namespace не должен, потому что он уже там?Обе сущности имеют внутренний идентификатор, который автоматически генерируется БД, а идентификатор пространства имен устанавливается равным значению базы данных после первого вызова SaveChanges.Я думал, что EF Core распознает, что идентификатор не равен 0, и не попытается его сохранить.Любая помощь / предложения очень приветствуются.

1 Ответ

0 голосов
/ 12 декабря 2018

Я думал, что EFC распознает, что идентификатор не равен 0, и не попытается его сохранить.

Проблема в том, что вы используете метод Add, который отмечает все достижимые, а неотслеживаемые объекты как новые, независимо от значения ключа (это позволяет использовать сценарии вставки идентификаторов).Это объясняется в Отключенные объекты - Работа с графиками - Все новые / все существующие объекты .Пока ваш сценарий попадает в Сочетание новых и существующих сущностей .

Любая идея, как заставить EFC распознать (во втором context.SaveChanges), что myType следует вставитьв базу данных, но myType.Namespace не должен, потому что он уже там?Обе сущности имеют идентификатор int, который автоматически генерируется БД, а идентификатор пространства имен устанавливается равным значению базы данных после первого вызова SaveChanges.

На самом деле существует простойРешение, объясненное во второй ссылке на документацию:

С автоматически сгенерированными ключами, обновление можно снова использовать как для вставок, так и для обновлений, даже если график содержит смесь сущностей, которые требуют вставки, и тех, которые требуютОбновление

, где «снова» относится к Сохранение отдельных объектов :

Метод Update обычно помечает объект для обновления, а не для вставки.Однако, если у сущности есть автоматически сгенерированный ключ, и значение ключа не было установлено, тогда сущность вместо этого автоматически помечается для вставки.

К счастью, ваши сущности используют автоматически сгенерированные ключи, поэтому простоиспользуйте Update вместо Add:

if (dbType == null)
{
    dbType = myType;
    context.Update(dbType); // <--
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...