Kod ramki encji najpierw wykorzystujący Guid jako tożsamość z inną kolumną tożsamości

aka Jak możemy najpierw utworzyć wiele kolumn tożsamości w kodzie?

Ze względu na wydajność klastrowania, powszechną rekomendacją jest użycie autoinkremowanej kolumny całkowitej zamiast GUID utworzonego za pomocą newid().

Aby zadeklarować kolumnę jako autoincrement, musisz podać ją adnotacją [DatabaseGenerated(DatabaseGeneratedOption.Identity)].

Ale w tabeli można mieć tylko jedną tożsamość.

Więc zaczynając od modelu bazowego jak:

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

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

Jak to skonfigurować tak że:

  1. Guid jest automatycznie generowany przez bazę danych, a nie kod
  2. ClusterId jest autoinkremowane
  3. Entity Framework Code First nie wyrzuca wszelkiego rodzaju błędów, takich jak:
    • Modyfikacje tabel, w których kolumna klucza głównego ma właściwość 'StoreGeneratedPattern' ustawioną na 'Computed' nie są obsługiwane. Zamiast tego użyj wzorca "tożsamość".

FYI , jeśli chcesz automatycznie wygenerować go w kodzie, możesz pominąć adnotację w polu Id i zrobić coś w stylu:

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();
  }

}
Author: drzaus, 2012-08-18

1 answers

To skończyło się dla mnie, Entity Framework 5.

  1. wyłącz automatyczne migracje
  2. migruj, aby utworzyć tabelę początkową, bez zbędnych dodatków
  3. Declare the ClusterId as Identity (annotation)

    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public override int ClusterId { get; set; }
    
  4. Migrate

  5. Zadeklaruj właściwość pk Id jako tożsamość Po zaktualizowaniu drugiej

    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public override Guid Id { get; set; }
    
    • bonus : EF wydaje się zakładać Id jest kluczem podstawowym, więc nie potrzebujesz [Key, Required]
  6. Tworzenie kodu migracji jak add-migration TrickEfIntoAutogeneratingMultipleColumns

  7. w metodzie Up(), w instrukcji AlterColumn, powiedz bazie danych, aby autogenizowała GUID, deklarując defaultSqlValue
    • AlterColumn(theTable, "Id", c => c.Guid(nullable: false, identity: true, defaultValueSql: "newid()"));
  8. Migrate

Wydaje się to" oszukiwać " EF, w tym sensie, że zakłada, że obie kolumny są tożsamościami i odpowiednio reaguje. Podczas migracji stara się, aby inna kolumna stała się tożsamością, ale pozornie nie obchodzi go, kiedy to po cichu nie powiedzie się-kończy się z jednym oznaczonym jako tożsamość, a drugim z wartością domyślną.

Podczas normalnego działania kodu, gdy EF przechodzi przez kroki SaveChanges/ChangeTracking, ponieważ widzi właściwość Id jako tożsamość, robi to w całości " Przypisz klucz tymczasowy " , więc nie próbuje użyć domyślnego 0000000... wartość, a zamiast tego pozwala bazie danych wygenerować go za pomocą domyślnej funkcji wartości, którą podałeś.

(pomyślałbym przypisanie tego pola jako Computed osiągnęłoby to samo, ale...Błędy, o których wspomniałem w pytaniu...boo...)

I, ponieważ pole ClusterId jest również tożsamością w kodzie, a tak naprawdę jest tożsamością w bazie danych, jest również autoinkrementacją.

 36
Author: drzaus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-31 16:50:14