Comment définir les relations facultatives clé étrangère dans FluentAPI/Annotations de données avec le cadre D'entité?
j'ai un (échantillon) de l'application avec le code suivant:
public class Posts
{
[Key]
[Required]
public int ID { get; set; }
[Required]
public string TypeOfPost { get; set; }
public int PollID { get; set; }
public virtual Poll Poll { get; set; }
public int PostID { get; set; }
public virtual Post Post { get; set; }
}
fondamentalement, Je ne sais pas s'il y a une meilleure façon de faire cela, mais, j'ai une liste de messages, et, les gens peuvent choisir si c'est un Poll
et Post
, Entity Framework ne fonctionne pas avec les Énumérations, je viens de le stocker en tant que chaîne de caractères TypeOfPost
et puis dans l'application, j'interroge programmatiquement soit Poll soit Post basé sur la valeur de TypeOfPost
.
je ne pense pas qu'il y est de toute façon de réglage "Un seul requis" ou similaire, donc, je m'occupe de toutes les vérifications et des trucs dans la demande. (Si quelqu'un connaît une meilleure façon de faire, s'il vous plaît dire!).
de toute façon, le problème est que je peux obtenir ce bon fonctionnement en allant dans SQL Management Studio et éditant manuellement le schéma pour permettre nulls - mais, je ne peux pas travailler sur la façon de le faire dans le FluentAPI, et j'ai besoin d'aide.
j'ai essayé les deux options suivantes:
modelBuilder.Entity<Post>()
.HasOptional(x => x.Poll).WithOptionalDependent();
modelBuilder.Entity<Post>()
.HasOptional(x => x.Poll).WithOptionalPrincipal();
le premier semble créer un colonne dans la base de données qui permet nulls, et le second ne semble pas faire quoi que ce soit.
je crois que le premier est celui dont j'ai besoin, mais j'ai besoin de l'utiliser en combinaison avec [ForeignKey]Post
Classe. Si j'ai raison ici, est-ce que [ForeignKey] doit aller sur la propriété virtuelle, ou L'ID de la propriété?
En outre, quelle est la réelle différence entre WithOptionalDependent
et <!--8? - J'ai lu sur MSDN, mais je ne comprends vraiment pas différence.
4 réponses
j'essaierais probablement de créer les deux relations un-à-un comme en option: parce que Poll
faites référence à Posts
et Post
faites référence à Posts
:
modelBuilder.Entity<Posts>()
.HasOptional(x => x.Post)
.WithRequired();
modelBuilder.Entity<Posts>()
.HasOptional(x => x.Poll)
.WithRequired();
Cela fait Posts
automatiquement le principal dans la relation et Post
ou Poll
la personne à charge. Le principal a la clé primaire dans la relation, le dépendant la clé étrangère qui est aussi le touche primaire en même temps en Post
/Poll
table parce que c'est une relation un-à-un. Seulement dans une relation de un à plusieurs vous auriez une colonne séparée pour la clé étrangère. Pour une relation un-à-un vous devez également supprimer les colonnes de clé étrangère PostId
et PollId
parce que Posts
renvoie par sa clé primaire à la Post
et Poll
.
une autre approche qui semble appropriée dans votre modèle est la cartographie des héritages. Ensuite, le modèle serait ressembler à ceci:
public abstract class BasePost // your former Posts class
{
public int ID { get; set; }
public string UserName { get; set; }
}
public class Post : BasePost
{
public string Text { get; set; }
// other properties of the Post class
}
public class Poll : BasePost
{
// properties of the Poll class
}
Vous n'avez pas besoin de l' TypeOfPost
puis plus parce que vous pouvez filtrer les deux types de béton en utilisant le OfType
opérateur LINQ, par exemple:
var x = context.BasePosts.OfType<Post>()
.Where(p => p.UserName == "Jim")
.ToList();
ceci sélectionnerait tous les messages d'un utilisateur particulier mais pas les sondages.
vous devez décider alors quel type de cartographie d'héritage vous voulez utiliser - TPH, TPT or TPC.
Modifier
Pour obtenir un un-à-plusieurs relation vous pouvez spécifier la correspondance suivante dans L'API Fluent:
modelBuilder.Entity<Posts>()
.HasOptional(x => x.Post)
.WithMany()
.HasForeignKey(x => x.PostID);
modelBuilder.Entity<Posts>()
.HasOptional(x => x.Poll)
.WithMany()
.HasForeignKey(x => x.PollID);
les propriétés de la clé étrangère doivent être nulles (int?
) pour ce que vous avez déjà trouvé. Parce que la désignation de vos propriétés de clé étrangère suit la convention de désignation EF utilise pour la cartographie, vous pouvez omettre la cartographie fluente tout à fait. Cela ne serait nécessaire que si vous aviez des noms non conventionnels (comme PostFK
ou quelque chose). Vous pouvez également utiliser des annotations de données ([ForeignKey(...)]
attribut) au lieu de parler couramment API.
la raison pour laquelle il ne permettait pas nulls parce que ce qui suit:
public int PollID { get; set; }
public virtual Poll Poll { get; set; }
public int PostID { get; set; }
public virtual Post Post { get; set; }
aurait dû être
public int? PollID { get; set; }
public virtual Poll Poll { get; set; }
public int? PostID { get; set; }
public virtual Post Post { get; set; }
la ForeignKey doit juste être Nullable pour la rendre optionnelle - virtual est séparé, et seulement requis pour le chargement paresseux.
Un lien nécessaire dans déclarative EF Premier Code:
public User User { get; set; }
[ForeignKey("User")]
public int UserId { get; set; }
Une option de relation dans déclarative EF Premier Code:
public User User { get; set; }
[ForeignKey("User")]
public int? UserId { get; set; }
Vous le verrez quand vous exécutez update-database -verbose -f
:
ALTER TABLE [dbo].[MyTable] ALTER COLUMN [UserId] [int] NULL
autre chose qui pourrait aider. Le fait de définir les attributs de clé étrangère (annotations) avec l'attribut [Required] permettra également de renforcer les propriétés de navigation requises par EF, même lorsque la propriété FK est nulle. J'ai un cas spécial avec les données héritées où une propriété FK est nécessaire mais peut ou ne peut pas faire référence à un document dans la relation. C'est logique, mais je ne pensais pas que EF était aussi "intelligent".
[Required] <-- even if the FK is nullable, OrgUnit will be Required
[StringLength(10)]
[ForeignKey("OrgUnit"), Column(Order = 1)]
public string OrgCode
{
get;
set;
}
... other FK, Column order 0
public virtual OrgUnit OrgUnit
{
get;
set;
}