Question
Est-il possible de définir une contrainte unique sur une propriété en utilisant soit la syntaxe fluide, soit un attribut? Sinon, quelles sont les solutions de contournement?
J'ai une classe d'utilisateurs avec une clé primaire, mais je voudrais m'assurer que l'adresse e-mail est également unique. Est-ce possible sans modifier directement la base de données?
Solution (basée sur la réponse de Matt)
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
ouDbContext
.Réponses:
Pour autant que je sache, il n'y a aucun moyen de le faire avec Entity Framework pour le moment. Cependant, ce n'est pas seulement un problème avec des contraintes uniques ... vous voudrez peut-être créer des index, vérifier des contraintes et éventuellement des déclencheurs et d'autres constructions. Voici un modèle simple que vous pouvez utiliser avec votre configuration code-first, bien qu'il ne soit certes pas indépendant de la base de données:
Une autre option est que si votre modèle de domaine est la seule méthode d'insertion / mise à jour de données dans votre base de données, vous pouvez implémenter vous-même l'exigence d'unicité et laisser la base de données en dehors. Il s'agit d'une solution plus portable et vous oblige à être clair sur vos règles métier dans votre code, mais laisse votre base de données ouverte aux données non valides qui sont back-doored.
la source
SaveChanges()
), mais il est toujours possible qu'une autre insertion / mise à jour se glisse entre le moment de la vérification d'unicité et l'heure deSaveChanges()
. Ainsi, en fonction de l'importance de la mission de l'application et de la probabilité d'une violation d'unicité, il est probablement préférable d'ajouter la contrainte à la base de données.serializable isolation level
(ou le verrouillage de table personnalisé, ugh) vous permettrait en fait de garantir l'unicité de votre code. Mais la plupart des gens n'utilisent pas leserializable isolation level
pour des raisons de performances. La valeur par défaut dans MS Sql Server estread committed
. Voir la série en 4 parties à partir de: michaeljswart.com/2010/03/…À partir d'EF 6.1, il est désormais possible:
Cela vous donnera un index unique au lieu d'une contrainte unique, à proprement parler. Pour la plupart des raisons pratiques, ce sont les mêmes .
la source
Pas vraiment lié à cela mais cela pourrait aider dans certains cas.
Si vous cherchez à créer un index composite unique sur disons 2 colonnes qui agira comme une contrainte pour votre table, alors à partir de la version 4.3, vous pouvez utiliser le nouveau mécanisme de migration pour y parvenir:
En gros, vous devez insérer un appel comme celui-ci dans l'un de vos scripts de migration:
Quelque chose comme ca:
la source
DropIndex("TableName", new[] { "Column1", "Column2" });
Je fais un hack complet pour exécuter SQL lors de la création de la base de données. Je crée mon propre DatabaseInitializer et hérite de l'un des initialiseurs fournis.
C'est le seul endroit que j'ai pu trouver pour caler mes instructions SQL.
C'est de CTP4. Je ne sais pas comment cela fonctionne dans CTP5.
la source
En essayant simplement de savoir s'il y avait un moyen de le faire, le seul moyen que j'ai trouvé jusqu'à présent était de l'appliquer moi-même, j'ai créé un attribut à ajouter à chaque classe où vous fournissez le nom des champs dont vous avez besoin pour être unique:
Puis dans ma classe je vais l'ajouter:
Enfin, j'ajouterai une méthode dans mon référentiel, dans la méthode Add ou lors de l'enregistrement des modifications comme ceci:
Pas trop gentil car il faut s'appuyer sur la réflexion mais c'est jusqu'à présent l'approche qui fonctionne pour moi! = D
la source
Également en 6.1, vous pouvez utiliser la version à syntaxe fluide de la réponse de @ mihkelmuur comme ceci:
La méthode fluide n'est pas parfaite IMO mais au moins c'est possible maintenant.
Plus de détails sur le blog Arthur Vickers http://blog.oneunicorn.com/2014/02/15/ef-6-1-creating-indexes-with-indexattribute/
la source
Un moyen simple dans Visual Basic à l'aide des migrations EF5 Code First
Exemple de classe publique
Fin de classe
L'attribut MaxLength est très important pour un index unique de type chaîne
Exécutez cmd: update-database -verbose
après l'exécution de cmd: add-migration 1
dans le fichier généré
la source
Similaire à la réponse de Tobias Schittkowski mais C # et a la capacité d'avoir plusieurs champs dans les constrtaints.
Pour l'utiliser, placez simplement un [Unique] sur n'importe quel champ que vous souhaitez être unique. Pour les chaînes, vous devrez faire quelque chose comme (notez l'attribut MaxLength):
car le champ de chaîne par défaut est nvarchar (max) et cela ne sera pas autorisé dans une clé.
Pour plusieurs champs de la contrainte, vous pouvez faire:
Tout d'abord, UniqueAttribute:
Ensuite, incluez une extension utile pour obtenir le nom de la table de base de données à partir d'un type:
Ensuite, l'initialiseur de base de données:
la source
J'ai résolu le problème par réflexion (désolé, les amis, VB.Net ...)
Tout d'abord, définissez un attribut UniqueAttribute:
Ensuite, améliorez votre modèle comme
Enfin, créez un DatabaseInitializer personnalisé (dans ma version, je recrée la base de données sur les modifications de la base de données uniquement si en mode débogage ...). Dans ce DatabaseInitializer, les index sont automatiquement créés en fonction des attributs uniques:
Peut-être que cela aide ...
la source
Si vous substituez la méthode ValidateEntity dans votre classe DbContext, vous pouvez également y placer la logique. L'avantage ici est que vous aurez un accès complet à tous vos DbSets. Voici un exemple:
la source
Si vous utilisez EF5 et que vous avez toujours cette question, la solution ci-dessous l'a résolue pour moi.
J'utilise la première approche du code, mettant donc:
dans le script de migration a bien fait le travail. Il autorise également les valeurs NULL!
la source
Avec l'approche EF Code First, on peut implémenter la prise en charge des contraintes uniques basées sur les attributs à l'aide de la technique suivante.
Créer un attribut de marqueur
Marquez les propriétés que vous souhaitez rendre uniques sur les entités, par exemple
Créez un initialiseur de base de données ou utilisez-en un existant pour créer les contraintes uniques
Définissez le contexte de votre base de données pour utiliser cet initialiseur dans le code de démarrage (par exemple dans
main()
ouApplication_Start()
)La solution est similaire à celle de mheyman, avec une simplification de ne pas prendre en charge les clés composites. À utiliser avec EF 5.0+.
la source
Solution Fluent Api:
la source
J'ai fait face à ce problème aujourd'hui et j'ai finalement pu le résoudre. Je ne sais pas si c'est une bonne approche mais au moins je peux continuer:
la source
Utilisez un validateur de propriété unique.
ValidateEntity
n'est pas appelée dans la même transaction de base de données. Par conséquent, il peut y avoir des conditions de concurrence avec d'autres entités de la base de données. Vous devez quelque peu pirater EF pour forcer une transaction autour duSaveChanges
(et donc,ValidateEntity
).DBContext
ne peut pas ouvrir la connexion directement, maisObjectContext
peut.la source
Selon http://blogs.msdn.com/b/adonet/archive/2014/02/11/ef-6-1-0-beta-1-available.aspx , EF 6.1 aura un IndexAttribute pour nous aider .
la source
Après avoir lu cette question, j'avais ma propre question en train d'essayer d'implémenter un attribut pour désigner des propriétés comme des clés uniques comme celles de Mihkel Müür , Tobias Schittkowski et mheyman suggèrent: mapper les propriétés du code Entity Framework aux colonnes de la base de données (CSpace vers SSpace)
Je suis enfin arrivé à cette réponse qui peut mapper les propriétés scalaires et de navigation vers les colonnes de la base de données et créer un index unique dans une séquence spécifique désignée sur l'attribut. Ce code suppose que vous avez implémenté un UniqueAttribute avec une propriété Sequence et que vous l'avez appliqué aux propriétés de classe d'entité EF qui doivent représenter la clé unique de l'entité (autre que la clé primaire).
Remarque: ce code repose sur EF version 6.1 (ou ultérieure) qui expose
EntityContainerMapping
non disponible dans les versions antérieures.la source
Pour ceux qui utilisent les premières configurations de code, vous pouvez également utiliser l'objet IndexAttribute comme ColumnAnnotation et définir sa propriété IsUnique sur true.
Par exemple:
Cela créera un index unique nommé IX_name dans la colonne Name.
la source
Désolé pour la réponse tardive mais j'ai trouvé bon de le partager avec vous
J'ai posté à ce sujet au projet de code
En général, cela dépend des attributs que vous mettez sur les classes pour générer vos index uniques
la source