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:
- Guid jest automatycznie generowany przez bazę danych, a nie kod
-
ClusterId
jest autoinkremowane - 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();
}
}
1 answers
To skończyło się dla mnie, Entity Framework 5.
- wyłącz automatyczne migracje
- migruj, aby utworzyć tabelę początkową, bez zbędnych dodatków
-
Declare the
ClusterId
as Identity (annotation)[DatabaseGenerated(DatabaseGeneratedOption.Identity)] public override int ClusterId { get; set; }
-
Migrate
-
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]
-
bonus : EF wydaje się zakładać
Tworzenie kodu migracji jak
add-migration TrickEfIntoAutogeneratingMultipleColumns
- w metodzie
Up()
, w instrukcjiAlterColumn
, powiedz bazie danych, aby autogenizowała GUID, deklarującdefaultSqlValue
AlterColumn(theTable, "Id", c => c.Guid(nullable: false, identity: true, defaultValueSql: "newid()"));
- 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ą.
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