elwyn
elwyn

Reputation: 10521

MVC 3 - Widget fine in Create action, but has null values in View action

I'm using ASP.NET MVC3, with Entity Framework.

I have a Widget controller, with standard Widget CRUD actions.

In my Create action, I successfully create a new Widget object, which has two FooBar objects. This is added to my database just fine, and the action the redirects to the View action.

[HttpPost]
public ActionResult Create(Widget model)
{
    if (ModelState.IsValid)
    {
        //At this point, the widget has two FooBar properties. I can see the values for these FooBars just fine.
        if (repo.AddWidget(model))
        {
            ViewBag.Message = "Your widget has been created.");
            return RedirectToAction("View", new { id = model.Id });
        }
        else
        {
            ViewBag.Error = "Woops, something went wrong. Please try again.");
        }
    }
    return View(model);
}

In the View action, I fetch the newly created Widget from my repository - except now the two FooBar properties are null.

public ActionResult View(int id)
{
    var widget = repo.GetWidget(id);

    if (widget == null)
    {
        ViewBag.Error = "No widget found for the specified ID";
        return RedirectToAction("Find");
    }
    //At this point, the widget has two null values for the FooBar1 and FooBar 2 properties
    return View(widget);
}

In the database itself I can see the correct FooBar ID values on my Widget.

My model is set up pretty much exactly the same as shown in this tutorial: http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx

public class WidgetContext : DbContext
{
    public DbSet<Widget> Widgets { get; set; }
    public DbSet<FooBar> FooBars { get; set; }
}

Can anyone suggest how I might start tracking this issue down?

Update: I should clarify the values are null whenever I call the View action, not only after a Create.

Upvotes: 0

Views: 626

Answers (1)

Ladislav Mrnka
Ladislav Mrnka

Reputation: 364369

Looks like FooBar is separate entity and FooBar1 and FooBar2 are navigation properties. In such case you must either explicitly say you want to loade them (we call this eager loading):

var widget = context.Widgets
                    .Include(w => w.FooBar1)
                    .Include(w => w.FooBar2)
                    .SingleOfDefault(w => w.Id == id);

Note: Strongly typed Include requires EF 4.1 for EFv1 or EFv4 use:

var widget = context.Widgets
                    .Include("FooBar1")
                    .Include("FooBar2")
                    .SingleOfDefault(w => w.Id == id);

or create custom strongly typed extension method like this.

or you must turn lazy loading on. Lazy loading makes separate queries to database once properties are first accessed in your view. It requires making both FooBar1 and FooBar2 virtual and context must be alive when view is rendered. Usually this is handled by singe context per HTTP request where context is for example created and disposed in custom controller factory or in custom Http module.

Also next time make your question complete please. You have shown a lot of code but the important parts (Windget class and GetById method) are missing. Unfortuanatelly users here aren't oracles so we need to now necessary details. Both action methods are almost irrelevant to your problem.

Upvotes: 1

Related Questions