简体   繁体   中英

Entity Framework does not update Foreign Key object

I'm new to Entity Framework and this behavior confuses me:

    [Table("ClinicProfile")]
    public class ClinicProfile
    {
        [Key]
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }

        [ForeignKey("ContactData")]
        public int ContactDataId { get; set; }
        public ContactData ContactData { get; set; }
    }

    [Table("ContactData")]
    public class ContactData
    {
         [Key]
         [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
         public int Id { get; set; }

         ...
    }

When inserting the new entity all works fine - ContactData is saved to the table and foreign key assigned:

clinicProfile.ContactData = contactData;
SharedContext.Current.Entry(clinicProfile).State = EntityState.Added;
SharedContext.Current.SaveChanges();

But when I try to update this entity, ContactData don't get an update.

clinicProfile.ContactData = contactData;
SharedContext.Current.Entry(clinicProfile).State = EntityState.Modified;
SharedContext.Current.SaveChanges();

Must I mark ContactData as modified too? Or am I just doing something wrong?

EDIT-2 - The answer

Use this code, if contactData is the new object in the DB, with the new object id.

clinicProfile.ContactData = contactData;
SharedContext.Current.Entry(clinicProfile).State = EntityState.Modified;
SharedContext.Current.SaveChanges();

If you just want to update the old contactData, it would be correct to use this code:

SharedContext.Current.Entry(contactData).State = EntityState.Modified;
SharedContext.Current.SaveChanges();

EDIT - extended code snapshot

Code from MVC controller, postback from the page. Parameters "clinicProfile" and "contactData", "adressData" contain valid Id's.

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Modify(ClinicProfile clinicProfile, ContactData contactData, AdressData adressData)
        {
            ViewBag.Id = clinicProfile.Id;

            if (ModelState.IsValid)
            {
                if (clinicProfile.Id != 0)
                {
                    clinicProfile.ContactData = contactData;
                    clinicProfile.AdressData = adressData;
                    clinicProfile.AdressDataComposed = adressData.ComposeData();
                    clinicProfile.ContactDataComposed = contactData.ComposeData();

                    SharedContext.Current.Entry(clinicProfile).State = EntityState.Modified;
                    SharedContext.Current.SaveChanges();

                    Config.SaveClinicPhoto(clinicProfile.ClinicImageUpload, clinicProfile.Id);
                    Config.SaveClinicPreviewPhoto(clinicProfile.ClinicImageUpload, clinicProfile.Id);

                    return View(new ClinicProfileComposite { AdressData = adressData, ClinicProfile = clinicProfile, ContactData = contactData });
                }

                {
                    clinicProfile.ContactData = contactData;
                    clinicProfile.AdressData = adressData;
                    clinicProfile.AdressDataComposed = adressData.ComposeData();
                    clinicProfile.ContactDataComposed = contactData.ComposeData();

                    SharedContext.Current.Entry(clinicProfile).State = EntityState.Added;
                    SharedContext.Current.SaveChanges();

                    Config.SaveClinicPhoto(clinicProfile.ClinicImageUpload, clinicProfile.Id);
                    Config.SaveClinicPreviewPhoto(clinicProfile.ClinicImageUpload, clinicProfile.Id);

                    return RedirectToAction("Info", new { id = clinicProfile.Id });
                }
            }

            ViewBag.Id = clinicProfile.Id;
            return View(new ClinicProfileComposite { AdressData = adressData, ClinicProfile = clinicProfile, ContactData = contactData });
        }

you just misplaced the foreign key property

 [Table("ClinicProfile")]
    public class ClinicProfile
    {
        [Key]
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }

        //[ForeignKey("ContactData")] here the wrong place
        public int ContactDataId { get; set; }
        [ForeignKey("ContactDataId")] // here the correct place
        public ContactData ContactData { get; set; }
    }

    [Table("ContactData")]
    public class ContactData
    {
         [Key]
         [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
         public int Id { get; set; }

         ...
    }

and when you want to set the foreign key data, you can either set the ContactDataId value or retrieve the ContactData from Database as object and set it in the ClinicProfile

// according to your data posted later

[HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Modify(ClinicProfile clinicProfile, ContactData contactData, AdressData adressData)
        {
            ViewBag.Id = clinicProfile.Id;

            if (ModelState.IsValid)
            {
                if (clinicProfile.Id != 0)
                {
                    // here you want to tell the SharedContext to attach the contactData to the clinicProfile 
                    // you need to retrieve the lastVersion of contactData from db
                    var currentContactData=SharedContext.Current.ContactData.Single(t=>t.Id=contactData.Id);
                    // update the changed data in the currentContactData
                    clinicProfile.ContactData =currentContactData;  // instead of contactData;
                    clinicProfile.AdressData = adressData;
                    clinicProfile.AdressDataComposed = adressData.ComposeData();
                    clinicProfile.ContactDataComposed = contactData.ComposeData();

                    SharedContext.Current.Entry(clinicProfile).State = EntityState.Modified;
                    SharedContext.Current.SaveChanges();

                    Config.SaveClinicPhoto(clinicProfile.ClinicImageUpload, clinicProfile.Id);
                    Config.SaveClinicPreviewPhoto(clinicProfile.ClinicImageUpload, clinicProfile.Id);

                    return View(new ClinicProfileComposite { AdressData = adressData, ClinicProfile = clinicProfile, ContactData = contactData });
                }

                {
                    clinicProfile.ContactData = contactData;
                    clinicProfile.AdressData = adressData;
                    clinicProfile.AdressDataComposed = adressData.ComposeData();
                    clinicProfile.ContactDataComposed = contactData.ComposeData();

                    SharedContext.Current.Entry(clinicProfile).State = EntityState.Added;
                    SharedContext.Current.SaveChanges();

                    Config.SaveClinicPhoto(clinicProfile.ClinicImageUpload, clinicProfile.Id);
                    Config.SaveClinicPreviewPhoto(clinicProfile.ClinicImageUpload, clinicProfile.Id);

                    return RedirectToAction("Info", new { id = clinicProfile.Id });
                }
            }

            ViewBag.Id = clinicProfile.Id;
            return View(new ClinicProfileComposite { AdressData = adressData, ClinicProfile = clinicProfile, ContactData = contactData });
        }

// as result of comments discussion

if you want to update contactData , you need to tell the context that contactData was modified by setting its state to modified and as you mentioned in your last post, it will work if you make the following:

SharedContext.Current.Entry(clinicProfile).State = EntityState.Modified; SharedContext.Current.Entry(contactData).State = EntityState.Modified; SharedContext.Current.SaveChanges();

hope that this will help you

You just need to set ContactDataId , when updating

clinicProfile.ContactData = contactData;
clinicProfile.ContactDataId = contactData.Id;
SharedContext.Current.Entry(clinicProfile).State = EntityState.Modified;
SharedContext.Current.SaveChanges();

if you set to existing ClinicProfile new ContactData you should first save new ContactData to db, second get its new Id and third update ClinicProfile with new ContactDataId.

clinicProfile.ContactDataId = newContactData.Id;
SharedContext.Current.Entry(clinicProfile).State = EntityState.Modified;
SharedContext.Current.SaveChanges();

if you want to update existing ContactData properties then you should save only it.

SharedContext.Current.Entry(existingContactData).State = EntityState.Modified;
SharedContext.Current.SaveChanges();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM