3

My ASP.NET MVC 4 application uses Entity Framework v5, the Ninject and Ninject.MVC3 nuget packages, and data is being stored in SQL Server Express. Models were generated using the "EF 5.x DbContext Generator for C#" template. Lazy Loading Enabled is set to True in my edmx.

I'm using the repository pattern, with my repository and context living in a separate project in my solution that is referenced by the ASP.NET MVC 4 project.

So, the problem -- after saving a new object ("Trade") that's a property of a view model, I query the repository for that object. At that point, the navigation properties I would expect to be populated are null. See the comment in the Create() method below.

If I retrieve an existing Trade from the db (one that I didn't just save), all the navigation properties seem to be populated.

I found a report of a similar/identical problem on this page. The author of the article states, "I think this is a glitch in DbContext. Namely, Lazy loading for the foreign key navigation property doesn’t work for the newly added item, but the lazy loading for the navigation property in the many end works fine, such as Teacher.Classes. This glitch occurs only for the newly added item. If you don’t load Class.Teacher explicitly above for the newly added item, it will be null if it hasn’t been loaded somewhere in Entity Framework. However, if it is loaded already somewhere, then C.Teacher can be automatically resolved by Entity Framework. Whereas, for ObjectContext, lazy loading is fine for all types of navigation properties."

My controller's Create method looks like this:

[HttpPost]
public ActionResult Create(TradeViewModel tradeViewModel)
{
    if (ModelState.IsValid)
    {
        _employeesRepository.SaveTrade(tradeViewModel.Trade);
        var trade =
            _employeesRepository.Trades.First(
                x =>
                x.RequesterId == tradeViewModel.Trade.RequesterId &&
                x.RequesterWorkDate == tradeViewModel.Trade.RequesterWorkDate);

        // Null reference encountered below, as trade.TradeType and trade.Employee are both null
        String userMessage = "New " + trade.TradeType.TradeTypeDescription + " requested with '" + ControllerHelpers.GetDisplayName(trade.Employee) + "'";
        TempData["UserMessage"] = userMessage;

        return RedirectToAction("Index");
    }
    return View();
}

The SaveTrade() method in the employee repository looks like:

public void SaveTrade(Trade trade)
{
    var data = (from t in _context.Trades
                where t.RequesterId == trade.RequesterId
                      && t.RequesterWorkDate == trade.RequesterWorkDate
                select t);
    if (!data.Any())
    {
        _context.Trades.Add(trade);
    }
    _context.SaveChanges();
}

And finally, Trades in _employeesRepository looks like:

public IQueryable<Trade> Trades
{
    get { return _context.Trades; }
}
Nick Silberstein
  • 833
  • 2
  • 8
  • 24

2 Answers2

2

EF's deffered loading could be causing this. Try eagerly loading the employee like below

  var trade =
        _employeesRepository.Trades.Include("TradeType").Include("Employee").First(
     x =>
            x.RequesterId == tradeViewModel.Trade.RequesterId &&
            x.RequesterWorkDate == tradeViewModel.Trade.RequesterWorkDate);

You can get a clearer picture if you try looking at the query that's being generated by EF. I'd use EfProfiler http://www.hibernatingrhinos.com/products/EFProf for this type of analysis. You can of course use your favorite tool.

Hope this helps.

Update

Here'a link to Julie Lerman's article that may help in understanding the deferred loading concepts http://msdn.microsoft.com/en-us/magazine/hh205756.aspx

Added tradetype in the include

Yogiraj
  • 1,952
  • 17
  • 29
  • [An article](http://www.codeproject.com/Articles/396822/Basic-Handling-and-Tips-of-Database-Relationships) I found says, "I think this is a glitch in DbContext. Namely, Lazy loading for the foreign key navigation property doesn’t work for the newly added item, but the lazy loading for the navigation property in the many end works fine, such as Teacher.Classes. This glitch occurs only for the newly added item." I'm just surprised that very few people seem to be running into this problem. – Nick Silberstein Dec 04 '12 at 23:56
  • Good article.. What query is it generating? It does not create proper joins even after eagerly loading those? – Yogiraj Dec 05 '12 at 00:16
  • A colleague of mine faced the similar problem, it looks like _context.refresh() fixed it for him. – Yogiraj Dec 05 '12 at 00:37
  • Eager loading does work fine (if I set lazy loading enabled to false, and add .Include() statements in _employesRepository.Trades). It's the default, lazy loading enabled = true setting that I'm having the problem with. There is no Refresh() in DbContext; I tried [this method](http://stackoverflow.com/questions/5221314/refresh-entity-instance-with-dbcontext) at the end of my save method but it did not help (navigation properties were still null after retrieving the saved trade). – Nick Silberstein Dec 05 '12 at 00:48
  • @Yogiraj: OMG OMG OMG OMG OMG OMG!!! My problem is solved!!! Thanks a bunch for the article and for the post. I was having the same problem for 2 weeks now. I had Lazy loading enabled, but I decided to "force" an Eager Load.... It is working now :D :D :D Woooohoooooo! – Jose A Jul 10 '16 at 11:29
0

You are probably creating the Trade by using New(). You should use your DBContext's Trades.Create() method instead.

Chalky
  • 1,624
  • 18
  • 20