0

Hope someone can help me with this.

I have a controller in my ASP.NET MVC project that is used for editing a so called survey form. The survey form has a 1-to-1 relation with objects of type Form. When saving the survey form I also want to set the name of the form. However the form property is null. The FormID property has the correct value (using database first, EF5). Here is the problem.

    [HttpPost]
    public ActionResult Edit(SurveyForm surveyform)
    {
      if (ModelState.IsValid)
        {
            db.Entry(surveyform).State = EntityState.Modified;

            // This cannot be done because surveyform.Form is null
            surveyform.Form.Name = "Wish this would work!";


            db.SaveChanges();
        }
    }

My question is: how can I 'attach' surveyform to the model so that is loads related data?

Thanks in advance!

2
  • How are you passing SurveyForm as a parameter to Edit method? Are you POSTing it? Commented Sep 1, 2013 at 13:40
  • Yes it's a post. It is like the scaffolding code. Commented Sep 1, 2013 at 16:24

4 Answers 4

1

At a guess, I'd say the entity being POSTed back isn't being tracked, so Entity Framework doesn't realise it's from the database. The line db.Entry(surveyForm) gets the entry matching the POSTed form, but you're not retaining it. Try this:

[HttpPost]
public ActionResult Edit(SurveyForm surveyform)
{
  if (ModelState.IsValid)
    {
        var formEntry = db.Entry(surveyform);

        formEntry.State = EntityState.Modified;
        formEntry.Form.Name = "This might work...";

        db.SaveChanges();
    }
}

Hopefully, the .Entry() will get you the database's version. Unfortunately, you'll probably have to copy the property values accross, although you might find you can use .Attach() and then copy over the navigation properties from the database's version.

Having said that, it's generally a good idea to not use your database models in the view if you can help it; separation of concerns and all that. If there's more than a couple of properties on that model that are needed for the database but not the view (or vice versa) then you might want to use a local view model for it and just copy the properties to a freshly-retrieved database entity.

Sign up to request clarification or add additional context in comments.

2 Comments

Separation of concerns is ofcourse always a winning lotery number, but actually I thought that this (automatically creating an object and copying the properties from the form post) was one of the gems of Microsoft's implementation of MVC. I took the scaffolding as good practice and so using the objects from the model felt the right way and pretty natural.
I have to admit, I do like that feature - it's one of the reasons I like Entity Framework and ASP.NET MVC as a combo. If done right, you can keep your EF classes pretty clean, in which case separate viewmodels aren't really required. There's also the Bind attributes you can use to prevent over-POSTing and the like.
1

Try:

db.Entry(surveyform).Reference(x => x.Form).Load();
surveyform.Form = db.Entry(surveyform).Reference(x => x.Form).CurrentValue;

Comments

0

In your model, make sure you have a navigation propery like this:

public virtual Form Form { get; set; }

And then in your DbContext:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
 {
    modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    modelBuilder.Entity<SurveyForm>().HasOptional(p => p.Form);
 }

HasOption can be replaced with HasRequired.

I have never had the exact issue you are having, so I hope this helps.

Comments

0

Eventually I combined multiple suggestions above and ended up with the following.

I added the following to my view:

    @Html.TextBox("formName", Model.Form.Name)

and then changed the code in my controller to:

    [HttpPost]
    public ActionResult Edit(string formName, SurveyForm surveyForm)
    {
        if (ModelState.IsValid)
        {
            var surveyFormEntry = db.Entry<SurveyForm>(surveyForm);
            db.SurveyForms.Attach(surveyForm);
            surveyFormEntry.State = EntityState.Modified;

            surveyFormEntry.Reference(x => x.Form).Load();
            surveyForm.Form = db.Entry(surveyForm).Reference(x => x.Form).CurrentValue;
            surveyForm.Form.Name = formName;

            db.SaveChanges();
            return RedirectToAction("Index", new { surveyId = surveyForm.SurveyID });
        }

It was a lot of trial and error. A way of programming I so disapprove on and dislike but I'm happy it finally works.

Thanks all!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.