Ich habe eine Entität mit dem Primärschlüssel "Id", die Guid ist:
public class FileStore
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Path { get; set; }
}
Und einige Konfigurationen:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<FileStore>().Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
base.OnModelCreating(modelBuilder);
}
Wenn ich versuche, einen Datensatz einzufügen, wird folgende Fehlermeldung angezeigt:
Der Wert NULL kann nicht in die Spalte 'Id', Tabelle 'FileStore' eingefügt werden. Spalte erlaubt keine Nullen. INSERT schlägt fehl. \ R \ nDie Anweisung wurde beendet.
Ich möchte Guid nicht manuell generieren. Ich möchte nur einen Datensatz einfügen und Id
von SQL Server generiert werden. Wenn ich festlege .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
, Id
ist die Spalte in SQL Server keine Identitätsspalte.
Wie kann ich Entity Framework so konfigurieren, dass Guid in SQL Server automatisch generiert wird?
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
bevorpublic Guid ID {get; set;}
?OnModelCreating
es hier überschrieben wird.Antworten:
Zusätzlich zum Hinzufügen dieser Attribute zu Ihrer ID-Spalte:
[Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public Guid Id { get; set; }
In Ihrer Migration sollten Sie Ihre ändern
CreateTable
, um diedefaultValueSQL
Eigenschaft zu Ihrer Spalte hinzuzufügen , dh:Id = c.Guid(nullable: false, identity: true, defaultValueSql: "newsequentialid()"),
Dies verhindert, dass Sie Ihre Datenbank manuell berühren müssen, was Sie, wie Sie in den Kommentaren ausgeführt haben, mit Code First vermeiden möchten.
quelle
Id = c.Guid(nullable: false, identity: true, defaultValueSql: "newsequentialid()"),
"Versuche dies :
public class FileStore { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public Guid Id { get; set; } public string Name { get; set; } public string Path { get; set; } }
Sie können diesen SO-Beitrag überprüfen .
quelle
Sie können den Standardwert Ihrer ID in Ihrer Datenbank auf newsequentialid () oder newid () setzen. Dann sollte die Identitätskonfiguration von EF funktionieren.
quelle
Dies funktioniert für mich (kein Azure), SQL 2008 R2 auf dem Dev-Server oder localdb \ mssqllocaldb auf der lokalen Workstation. Hinweis: Die Entität fügt die Spalten Create, CreateBy, Modified, ModifiedBy und Version hinzu.
public class Carrier : Entity { public Guid Id { get; set; } public string Code { get; set; } public string Name { get; set; } }
Erstellen Sie dann eine Zuordnungskonfigurationsklasse
public class CarrierMap : EntityTypeConfiguration<Carrier> { public CarrierMap() { HasKey(p => p.Id); Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); Property(p => p.Code) .HasMaxLength(4) .IsRequired() .HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute { IsClustered = true, IsUnique = true })); Property(p => p.Name).HasMaxLength(255).IsRequired(); Property(p => p.Created).HasPrecision(7).IsRequired(); Property(p => p.Modified) .HasColumnAnnotation("IX_Modified", new IndexAnnotation(new IndexAttribute())) .HasPrecision(7) .IsRequired(); Property(p => p.CreatedBy).HasMaxLength(50).IsRequired(); Property(p => p.ModifiedBy).HasMaxLength(50).IsRequired(); Property(p => p.Version).IsRowVersion(); } }
Dadurch wird in der anfänglichen DbMigration eine Up-Methode erstellt, wenn Sie eine Add-Migration wie diese ausführen
CreateTable( "scoFreightRate.Carrier", c => new { Id = c.Guid(nullable: false, identity: true), Code = c.String(nullable: false, maxLength: 4), Name = c.String(nullable: false, maxLength: 255), Created = c.DateTimeOffset(nullable: false, precision: 7), CreatedBy = c.String(nullable: false, maxLength: 50), Modified = c.DateTimeOffset(nullable: false, precision: 7, annotations: new Dictionary<string, AnnotationValues> { { "IX_Modified", new AnnotationValues(oldValue: null, newValue: "IndexAnnotation: { }") }, }), ModifiedBy = c.String(nullable: false, maxLength: 50), Version = c.Binary(nullable: false, fixedLength: true, timestamp: true, storeType: "rowversion"), }) .PrimaryKey(t => t.Id) .Index(t => t.Code, unique: true, clustered: true);
Hinweis: Keine Sorge, dass die ID-Spalten keinen Standardwert erhalten
Führen Sie nun Update-Database aus, und Sie sollten eine Tabellendefinition in Ihrer Datenbank wie folgt erhalten:
CREATE TABLE [scoFreightRate].[Carrier] ( [Id] UNIQUEIDENTIFIER DEFAULT (newsequentialid()) NOT NULL, [Code] NVARCHAR (4) NOT NULL, [Name] NVARCHAR (255) NOT NULL, [Created] DATETIMEOFFSET (7) NOT NULL, [CreatedBy] NVARCHAR (50) NOT NULL, [Modified] DATETIMEOFFSET (7) NOT NULL, [ModifiedBy] NVARCHAR (50) NOT NULL, [Version] ROWVERSION NOT NULL, CONSTRAINT [PK_scoFreightRate.Carrier] PRIMARY KEY NONCLUSTERED ([Id] ASC) ); GO CREATE UNIQUE CLUSTERED INDEX [IX_Code] ON [scoFreightRate].[Carrier]([Code] ASC);
Hinweis: Wir haben den SqlServerMigrationSqlGenerator überschrieben, um sicherzustellen, dass der Primärschlüssel NICHT zu einem Clustered-Index wird, da wir unsere Entwickler dazu ermutigen, einen besseren Clustered-Index für Tabellen festzulegen
public class OurMigrationSqlGenerator : SqlServerMigrationSqlGenerator { protected override void Generate(AddPrimaryKeyOperation addPrimaryKeyOperation) { if (addPrimaryKeyOperation == null) throw new ArgumentNullException("addPrimaryKeyOperation"); if (!addPrimaryKeyOperation.Table.Contains("__MigrationHistory")) addPrimaryKeyOperation.IsClustered = false; base.Generate(addPrimaryKeyOperation); } protected override void Generate(CreateTableOperation createTableOperation) { if (createTableOperation == null) throw new ArgumentNullException("createTableOperation"); if (!createTableOperation.Name.Contains("__MigrationHistory")) createTableOperation.PrimaryKey.IsClustered = false; base.Generate(createTableOperation); } protected override void Generate(MoveTableOperation moveTableOperation) { if (moveTableOperation == null) throw new ArgumentNullException("moveTableOperation"); if (!moveTableOperation.CreateTableOperation.Name.Contains("__MigrationHistory")) moveTableOperation.CreateTableOperation.PrimaryKey.IsClustered = false; base.Generate(moveTableOperation); } }
quelle
Es ist mir schon mal passiert.
Wenn die Tabelle erstellt und
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
später hinzugefügt wurde , konnte die Codemigration der Guid-Spalte keinen Standardwert zuweisen.Die Reparatur:
Alles, was wir brauchen, ist, in die Datenbank zu gehen, die Spalte ID auszuwählen und
newsequentialid()
manuell hinzuzufügenDefault Value or Binding
.Die dbo .__ MigrationHistory-Tabelle muss nicht aktualisiert werden.
Ich hoffe es hilft.
Die Lösung der Zugabe
New Guid()
wird im allgemeinen nicht bevorzugt, weil in der Theorie gibt ist die Möglichkeit , dass Sie ein Duplikat aus Versehen bekommen könnten.Und Sie sollten sich keine Gedanken über die direkte Bearbeitung in der Datenbank machen. Alles, was Entity Framework tut, ist die Automatisierung eines Teils unserer Datenbankarbeit.
Übersetzen
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
in
[Id] [uniqueidentifier] NOT NULL DEFAULT newsequentialid(),
Wenn unsere EF eine Sache irgendwie übersehen hat und den Standardwert für uns nicht hinzugefügt hat, fügen Sie ihn einfach manuell hinzu.
quelle
Primary Key
Fall ist , ist es unmöglich, einen doppelten Guid-Schlüssel in diesem Feld zu haben. WeilPrimary Key
wird eine eindeutige Einschränkung haben. Der Datenbankserver lehnt doppelte Primärschlüssel ab.Demnach wird DatabaseGeneratedOption.Identity von einer bestimmten Migration nicht erkannt, wenn sie nach dem Erstellen der Tabelle hinzugefügt wird. Dies ist der Fall, auf den ich stoße. Also habe ich die Datenbank und diese spezifische Migration gelöscht und eine neue Migration hinzugefügt, schließlich die Datenbank aktualisiert, dann funktioniert alles wie erwartet. Ich verwende EF 6.1, SQL2014 und VS2013.
quelle
Entity Framework - Verwenden Sie eine Guid als Primärschlüssel
Die Verwendung eines Guid als Primärschlüssel für Ihre Tabellen erfordert bei Verwendung von Entity Framework etwas mehr Aufwand als bei Verwendung einer Ganzzahl. Der Einrichtungsprozess ist unkompliziert, nachdem Sie gelesen / gezeigt haben, wie es geht.
Der Prozess unterscheidet sich geringfügig für die Ansätze Code First und Database First. Dieser Beitrag beschreibt beide Techniken.
Geben Sie hier die Bildbeschreibung ein
Code zuerst
Die Verwendung eines Guid als Primärschlüssel bei der ersten Code-Vorgehensweise ist einfach. Fügen Sie beim Erstellen Ihrer Entität das DatabaseGenerated-Attribut wie unten gezeigt zu Ihrer Primärschlüsseleigenschaft hinzu.
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] public Guid Id { get; set; }
Das Entitätsframework erstellt die Spalte wie erwartet mit einem Primärschlüssel und einem Datentyp mit eindeutiger Kennung.
Beachten Sie auch sehr wichtig, dass der Standardwert für die Spalte auf festgelegt wurde
(newsequentialid())
. Dies erzeugt eine neue sequentielle (kontinuierliche) Guid für jede Zeile. Wenn Sie so geneigtnewid()
wären , könnten Sie dies in ) ändern , was zu einer völlig zufälligen Guid für jede neue Zeile führen würde. Dies wird jedes Mal gelöscht, wenn Ihre Datenbank gelöscht und neu erstellt wird. Dies funktioniert also besser, wenn Sie den Ansatz "Database First" verwenden.Datenbank zuerst
Der erste Datenbankansatz folgt einer ähnlichen Linie wie der erste Code-Ansatz, Sie müssen Ihr Modell jedoch manuell bearbeiten, damit es funktioniert.
Stellen Sie sicher, dass Sie die Primärschlüsselspalte bearbeiten und die Funktion (newsequentialid ()) oder (newid ()) als Standardwert hinzufügen, bevor Sie etwas tun.
Geben Sie hier die Bildbeschreibung ein
Öffnen Sie als Nächstes Ihr EDMX-Diagramm, wählen Sie die entsprechende Eigenschaft aus und öffnen Sie das Eigenschaftenfenster. Stellen Sie sicher, dass StoreGeneratedPattern auf Identität festgelegt ist.
Sie müssen Ihrer Entität keine ID in Ihrem Code geben, die automatisch für Sie ausgefüllt wird, nachdem die Entität in die Datenbank übernommen wurde.
using (ApplicationDbContext context = new ApplicationDbContext()) { var person = new Person { FirstName = "Random", LastName = "Person"; }; context.People.Add(person); context.SaveChanges(); Console.WriteLine(person.Id); }
Wichtiger Hinweis: Ihr Guid-Feld MUSS ein Primärschlüssel sein, sonst funktioniert dies nicht. Entity Framework gibt Ihnen eine ziemlich kryptische Fehlermeldung!
Zusammenfassung
Guid (Global Unique Identifiers) kann problemlos als Primärschlüssel in Entity Framework verwendet werden. Je nachdem, welchen Ansatz Sie wählen, ist ein wenig zusätzlicher Aufwand erforderlich. Wenn Sie den Code First-Ansatz verwenden, fügen Sie Ihrem Schlüsselfeld das Attribut DatabaseGenerated hinzu. Setzen Sie beim Ansatz "Database First" das StoredGeneratedPattern in Ihrem Modell explizit auf "Identität".
[1]: https://i.stack.imgur.com/IxGdd.png [2]: https://i.stack.imgur.com/Qssea.png
quelle
Wenn Sie Code-First ausführen und bereits eine Datenbank haben:
public override void Up() { AlterColumn("dbo.MyTable","Id", c => c.Guid(nullable: false, identity: true, defaultValueSql: "newsequentialid()")); }
quelle
Du kannst nicht. Sie werden / tun eine Menge Dinge zu brechen. Wie Beziehungen. Dies hängt davon ab, dass die Nummer zurückgezogen wird, was EF nicht so tun kann, wie Sie es eingerichtet haben. Der Preis für das Brechen jedes Musters, das es gibt.
Generieren Sie die GUID in der C # -Ebene, damit die Beziehungen weiter funktionieren können.
quelle
Und was ist so etwas?
public class Carrier : Entity { public Carrier() { this.Id = Guid.NewGuid(); } public Guid Id { get; set; } public string Code { get; set; } public string Name { get; set; } }
quelle