Вставка идентификатора только для исходных данных с EF Code-First Migrations - PullRequest
0 голосов
/ 17 сентября 2018

В настоящее время я пытаюсь внести некоторые локальные данные в базу данных, работая с зеркалами EF Code-First. Эти данные уже имеют уникальный идентификатор, поэтому изначально первый «набор» данных должен быть вставлен как есть.

Теперь я подумываю установить «DatabaseGeneratedOption.None», добавьте набор данных в базу данных, вычислите последний использованный идентификатор, выполните повторное заполнение с помощью команды T-SQL 'dbcc checkident (tablename, reseed, [NEW AUTO ID])' а затем добавьте еще одну миграцию, сбросив GeneratedOption в DatabaseGeneratedOption.Identity.

Это правильный подход и / или даже возможен ли я или я не на том пути?

Любые выводы будут оценены
С наилучшими пожеланиями

РЕДАКТИРОВАТЬ - Михалс ответ

Пытался реализовать ответ Михалса, но идентификаторы все еще «генерируются» базой данных, а мои явные значения игнорируются. Может быть, это способ, которым я вставляю значения:

MyDbContext context = // GetContext;
DbSet<SomeClass> dbSet = context.SomeClass;
context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT " + someClassTableName + " ON");

foreach(SomeClass sc in toAdd)
{
    // sc already contains all data including its unique ID
    sbSet.Add(sc);
}

context.SaveChanges();
context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT " + someClassTableName + " OFF");

Решение / w Михалса ответы

Ну, Я изо всех сил старался реализовать ответ Михалса различными способами и, наконец, пришел к (действительно странному) решению.

Во-первых, у меня есть мой класс DBContext и, следовательно, класс Dervied с именем DBContextEditor. То, что это делает, - ничто иное, как переопределение OnModelCreating, где я изменяю все свойства «Идентичность».

public class MyContextEditor : MyContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<SomeClass>()
        .Property(e => e.ID)
        .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
    }
}

Использование этого класса в сочетании с некоторыми другими приемами из других постов (см. Источники ниже), наконец, дало мне результат, который я искал.
Наконец-то у меня было что-то вроде этого:

MyContext context = new MyContextEditor();
DbSet<SomeClass> dataSet = context.SomeClass;

// this.Clear(dataSet); Just for testing to reset Identity Auto ID and remove all Data
// this.Reset(dataSet);

context.Database.Connection.Open();
// Add data to dataSet...
// dataSet.Add(toAdd);
// Apply Michals answer and save
context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT " + tableName + " ON");
context.SaveChanges();
context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT " + tableName + " OFF");

// Close Connection
context.Database.Connection.Close();

Я также попытался реализовать переопределение в классе MyContext, который завершился ошибкой, в которой говорилось: «Модель выпечки отличается ...», что также изменило свойство ID на «идентичность».

Наконец, этот подход дал мне желаемый контроль над добавлением Идентификационных данных, сохраняя при этом возможность генерировать значения идентификаторов. Кроме того, любая дальнейшая миграция не меняет модель и не удаляет флаг «Идентичность», тогда как [DatabaseGeneratedOption] его удалял. Также возможно и рекомендуется хранить это в таком виде:

using( var transaction = context.Database.BeginTransaction'))

Только для справки Модель в псевдокоде

class SomeClass
{
    [Key]
    public int ID { get; set; }

    public string Title { get; set; }
    // More Properties
}

Похожие сообщения и источники

1 Ответ

0 голосов
/ 17 сентября 2018

Что я лично делаю, так это:

  1. SET IDENTITY_INSERT sometableWithIdentity ON
  2. Семя Все данные
  3. SET IDENTITY_INSERT sometableWithIdentity OFF.

При заполнении данных я присоединяю все сущности к контексту в том виде, в каком они были добавлены как существующие ранее идентификаторы.

Иногда возникает проблема, если есть циклическая ссылка на внешний ключ. Чтобы обойти, я убираю одну из сторон Внешних ключей, добавляю все сущности и возвращаю внешние ключи.

например. Если у меня есть следующее:

public class Customer 
{
    public List<Address> Addresses { get; set; }

    public long? DefaultAddressId { get; set; }
    public Address DefaultAddress { get; set; }
}

public class Customer 
{
    public long Id { get; set; }

    public long CustomerId { get; set; }
    public Customer Customer { get; set; }
}

Я бы сделал что-то вроде следующего:

  1. Вставить Customer.DefaultAddressId
  2. Присоединить Customer + Address как EntityState.New
  3. Context.SaveChanges() для сохранения в БД
  4. Повторно прикрепить Customer.DefaultAddressId к отслеживаемому клиенту с шага 2
  5. Context.SaveChanges() для сохранения идентификатора адреса по умолчанию

Другой вариант - отключить ссылочную целостность во время заполнения, если это возможно. Но так как мы используем несколько баз данных (Sqlite для локального разработчика, PostegreSql для prod, а иногда и MariaDb), мы не смогли успешно отключить его + включить снова + принудительно проверить наличие ссылочной целостности /

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...