Comment dois-je déclarer les relations clés étrangères en utilisant le Code First Entity Framework (4.1) dans MVC3?
j'ai cherché des ressources sur la façon de déclarer les relations étrangères clés et d'autres contraintes en utilisant code First EF 4.1 sans beaucoup de chance. Fondamentalement, je construis le modèle de données en code et en utilisant MVC3 pour interroger ce modèle. Tout fonctionne via MVC ce qui est génial (bravo à Microsoft!) mais maintenant je veux que cela ne fonctionne pas parce que j'ai besoin d'avoir des contraintes de modèle de données.
par exemple, j'ai un objet ordre qui a une tonne de propriétés qui sont externes les objets (tables). En ce moment je peux créer un ordre sans problème, mais sans pouvoir ajouter la clé étrangère ou des objets externes. MVC3 ne pose aucun problème.
je réalise que je pourrais juste ajouter les objets moi-même dans la classe controller avant de sauvegarder, mais je voudrais l'appel à DbContext.SaveChanges() échoue si la contrainte relations n'ont pas été respectées.
INFORMATIONS NOUVELLES
donc, spécifiquement, Je tiens un exception à se produire lorsque je tente de enregistrer un objet de commande sans la spécification d'un objet client. Ce ne semble pas être le problème si je rédigez simplement les objets comme décrit dans la plupart des documents de la première EF codée.
dernier code:
public class Order
{
public int Id { get; set; }
[ForeignKey( "Parent" )]
public Patient Patient { get; set; }
[ForeignKey("CertificationPeriod")]
public CertificationPeriod CertificationPeriod { get; set; }
[ForeignKey("Agency")]
public Agency Agency { get; set; }
[ForeignKey("Diagnosis")]
public Diagnosis PrimaryDiagnosis { get; set; }
[ForeignKey("OrderApprovalStatus")]
public OrderApprovalStatus ApprovalStatus { get; set; }
[ForeignKey("User")]
public User User { get; set; }
[ForeignKey("User")]
public User Submitter { get; set; }
public DateTime ApprovalDate { get; set; }
public DateTime SubmittedDate { get; set; }
public Boolean IsDeprecated { get; set; }
}
c'est l'erreur que j'obtiens maintenant en accédant à la vue générée par VS pour le Patient:
MESSAGE D'ERREUR
la cotisation étrangère sur les biens "Patient" sur le type "PhysicianPortal.Modèle."L'ordre n'est pas valide. Nom de la clé étrangère "Parent" n'a pas été trouvé sur le type de charge "PhysicianPortal.Modèle.La commande'. Le La valeur du nom doit être une virgule séparée liste des noms de propriétés clés étrangères.
concerne",
Guido
2 réponses
si vous avez une classe Order
, ajouter une propriété qui fait référence à une autre classe dans votre modèle, par exemple Customer
devrait suffire à faire savoir à EF qu'il y a une relation:
public class Order
{
public int ID { get; set; }
// Some other properties
// Foreign key to customer
public virtual Customer Customer { get; set; }
}
vous pouvez toujours définir la relation FK
explicitement:
public class Order
{
public int ID { get; set; }
// Some other properties
// Foreign key to customer
[ForeignKey("Customer")]
public string CustomerID { get; set; }
public virtual Customer Customer { get; set; }
}
le constructeur ForeignKeyAttribute
prend une chaîne comme paramètre: si vous la placez sur une propriété de clé étrangère, elle représente le nom de la propriété associée propriété de navigation. Si vous le placez sur la propriété de navigation, il représente le nom de la clé étrangère.
ce que cela signifie, Si vous placez le ForeignKeyAttribute
sur la propriété Customer
, l'attribut prendrait CustomerID
dans le constructeur:
public string CustomerID { get; set; }
[ForeignKey("CustomerID")]
public virtual Customer Customer { get; set; }
modifier basé sur dernier Code Vous obtenez cette erreur à cause de cette ligne:
[ForeignKey("Parent")]
public Patient Patient { get; set; }
EF recherchera une propriété appelée Parent
pour l'utiliser comme exécuteur étranger de clés. Vous pouvez faire deux choses:
1) supprimer le ForeignKeyAttribute
et le remplacer par le RequiredAttribute
pour marquer la relation comme requis:
[Required]
public virtual Patient Patient { get; set; }
décorer une propriété avec le RequiredAttribute
a aussi un bel effet secondaire: la relation dans la base de données est créée avec ON DELETE CASCADE
.
I recommanderait également de faire la propriété virtual
pour permettre le chargement paresseux.
2) Créer une propriété appelée Parent
qui servira de clé étrangère. Dans ce cas, il est probablement plus logique de l'appeler par exemple ParentID
(vous aurez besoin de changer le nom dans le ForeignKeyAttribute
ainsi):
public int ParentID { get; set; }
Dans mon expérience, dans ce cas, si elle fonctionne mieux dans l'autre sens:
[ForeignKey("Patient")]
public int ParentID { get; set; }
public virtual Patient Patient { get; set; }
vous pouvez définir clé étrangère par:
public class Parent
{
public int Id { get; set; }
public virtual ICollection<Child> Childs { get; set; }
}
public class Child
{
public int Id { get; set; }
// This will be recognized as FK by NavigationPropertyNameForeignKeyDiscoveryConvention
public int ParentId { get; set; }
public virtual Parent Parent { get; set; }
}
Maintenant ParentId est propriété de clé étrangère et définit la nécessaire relation entre l'enfant et les parents. Sauver l'enfant sans quitter parent fera exception.
si le nom de votre propriété FK ne se compose pas du nom de la propriété de navigation et du nom de PK parent, vous devez soit utiliser L'annotation de données ForeignKeyAttribute, soit utiliser l'API fluent pour mapper la relation
données annotation:
// The name of related navigation property
[ForeignKey("Parent")]
public int ParentId { get; set; }
API Fluent:
modelBuilder.Entity<Child>()
.HasRequired(c => c.Parent)
.WithMany(p => p.Childs)
.HasForeignKey(c => c.ParentId);
D'autres types de contraintes peuvent être appliquées par annotations de données et validation de modèle .
Edit:
vous obtiendrez une exception si vous ne définissez pas ParentId
. Il est nécessaire de propriété (non nullable). Si vous ne le définissez pas, il est très probable que vous tenterez d'envoyer la valeur par défaut à la base de données. La valeur par défaut est 0, donc si vous ne pas avoir de client avec Id = 0 Vous obtiendrez une exception.