8
votes

Entity Framework Code Première cartographie Touche étrangère à l'aide de API fluide

J'ai la situation dans laquelle un utilisateur peut avoir plusieurs adresses. En conséquence, j'ai une iCollection sur ma classe d'utilisateurs. Mais je souhaite aussi que l'utilisateur puisse choisir une adresse par défaut. J'ai donc fait ce qui suit:

public class Address
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Details { get; set; }
    public virtual Area Area { get; set; }
}


5 commentaires

Comment l'adresse est-elle ressemblant à l'adresse ? A-t-il une référence à un seul utilisateur de sorte que chaque adresse appartient uniquement à un utilisateur? Ou les utilisateurs peuvent-ils partager une adresse au cas où je m'attendais à une relation nombreuses à plusieurs?


@Slauma: Je viens de mettre à jour la question. Verifiez le s'il vous plaît.


Pourquoi avez-vous eu des problèmes avec DÉPOSITION DU PUBLIC VIRTUELLADDRESS {GET; ensemble; } ? À mon avis, cette propriété est la meilleure façon d'exprimer la relation que vous aimeriez avoir - et je ne peux pas voir un problème pour mapper cela à la DB. Si vous supprimez la propriété (et ne disposez pas d'une propriété utilisateur de la classe d'adresse) defaultAddressid devient essentiellement une propriété scalaire qui ne participe pas à une relation du tout. Donc, vous perdriez des vérifications en contraintes de clé étrangère dans la base de données (chaque nombre peut être dans cette propriété, peu importe si une adresse avec cet identifiant existe ou non).


@Slauma: Je ne sais pas pourquoi il y a des problèmes avec ça. Cela fonctionnait bien avant de passer à EF 4.1 En plus des autres problèmes que je n'ai pas encore résolus. Voir cette question


J'ai testé votre modèle tel qu'il est ci-dessus dans vos questions et cela fonctionne bien pour moi. Ce modèle est en fait exactement la solution que je choisirais de travailler avec une collection d'adresses et une défaillance de la valeur par défaut. Je crois que vos complications sont ailleurs ailleurs.


4 Réponses :


0
votes

Vous n'avez pas besoin de la mapper si vous retirez la propriété de défaillanceAddress. Vous pouvez simplement avoir la propriété là-bas et EF devrait savoir la mapper qu'il a fourni par défautDDRESSID est dans la table utilisateur


2 commentaires

Comment EF est-il censé savoir comment mapper? Serait-il toujours nullable? Parce que si un utilisateur n'a pas encore ajouté d'adresse, cela devrait être null et il ne devrait pas provoquer une erreur lors de l'ajout de l'utilisateur à la base de données ...


Oui, il serait toujours nullable. J'ai trouvé des problèmes de cartographie une relation de 1 à 1 à l'aide de l'API fluide car il ne semble pas avoir le moyen de cartographier une clé dans 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 en utilisant hasoptional (u => u.defaultaddress) .withmany (). Haskey (u => u.defaultAddressid);



10
votes

Je voudrais personnellement déplacer personnellement la relation de la clé étrangère de utilisateur code> à adresse code> et ajouter un isdefaultAddress code> propriété de la classe d'adresse.

public class Address
{
    public int Id { get; set; }

    // This property marks the FK relation
    public virtual User User { get; set; }

    public string Name { get; set; }
    public string Details { get; set; }
    public virtual Area Area { get; set; }

    // This property signals whether this is the user's default address
    public bool IsDefaultAddress { get; set; }
}


6 commentaires

@Sergi Papaseit: +1 pour la réponse. Je ne sais pas pourquoi j'aime bien compliquer des choses. J'aurais dû faire ça dès le début. Je suppose que je suis obsédé à la "normalisation" de la base de données. Je suppose que parfois il doit y avoir un compromis pour le souci de simplicité. Merci encore :)


@Kassem - Il est toujours bon de garder Kiss et Yagni à l'esprit;) Heureux d'aider :)


Honnêtement, j'irais avec la solution dans la question. Je ne sais pas pourquoi cela ne devrait pas travailler (je venais de le tester et c'est bien. Cela crée 2 relations.) Avec votre solution, il faut s'assurer que dans la logique commerciale que ISDEFAULDDDRESS ISN ' t Définissez plus d'une adresse d'un utilisateur. Et si vous modifiez la défaillanceDDRESS, il faut rechercher l'ancienne adresse et réinitialiser l'ancien drapeau. La solution dans la question exprime mieux les relations "naturelles" du modèle à mon avis et il n'est pas nécessaire de s'inquiéter des drapeaux par défaut en double.


@Slauma - Je dois dire que vous avez un bon point. Mon sentiment d'intestin initial aurait été de faire comme je l'ai suggéré, mais il est vrai que d'avoir une propriété defaultAddress dans la classe utilisateur exprime clairement la relation. Je suppose que tout dépend de ce que vous voulez exprimer / réaliser. J'ajouterais toujours une référence à utilisateur dans l'adresse classe.


@Slauma: C'est pourquoi je suis allé avec la solution dans la question. Je ne voulais pas m'inquiéter des adresses par défaut en double qui pourrait être causée par la solution de Sergi. Mais, je ne veux pas que je tiens à garder les choses aussi simples que possible afin de suivre ce qui cause des problèmes dans mon modèle. Mais naturellement, si j'ajoute une référence à l'utilisateur dans la classe d'adresses, cela devrait fonctionner correctement?


@Kassem: J'ai ajouté un exemple de test dans une réponse ici. Vous pouvez essayer cela et devrait voir que cela fonctionne avec votre modèle simple dans la question. Peut-être que cela vous aide à trouver les problèmes que vous rencontrez dans votre modèle "réel" en comparant les deux modèles et leur configuration.



2
votes

DefaultAddressID n'a pas besoin de mappage spécifique car il ne s'agira que de la colonne de utilisateur sans aucune relation (FK) à Adresse . Il n'y aura aucune relation créée car la propriété de navigation n'existe pas de chaque côté. En outre, il devrait s'agir d'une relation individuelle qui ne fonctionnera pas car EF ne prend pas en charge les clés uniques.

J'aime la solution fournie par @ssergi Papaseit


2 commentaires

Oui, je suppose que je vais aller avec la réponse de Sergi. Mais suggérez-vous que je devais ajouter une propriété de navigation à l'utilisateur de la classe d'adresses?


Suivez l'approche de @ Sergi Vous aurez besoin de Adresses COLLECTION IN UTILISATEUR .



8
votes

Votre modèle original dans la question devrait fonctionner. Vous pouvez le tester assez facilement:

  • Créer une nouvelle demande de console (vs 2010) li>
  • Nom It "Efestestapp" LI>
  • Ajouter une référence à "EntityFramework.dll" LI>
  • Supprimer le contenu du programme.cs et copier le code suivant dans le fichier li> ul>

    programme.cs: p>

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>()
                    .HasMany(u => u.Addresses)
                    .WithRequired();
    }
    


5 commentaires

Vous pouvez également utiliser l'attribut [requis] sur les adresses dans la classe de l'utilisateur pour marquer la relation au besoin (ef ajoutera une cascade de Supprimer également). Je ne sais pas comment ça va travailler sur une collection cependant.


@Sergi PapasITIT: Oui, j'ai essayé aussi de placer le [requis] attribut sur les adresses collection mais cela ne fonctionne pas. Il n'y a pas d'erreur d'erreur de compilateur ou d'EF, la clé étrangère reste tout simplement nullable. Nous avons donc toujours une relation facultative. Je suppose que nous devrions ajouter une propriété utilisateur dans la classe adresse , puis marquer cette propriété comme [requis] si nous voulions utiliser des donnéesAnotations exclusivement et aucune API fluide.


J'utilise cela aussi. Mais je me demandais s'il existe un moyen d'éviter les Savechanges intermédiaires avant de définir la valeur par défaut?


@Ravi: Avez-vous testé pour supprimer le premier SAVECHANGES ? Cela devrait fonctionner, n'est-ce pas? Les SAVECHANGES intermédiaires étaient uniquement à des fins de débogage et de démonstration pour montrer les modifications apportées à la DB.


Oui. Je l'ai essayé et ça ne marche pas. Il semble que la clé principale est un identifiant incrémentiel qu'il ne sait pas ce que l'ID de la valeur par défaut est sans enregistrer d'abord. Je pense que cela fonctionnerait si nous utilisons le GUID comme pk.