Entity Framework Code First Mappage des Clés Étrangères en Utilisant des API Fluent
J'ai la situation où un Utilisateur peut avoir plusieurs adresses. En conséquence, j'ai une ICollection sur ma classe d'utilisateur. Mais je tiens également à l'utilisateur d'être en mesure de choisir une adresse par défaut. J'ai donc fait le suivant:
public class User
{
public int Id { get; set; }
public int? DefaultAddressId { get; set; }
[ForeignKey("DefaultAddressId")]
public virtual Address DefaultAddress { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
//properties were removed for purpose of this post
}
Je voudrais enlever le public virtual Address DefaultAddress { get; set; }
au total, garder le DefaultAddressId et de la carte à l'aide de l'API Fluent au lieu de cela, car la configuration actuelle, est à l'origine de beaucoup de problèmes (dans ce cas, et d'autres classes où j'en ai un similaire de l'installation). Donc cela peut être fait en utilisant l'api fluent?
Mise à JOUR:
L'adresse de la classe ne dispose pas actuellement de toute référence à l'Utilisateur de la classe, c'est un uni-directionnelle de la relation. Mais oui, une adresse appartient à UN seul utilisateur, ce n'est pas une relation plusieurs-à-plusieurs. Voici l'adresse de la classe:
public class Address
{
public int Id { get; set; }
public string Name { get; set; }
public string Details { get; set; }
public virtual Area Area { get; set; }
}
Address
classe? A-t-elle une référence à un seul User
de sorte que chaque Adresse appartient uniquement à un utilisateur? Ou les utilisateurs peuvent partager une Adresse dans ce cas, je m'attends à une plusieurs-à-plusieurs relation?J'ai juste mis à jour à la question. Vérifiez s'il vous plaît.
Pourquoi avez-vous eu des problèmes avec
public virtual Address DefaultAddress { get; set; }
? À mon avis, cette propriété est la meilleure façon d'exprimer la relation que vous souhaitez avoir et je ne vois pas le problème de cette carte à la DB. Si vous supprimez la propriété (et qui n'ont pas User
propriété à la classe d'Adresse) DefaultAddressId
devient essentiellement une propriété scalaire qui ne participent pas à une relation. Si vous perdez la clé étrangère contrainte vérifie dans la base de données (chaque nombre peut être dans cette propriété, peu importe si une adresse avec cet IDENTIFIANT existe ou pas).Je ne suis pas sûr de savoir pourquoi il y a des problèmes. Ça marchait très bien avant la mise à jour vers 4.1 EF en plus d'autres problèmes que je n'ai pas encore résolu encore. reportez-vous à cette question
J'ai testé votre modèle tel qu'il est ci-dessus dans vos questions et il fonctionne très bien pour moi. Ce modèle est en fait exactement la solution que j'ai choisi de travailler avec une collection d'Adresses et un DefaultAddress. Je crois, que vos complications sont quelque part d'autre.
OriginalL'auteur Kassem | 2011-03-30
Vous devez vous connecter pour publier un commentaire.
Personnellement, je ne déplacez la Clé Étrangère de la relation de
User
àAddress
, et d'ajouter uneIsDefaultAddress
bien sur la classe d'adresse.EF sais qu'il a besoin d'un
Foreign Key
relation entreAddress
etUser
.Ce serait simplifier votre modèle d'une grande. C'est, bien sûr, si une adresse ne peut appartenir qu'à un seul utilisateur (comme demandé par Slauma dans les commentaires).
Il est toujours bon de garder K. I. S. S et YAGNI dans l'esprit 😉 Heureux de vous aider 🙂
Honnêtement, j'irais avec la solution de la question. Je ne sais pas pourquoi cela ne fonctionnerait pas (j'avais juste testé et c'est très bien. Il crée 2 relations.) Avec votre solution, on doit veiller à ce que dans une logique de gestion
IsDefaultAddress
n'est pas défini sur plus d'une Adresse d'un utilisateur. Et si vous changez la DefaultAddress on a à la recherche de l'ancienne adresse et de réinitialiser le vieux drapeau. La solution de la question exprime le "naturel" des relations du modèle mieux à mon avis et qu'on n'a pas besoin de s'inquiéter à propos de dupliquer les drapeaux par défaut.Je dois dire que vous avez un bon point. Ma première intuition aurait été de le faire comme je l'ai suggéré, mais il est vrai que le fait d'avoir un
DefaultAddress
propriété dans leUser
classe exprime la relation clairement. Je suppose que tout dépend de ce que vous voulez à express/à atteindre. Je voudrais encore ajouter une référence àUser
dans leAddress
classe.C'est la raison pour laquelle je suis allé avec la solution de la question. Je ne voulais pas vous soucier de dupliquer les adresses par défaut, qui peuvent être causés par Sergi la solution. Mais, je donno, je tiens à garder les choses aussi simples que possible afin de traquer ce qui est à l'origine des problèmes dans mon modèle. Mais naturellement, si j'ajoute une référence à l'Utilisateur dans la classe d'Adresse, il devrait fonctionner correctement?
OriginalL'auteur Sergi Papaseit
Votre modèle d'origine dans la question devrait fonctionner. Vous pouvez le tester assez facilement:
Programme.cs:
Dans SQL Server Express, il crée une nouvelle DB appelé "EFTestApp.Contexte". Vous pouvez définir des points d'arrêt sur chaque SaveChanges ci-dessus, et montre les modifications dans la base de données.
Si vous regardez les relations dans la base de données, puis il y a les deux, et dans le tableau
Addresses
dans le DB est une colonne de clé étrangèreUser_Id
.Je pense que vous pouvez également supprimer
public int? DefaultAddressId { get; set; }
et[ForeignKey("DefaultAddressId")]
. Il crée la même base de données les tables et les relations avec une option de DefaultAddress.Peut-être que vous voulez que la relation
Address -> User
nécessaires (Adresses ne peut pas vivre seul dans la base de données sans que l'Utilisateur). Ensuite, vous pouvez l'ajouter à la classe de Contexte:Il fait
User_Id
dans la table des Adresses non nullable et met en place de suppression en cascade par défaut. Ainsi, lorsqu'un utilisateur est supprimé, ses adresses sont supprimés.[Required]
attribut surAddresses
dans leUser
classe pour marquer la relation, comme l'exige (EF ajouter on Delete cascade). Je ne suis pas sûr de savoir comment cela fonctionnera sur une collection.Papaseit: Oui, j'ai essayé ça aussi, à la place de la
[Required]
attribut sur laAddresses
de la collection, mais cela ne fonctionne pas. Il n'y a pas d'erreur du compilateur ou de l'EF exception, la clé étrangère simplement séjours nullable, il nous reste encore une option de relation. Je suppose que nous aurions besoin d'ajouter unUser
bien sur laAddress
classe et puis marquer cette propriété comme[Required]
si l'on voulait utiliser DataAnnotations exclusivement et pas d'API Fluent.Bon à savoir, merci! ; )
Je suis en utilisant ce. Mais vous vous demandez si il y a un moyen d'éviter les intermédiaires savechanges avant de définir la valeur par défaut?
Avez-vous tester afin de supprimer la première
SaveChanges
? Il doit travailler, n'est-ce pas? L'intermédiaireSaveChanges
ont été uniquement pour le débogage et à des fins de démonstration pour montrer les changements dans la base de données.OriginalL'auteur Slauma
DefaultAddressId
n'a pas besoin de cartographie spécifique parce que ce sera juste de la colonne dansUser
table sans aucun rapport (FK) àAddress
table. Il n'y aura aucun rapport créé parce que la navigation de la propriété n'existe pas sur le côté. Il doit aussi être un-à-un rapport qui ne fonctionnera pas parce que les EF ne prend pas en charge les clés uniques.J'aime fournies par la solution de @Sergi Papaseit
Suivez @Sergi approche, vous aurez besoin seulement
Addresses
collectionUser
.OriginalL'auteur Ladislav Mrnka
Vous n'avez pas besoin de la carte si vous retirez la DefaultAddress de la propriété. Vous pouvez juste avoir la propriété et de l'EF devrait savoir comment cartographier fourni DefaultAddressId est dans la table User
Oui, il serait encore nullable. J'ai trouvé quelques problèmes de mappage d'un 1 à 1 de relation d'aide de l'API fluent comme il ne semble pas avoir une correspondance entre la clé d'une colonne spécifique. Dans mon cas j'ai utilisé 1 à plusieurs dans la cartographie, même si l'objet ne contient que 1 instance de l'enfant. C'est fait à l'aide de HasOptional(u => u.DefaultAddress).WithMany().HasKey(u => u.DefaultAddressId);
OriginalL'auteur Gats