为什么Entity Framework没有初始化我的导航集合?

时间:2014-01-10 12:07:55

标签: asp.net-mvc entity-framework ef-code-first entity-framework-5

我正在创建一个ASP.NET MVC4锦标赛管理系统,该系统包含一个包含TournamentRound个对象的类public class Tournament { public int Id { get; set; } [Required] public String Name { get; set; } public virtual ICollection<Contestant> Contestants { get; set; } public virtual ICollection<Round> Rounds { get; set; } public void InitializeDefaults() { var round = new Round("Round 1"); Rounds.Add(round); // Generates NullReferenceException when called from controller } } public class Round { public long Id { get; set; } public int MaxContestants { get; set; } public String Title { get; set; } public Round() { } public Round(string title) : this() { Title = title; } } public class MainController { // (...) [HttpPost] public ActionResult CreateTournament(Tournament tournament) { var db = new DataContext(); var dbTournament = db.Tournaments.Create(); dbTournament.Name = tournament.Name; db.Tournaments.Add(dbTournament); dbTournament.InitializeDefaults(); db.SaveChanges(); return RedirectToRoute(new { action = "Main", tournamentId = dbTournament.Id }); } } public class DataContext : DbContext { public IDbSet<Tournament> Tournaments { get; set; } public IDbSet<Judge> Judges { get; set; } public IDbSet<Contestant> Contestants { get; set; } } 。我是EF Code First的新手,但是我已经理解EF是supposed to initialize我的集合对象,在实例化时观察到代理类,只要我将它们声明为虚拟。当我尝试在下面的代码中从ASP.NET控制器向它们添加元素时,为什么它们为空?

CreateTournament

更新

保存实体后重新初始化dataContext,解决了我的问题。但不是正确的方式。原始问题代表。

改为[HttpPost] public ActionResult CreateTournament(Tournament tournament) { var db = App.ServiceLocator.GetDataBase(); db.Tournaments.Add(tournament); db.SaveChanges(); db.Dispose(); // Reinitializing the datacontext db = App.ServiceLocator.GetDataBase(); var dbTournament = db.GetTournament(tournament.Id); dbTournament.InitializeDefaults(); db.SaveChanges(); return RedirectToRoute(new { action = "Main", tournamentId = dbTournament.Id }); } - 方法

{{1}}

1 个答案:

答案 0 :(得分:4)

它只会像您期望if you were attaching创建的dbTournament上下文一样。只有在这种情况下,创建集合并为延迟加载做准备才有意义。但是你添加 dbTournament作为新实体,在这种情况下,数据库中不能有任何可以引用新锦标赛的依赖Round,因此延迟加载查询无论如何都不会返回结果,并且EF不会首先为延迟加载创建集合。

could apply tricks首先要附加dbTournament,然后将其添加到上下文中。但是这只会产生由延迟加载触发的不必要的数据库查询而没有结果,而且相当hacky。在我看来,最简单和最合理的解决方案是默认构造函数中的标准集合初始化......

public Tournament()
{
    Rounds = new HashSet<Round>();
}

...或至少是InitializeDefaults方法中的警卫:​​

public void InitializeDefaults()
{
    var round = new Round("Round 1");
    if (Rounds == null)
        Rounds = new HashSet<Round>();
    Rounds.Add(round);
}