DbContext 出现问题?在检索新保存的记录后,导航属性为空。

3
我的ASP.NET MVC 4应用程序使用Entity Framework v5,Ninject和Ninject.MVC3 NuGet包,并且数据存储在SQL Server Express中。使用“EF 5.x DbContext生成器 for C#”模板生成模型。我的edmx中启用了延迟加载。
我正在使用存储库模式,我的存储库和上下文位于解决方案中的一个单独项目中,该项目由ASP.NET MVC 4项目引用。
问题在于,在保存视图模型属性之一的新对象(“Trade”)之后,我查询该对象的存储库。此时,我期望被填充的导航属性为空。请参见下面Create()方法中的注释。
如果我从数据库中检索现有的Trade(我没有保存过的Trade),则似乎所有导航属性都已填充。
我在这个页面上找到了一个类似/相同问题的报告。文章的作者指出,“我认为这是DbContext中的一个故障。即外键导航属性的惰性加载对于新添加的项不起作用,但是many end中的导航属性的惰性加载效果很好,例如Teacher.Classes。这个故障仅发生在新添加的项中。如果您不在新添加的项上方显式地加载Class.Teacher,则在Entity Framework中尚未加载的情况下它将为空。但是,如果它已经在某个地方加载了,则Entity Framework可以自动解析C.Teacher。而对于ObjectContext,所有类型的导航属性都可以使用延迟加载。”
我的控制器Create方法如下:
[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();
}

员工存储库中的SaveTrade()方法如下所示:
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();
}

最后,_employeesRepository中的交易如下所示:
public IQueryable<Trade> Trades
{
    get { return _context.Trades; }
}
2个回答

2

EF的延迟加载可能是导致这个问题的原因。尝试像下面一样及早加载员工:

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

如果您尝试查看EF生成的查询,就可以更清楚地了解情况。我会使用EfProfiler http://www.hibernatingrhinos.com/products/EFProf 进行此类分析。当然,您也可以使用您喜欢的工具。
希望这可以帮助您。 更新 这是Julie Lerman的一篇文章链接,可能有助于理解延迟加载概念:http://msdn.microsoft.com/en-us/magazine/hh205756.aspx 在包含中添加交易类型。

我发现的一篇文章说:“我认为这是DbContext中的一个故障。也就是说,对于新添加的项,外键导航属性的延迟加载不起作用,但是在多端的导航属性中,如Teacher.Classes,延迟加载正常工作。这个故障仅出现在新添加的项上。”我很惊讶很少有人遇到这个问题。 - Nick Silberstein
好的文章。它生成了什么查询?即使在急切加载后,它也不能创建适当的连接吗? - Yogiraj
我的一个同事遇到了类似的问题,看起来_context.refresh()可以解决它。 - Yogiraj
急切加载(Eager loading)可以正常工作(如果我将延迟加载设置为false,并在_employesRepository.Trades中添加.Include()语句)。问题出在默认的延迟加载启用=true设置上。DbContext中没有Refresh()方法;我尝试了这个方法,在我的保存方法末尾链接,但它没有帮助(检索保存的交易后,导航属性仍为空)。 - Nick Silberstein
@Yogiraj:天啊,我的问题解决了!非常感谢这篇文章和帖子。我已经遇到同样的问题两个星期了。虽然我启用了懒加载,但我决定“强制”使用急加载……现在它终于可以工作了:D :D :D Woooohoooooo! - Jose A

0

你可能正在使用New()创建交易。相反,你应该使用你的DBContext的Trades.Create()方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接