Код структуры Entity Framework Сначала используйте Guid как идентификатор с другой колонкой Identity

a.k.a Как мы можем создать несколько столбцов идентификации в Code First?

Из-за производительности кластеров, общая рекомендация состоит в том, чтобы использовать столбец с автоинкрементным целым числом вместо GUID, созданного с помощью newid().

Чтобы объявить столбец как автоинкремент, вы должны указать его с помощью аннотации [DatabaseGenerated(DatabaseGeneratedOption.Identity)].

Но вы можете иметь только одно удостоверение в таблице.

Итак, начиная с базовой модели, например:

public abstract class ModelBase {
    // the primary key
    public virtual Guid Id { get; set; }

    // a unique autoincrementing key
    public virtual int ClusterId { get; set; }
}

как мы настроим его так, чтобы:

  • Гид автоматически создается базой данных, а не кодом
  • ClusterId автоинкрементно
  • Код элемента Entity Framework Сначала не выбрасываются всевозможные ошибки, например:
    • Модификации таблиц, в которых столбец первичного ключа имеет свойство "StoreGeneratedPattern", установленное в "Computed", не поддерживается. Вместо этого используйте шаблон "Идентификация".

FYI, если вы хотите автоматически сгенерировать его в коде, вы можете пропустить аннотацию в поле Id и сделать что-то вроде:

public abstract class AbstractContext : DbContext {

  /// <summary>
  /// Custom processing when saving entities in changetracker
  /// </summary>
  /// <returns></returns>
  public override int SaveChanges()
  {
      // recommended to explicitly set New Guid for appropriate entities -- http://msdn.microsoft.com/en-us/library/dd283139.aspx
      foreach (var entry in ChangeTracker.Entries<ModelBase>().Where(e => e.State == EntityState.Added) ) {

          // only generate if property isn't identity...
          Type t = entry.Entity.GetType();
          var info = t.GetProperty("Id").GetCustomAttributes(
              typeof(DatabaseGeneratedAttribute), true).Cast<DatabaseGeneratedAttribute>().Single();

          if (info.DatabaseGeneratedOption != DatabaseGeneratedOption.Identity) {
              entry.Entity.Id = Guid.NewGuid(); // now we make it
          }
      }
      return base.SaveChanges();
  }

}

Ответ 1

Это закончилось для меня, Entity Framework 5.

  • Отключить автоматические миграции
  • Перенесите, чтобы создать начальную таблицу, без излишеств.
  • Объявить ClusterId как идентификатор (аннотация)

    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public override int ClusterId { get; set; }
    
  • Перенести

  • Объявить свойство pk Id как идентификатор после того, как он был обновлен

    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public override Guid Id { get; set; }
    
    • bonus: EF, похоже, предполагает, что Id является первичным ключом, поэтому вам не нужно [Key, Required]
  • Создайте код миграции, например add-migration TrickEfIntoAutogeneratingMultipleColumns

  • В методе Up() в операторе AlterColumn сообщите базе данных, чтобы автогенерировать GUID, объявив defaultSqlValue
    • AlterColumn(theTable, "Id", c => c.Guid(nullable: false, identity: true, defaultValueSql: "newid()"));
  • Перенести

Это кажется "трюком" EF, в том смысле, что он предполагает, что оба столбца являются тождествами и реагируют соответственно. Во время миграции он пытается сделать еще один столбец личным, но, похоже, ему все равно, когда это тихо провалится - вы попадаете в один знак с именем Identity, а другой со значением по умолчанию.

Во время нормальной работы кода, когда EF проходит шаги SaveChanges/ChangeTracking, поскольку он видит свойство Id как идентификатор, он делает это целым "assign временного ключа" , чтобы он не пытался использовать значение по умолчанию 0000000..., а вместо этого позволяет генерировать базу данных, используя указанную вами функцию значения по умолчанию.

(я бы подумал, что аннотировать это поле как Computed выполнил бы то же самое, но... ошибки, о которых я упоминал в вопросе... boo...)

И поскольку поле ClusterId также является идентификатором в коде и действительно является идентификатором в базе данных, оно также автоматически создается.