2011-03-06 4 views
6

Vous pouvez trouver le code source démontrant cette question @http://code.google.com/p/contactsctp5/code CTP5 EF Première question

J'ai trois objets de modèle. Contact, ContactInfo, ContactInfoType. Où un contact a beaucoup de contactinfo et chaque contactinfo est uninfotype de contact. Assez simple je suppose. Le problème que je rencontre est quand je vais éditer l'objet contact. Je l'ai tiré de mon dépôt de contact. Ensuite, je cours "UpdateModel (contact);" et il met à jour l'objet avec toutes les valeurs de mon formulaire. (Surveillance avec débogage) Lorsque j'enregistre les changements que, je reçois l'erreur suivante:

The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.

Il semble que, après que j'appelle le modèle de mise à jour, il NULLS mes références et cela semble tout casser? Toute idée sur la façon de remédier serait grandement appréciée. Merci.

Voici mes modèles:

public partial class Contact { 
    public Contact() { 
     this.ContactInformation = new HashSet<ContactInformation>(); 
    } 

    public int ContactId { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 

    public virtual ICollection<ContactInformation> ContactInformation { get; set; } 
} 

public partial class ContactInformation { 
    public int ContactInformationId { get; set; } 
    public int ContactId { get; set; } 
    public int ContactInfoTypeId { get; set; } 
    public string Information { get; set; } 

    public virtual Contact Contact { get; set; } 
    public virtual ContactInfoType ContactInfoType { get; set; } 
    } 

    public partial class ContactInfoType { 
    public ContactInfoType() { 
     this.ContactInformation = new HashSet<ContactInformation>(); 
    } 

    public int ContactInfoTypeId { get; set; } 
    public string Type { get; set; } 

    public virtual ICollection<ContactInformation> ContactInformation { get; set; } 
    } 

Mon contrôleur d'action:

[AcceptVerbs(HttpVerbs.Post)] 
    public ActionResult Edit(Contact person) { 
     if (this.ModelState.IsValid) { 
     var contact = this.contactRepository.GetById(person.ContactId); 
     UpdateModel(contact); 
     this.contactRepository.Save(); 
     TempData["message"] = "Contact Saved."; 
     return PartialView("Details", contact); 
     } else { 
     return PartialView(person); 
     } 
    } 

Code Contexte:

protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder) { 
     modelBuilder.Entity<Contact>() 
     .HasMany(c => c.ContactInformation) 
     .WithRequired() 
     .HasForeignKey(c => c.ContactId); 

     modelBuilder.Entity<ContactInfoType>() 
     .HasMany(c => c.ContactInformation) 
     .WithRequired() 
     .HasForeignKey(c => c.ContactInfoTypeId); 
    } 
+0

L'erreur est-elle indépendante du type de modifications que vous effectuez sur votre formulaire? Je pourrais imaginer qu'une telle erreur peut se produire si vous supprimez un 'ContactInformation' de la collection dans' Contact'. Est-ce que l'erreur se produit également si vous changez seulement par exemple le 'FirstName' sur votre formulaire et rien d'autre? – Slauma

Répondre

1

J'ai posé cette question grâce à Morteza Manavi sur le site Web de l'entité framework. Mon problème a été provoqué par mes propriétés de modèle ContactInformation, 'contactid' & 'contacttypeid' n'étant pas nullable. Une fois que j'ai résolu tout cela avec UpdateModel() a fonctionné correctement. Merci beaucoup!

3

Il y a quelques choses qui se passent ici.

Si vous êtes configuré pour un chargement différé, les objets enfants ne sont chargés que si vous leur demandez de charger. Cela peut être fait avec ce qui suit dans votre requête.

..

context.Contacts.Include(c => c.ContactInfos).Include(c => c.ContactInfos.ContactInfoType) 

voir this article pour plus de détails sur la fabrication d'objets sûrs sont chargés que vous le souhaitez. Si vous ne voulez pas enregistrer contactinfo et contactinfotype (car ils ne sont pas chargés ou que vous ne voulez pas), vous devrez indiquer au contexte de ne pas enregistrer les objets enfants qui ne devraient pas être mis à jour. Cela peut être fait en utilisant:

..

context.StateManager.ChangeObjectState(entity.ContactInfos.ContactInfoType, EntityState.Unchanged); 

Je trouve que je dois faire en cas de changement/en utilisant un objet de pays aux données utilisateur. Je ne veux certainement jamais que cela soit mis à jour par un utilisateur.

Au milieu d'écrire un peu d'un guide à tout cela, mais pourrait être des semaines jusqu'à ce qu'il soit fait sur mon blog

MVC ne stockera pas/renvoyer tout ce que vous ne mettez pas en la forme. Si vous envoyez une hiérarchie d'objets au formulaire et que les valeurs ne sont pas représentées dans les entrées masquées, elles reviendront vides sur votre modèle. Pour cette raison, je rends généralement les modèles de vue qui sont éditables seulement les versions des entités avec ToEntity et une méthode ToModel sur eux. Cela me couvre aussi pour la sécurité car je ne veux pas toutes sortes d'identifiants d'utilisateur dans les entrées cachées, juste pour que mes entités soient directement mappées dans MVC (voir this article on overposting).

J'aurais pensé que le fait que vos propriétés de contactinfo soient définies sur virtual, le UpdateModel ne me dérangerait pas si elles n'existaient pas sur le retour, mais je pourrais bien me tromper car je ne l'ai pas essayé.

+0

Mes propriétés infoinfo et contactinfotype sont marquées comme virtuelles. J'obtiens mon objet contact du contexte, par un simple context.Contact.SingleOrDefault (c => c.ContactId == id); –

+0

OK, relu ma réponse et il a été un peu biaisé édité maintenant. Avez-vous essayé d'inclure explicitement? J'ajoute généralement un niveau de chargement par défaut dans mes méthodes GetQuery de référentiel. Cela ressemblerait à l'exemple de mon premier point. Changez votre contexte.Contactez.SingleOrDefault (c => c.ContactId == id) à context.Contact.Include (c => c.ContactInfos) .SingleOrDefault (c => c.ContactId == id) – Gats

+0

J'ai essayé d'ajouter le inclut, mais cela n'a rien changé et j'ai toujours la même erreur. Toutes les valeurs dans le formulaire sont correctement mappées à la variable de personne et tout semble bien quand vous déboguez. Cependant, quand je préforme le updatemodel() il semble annuler les références et quand je l'enregistre échoue. –

Questions connexes