Frage
Ist es möglich, eine eindeutige Einschränkung für eine Eigenschaft mithilfe der fließenden Syntax oder eines Attributs zu definieren? Wenn nicht, wie lauten die Problemumgehungen?
Ich habe eine Benutzerklasse mit einem Primärschlüssel, möchte aber sicherstellen, dass die E-Mail-Adresse auch eindeutig ist. Ist dies möglich, ohne die Datenbank direkt zu bearbeiten?
Lösung (basierend auf Matts Antwort)
public class MyContext : DbContext {
public DbSet<User> Users { get; set; }
public override int SaveChanges() {
foreach (var item in ChangeTracker.Entries<IModel>())
item.Entity.Modified = DateTime.Now;
return base.SaveChanges();
}
public class Initializer : IDatabaseInitializer<MyContext> {
public void InitializeDatabase(MyContext context) {
if (context.Database.Exists() && !context.Database.CompatibleWithModel(false))
context.Database.Delete();
if (!context.Database.Exists()) {
context.Database.Create();
context.Database.ExecuteSqlCommand("alter table Users add constraint UniqueUserEmail unique (Email)");
}
}
}
}
ObjectContext
oder abDbContext
.Antworten:
Soweit ich das beurteilen kann, gibt es derzeit mit Entity Framework keine Möglichkeit, dies zu tun. Dies ist jedoch nicht nur ein Problem mit eindeutigen Einschränkungen. Möglicherweise möchten Sie Indizes erstellen, Einschränkungen überprüfen und möglicherweise auch Trigger und andere Konstrukte. Hier ist ein einfaches Muster, das Sie mit Ihrem Code-First-Setup verwenden können, obwohl es zugegebenermaßen nicht datenbankunabhängig ist:
Eine andere Option ist, wenn Ihr Domänenmodell die einzige Methode zum Einfügen / Aktualisieren von Daten in Ihre Datenbank ist, können Sie die Eindeutigkeitsanforderung selbst implementieren und die Datenbank aus dieser Datenbank herauslassen. Dies ist eine portablere Lösung und zwingt Sie dazu, Ihre Geschäftsregeln in Ihrem Code klar zu definieren, lässt Ihre Datenbank jedoch offen, damit ungültige Daten rückgängig gemacht werden.
quelle
SaveChanges()
), aber es besteht immer noch die Möglichkeit, dass zwischen dem Zeitpunkt der Eindeutigkeitsprüfung und dem Zeitpunkt von ein weiteres Einfügen / Aktualisieren abrutschtSaveChanges()
. Abhängig davon, wie geschäftskritisch die App ist und wie wahrscheinlich eine Verletzung der Eindeutigkeit ist, ist es wahrscheinlich am besten, die Einschränkung zur Datenbank hinzuzufügen.serializable isolation level
(oder benutzerdefinierte Tabellensperre, ugh) würde es Ihnen tatsächlich ermöglichen, die Eindeutigkeit Ihres Codes zu gewährleisten. Aber die meisten Leute benutzen dasserializable isolation level
aus Leistungsgründen nicht. Der Standardwert in MS SQL Server istread committed
. Siehe die 4-teilige Serie ab: michaeljswart.com/2010/03/…Ab EF 6.1 ist es nun möglich:
Auf diese Weise erhalten Sie streng genommen einen eindeutigen Index anstelle einer eindeutigen Einschränkung. Für die meisten praktischen Zwecke sind sie gleich .
quelle
Nicht wirklich damit verbunden, aber es könnte in einigen Fällen helfen.
Wenn Sie einen eindeutigen zusammengesetzten Index für beispielsweise zwei Spalten erstellen möchten, die als Einschränkung für Ihre Tabelle dienen, können Sie ab Version 4.3 den neuen Migrationsmechanismus verwenden, um dies zu erreichen:
Grundsätzlich müssen Sie einen solchen Aufruf in eines Ihrer Migrationsskripte einfügen:
Sowas in der Art:
quelle
DropIndex("TableName", new[] { "Column1", "Column2" });
Ich mache einen vollständigen Hack, um SQL auszuführen, wenn die Datenbank erstellt wird. Ich erstelle meinen eigenen DatabaseInitializer und erbe von einem der bereitgestellten Initialisierer.
Dies ist der einzige Ort, an dem ich meine SQL-Anweisungen einklemmen kann.
Dies ist von CTP4. Ich weiß nicht, wie es in CTP5 funktioniert.
quelle
Ich habe nur versucht herauszufinden, ob es eine Möglichkeit gibt, dies zu tun. Bisher habe ich es nur selbst durchgesetzt. Ich habe ein Attribut erstellt, das jeder Klasse hinzugefügt wird, in der Sie den Namen der Felder angeben, die eindeutig sein müssen:
Dann werde ich es in meiner Klasse hinzufügen:
Schließlich füge ich eine Methode in mein Repository ein, in die Add-Methode oder beim Speichern von Änderungen wie folgt:
Nicht allzu schön, da wir uns auf Reflexion verlassen müssen, aber dies ist der Ansatz, der für mich funktioniert! = D.
quelle
Auch in 6.1 können Sie die fließende Syntaxversion von @ mihkelmuurs Antwort wie folgt verwenden:
Die fließende Methode ist IMO nicht perfekt, aber zumindest jetzt möglich.
Weitere Details auf Arthur Vickers Blog http://blog.oneunicorn.com/2014/02/15/ef-6-1-creating-indexes-with-indexattribute/
quelle
Ein einfacher Weg in Visual Basic mit EF5 Code First Migrations
Public Class Sample
Klasse beenden
Das Attribut MaxLength ist sehr wichtig für einen eindeutigen Index des Zeichenfolgentyps
Führen Sie cmd: update-database -verbose aus
Nach dem Ausführen von cmd: add-migration 1
in der generierten Datei
quelle
Ähnlich wie Tobias Schittkowskis Antwort, aber C # und hat die Fähigkeit, mehrere Felder in den Constrtaints zu haben.
Um dies zu verwenden, platzieren Sie einfach ein [Einzigartig] auf einem beliebigen Feld, das Sie eindeutig sein möchten. Für Zeichenfolgen müssen Sie Folgendes tun (beachten Sie das MaxLength-Attribut):
weil das Standardzeichenfolgenfeld nvarchar (max) ist und dies in einem Schlüssel nicht zulässig ist.
Für mehrere Felder in der Einschränkung können Sie Folgendes tun:
Erstens das UniqueAttribute:
Fügen Sie dann eine nützliche Erweiterung hinzu, um den Namen der Datenbanktabelle von einem Typ abzurufen:
Dann der Datenbankinitialisierer:
quelle
Ich habe das Problem durch Nachdenken gelöst (sorry, Leute, VB.Net ...)
Definieren Sie zunächst ein Attribut UniqueAttribute:
Dann verbessern Sie Ihr Modell wie
Erstellen Sie abschließend einen benutzerdefinierten DatabaseInitializer (In meiner Version erstelle ich die DB bei DB-Änderungen nur im Debug-Modus neu ...). In diesem DatabaseInitializer werden die Indizes automatisch basierend auf den eindeutigen Attributen erstellt:
Vielleicht hilft das ...
quelle
Wenn Sie die ValidateEntity-Methode in Ihrer DbContext-Klasse überschreiben, können Sie die Logik auch dort ablegen. Der Vorteil hierbei ist, dass Sie vollen Zugriff auf alle Ihre DbSets haben. Hier ist ein Beispiel:
quelle
Wenn Sie EF5 verwenden und diese Frage immer noch haben, hat die folgende Lösung sie für mich gelöst.
Ich verwende den Code First-Ansatz und setze daher Folgendes ein:
im Migrationsskript hat die Arbeit gut gemacht. Es erlaubt auch NULL-Werte!
quelle
Mit dem EF Code First-Ansatz kann die Unterstützung von Attribut-basierten eindeutigen Einschränkungen mithilfe der folgenden Technik implementiert werden.
Erstellen Sie ein Markerattribut
Markieren Sie Eigenschaften, die für Entitäten eindeutig sein sollen, z
Erstellen Sie einen Datenbankinitialisierer oder verwenden Sie einen vorhandenen, um die eindeutigen Einschränkungen zu erstellen
Stellen Sie Ihren Datenbankkontext so ein, dass dieser Initialisierer im Startcode verwendet wird (z. B. in
main()
oderApplication_Start()
).Die Lösung ähnelt der von mheyman, mit der Vereinfachung, dass zusammengesetzte Schlüssel nicht unterstützt werden. Zur Verwendung mit EF 5.0+.
quelle
Fließende Api-Lösung:
quelle
Ich habe mich heute diesem Problem gestellt und konnte es endlich lösen. Ich weiß nicht, ob es ein richtiger Ansatz ist, aber zumindest kann ich weitermachen:
quelle
Verwenden Sie einen eindeutigen Eigenschaftsprüfer.
ValidateEntity
wird nicht innerhalb derselben Datenbanktransaktion aufgerufen. Daher kann es zu Rennbedingungen mit anderen Entitäten in der Datenbank kommen. Sie müssen EF etwas hacken, um eine Transaktion um dasSaveChanges
(und daherValidateEntity
) zu erzwingen .DBContext
kann die Verbindung nicht direkt öffnen,ObjectContext
kann aber .quelle
Laut http://blogs.msdn.com/b/adonet/archive/2014/02/11/ef-6-1-0-beta-1-available.aspx verfügt EF 6.1 über ein IndexAttribute, das uns hilft .
quelle
Nachdem ich diese Frage gelesen hatte, hatte ich meine eigene Frage beim Versuch, ein Attribut zum Festlegen von Eigenschaften als eindeutige Schlüssel zu implementieren, wie die Antworten von Mihkel Müür , Tobias Schittkowski und mheyman : Zuordnen von Entity Framework-Codeeigenschaften zu Datenbankspalten (CSpace to SSpace)
Endlich bin ich zu dieser Antwort gekommen, die sowohl Skalar- als auch Navigationseigenschaften auf Datenbankspalten abbilden und einen eindeutigen Index in einer bestimmten Reihenfolge erstellen kann, die für das Attribut festgelegt ist. In diesem Code wird davon ausgegangen, dass Sie ein UniqueAttribute mit einer Sequence-Eigenschaft implementiert und auf EF-Entitätsklasseneigenschaften angewendet haben, die den eindeutigen Schlüssel der Entität (außer dem Primärschlüssel) darstellen sollen.
Hinweis: Dieser Code basiert auf EF Version 6.1 (oder höher), die
EntityContainerMapping
in früheren Versionen nicht verfügbar ist.quelle
Für Benutzer, die Code-First-Konfigurationen verwenden, können Sie das IndexAttribute-Objekt auch als ColumnAnnotation verwenden und seine IsUnique-Eigenschaft auf true setzen.
Zum Beispiel:
Dadurch wird ein eindeutiger Index mit dem Namen IX_name in der Spalte Name erstellt.
quelle
Entschuldigung für die späte Antwort, aber ich fand es gut, sie mit dir zu teilen
Ich habe darüber bei Code Project gepostet
Im Allgemeinen hängt es von den Attributen ab, die Sie den Klassen zuweisen, um Ihre eindeutigen Indizes zu generieren
quelle