2

나는 Round 컬렉션이 포함 된 Tournament 클래스를 포함하는 ASP.NET MVC4 토너먼트 관리 시스템을 만들고 있습니다. 저는 EF Code First에 익숙하지 않지만 EF가 가상으로 선언 된 한 인스턴스화시 관찰 된 프록시 클래스가있는 supposed to initialize 컬렉션 객체라는 것을 이해했습니다. 아래 코드에서 ASP.NET 컨트롤러의 요소를 추가하려고 할 때 null 인 이유는 무엇입니까? 엔티티를 저장 한 후 데이터 컨텍스트를 다시 초기화 Entity Framework에서 내 탐색 모음을 초기화하지 않는 이유는 무엇입니까?

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; } 
} 

갱신

, 내 문제를 해결합니다. 그러나 올바른 방법이 아닙니다. 원래의 질문입니다. CreateTournament 변경된

[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 }); 
} 
+0

은을 가지고 : 제 생각에는 가장 간단하고 저렴한 솔루션은 InitializeDefaults 방법의 기본 생성자의 표준 컬렉션을 초기화 ...

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

... 또는 적어도 가드 중 하나입니다 보세요 : http://stackoverflow.com/questions/4069563/why-is-my-entity-framework-code-first-proxy-collection-null-and-why-cant-i-set – Marthijn

답변

3

당신이 컨텍스트에 생성 된 dbTournamentif you were attaching을 예상대로 그것은 단지 일하는 것이를 -method. 이 경우에만 컬렉션을 만들고 지연로드를 준비하는 것이 좋습니다. 그러나 당신은 dbTournament을 새로운 엔티티로 추가합니다.이 경우에는 새로운 토너먼트를 참조 할 수있는 데이터베이스에 Round의 종속물이 존재할 수 없으므로 지연로드 쿼리는 어쨌든 결과를 반환하지 않으며 EF 처음에는 느린 로딩을위한 콜렉션을 생성하지 않습니다.

could apply tricks 먼저 dbTournament을 첨부하고 문맥에 추가하는 것과 같습니다. 그러나 이것은 결과가없는 지연로드에 의해 트리거 된 불필요한 데이터베이스 쿼리만을 생성하고 오히려 해킹 할 수 있습니다.

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

만약 내가' HashSet'을 생성자에서 사용하면이 SO 응답의 Rowan Miller에서 인용 한대로 추후에 읽을 때 * 변경 추적 프록시 *를 방해하지 않을까요? http://stackoverflow.com/a/4069727/507339. 나는 세이프 사이드에있는 'InitializeDefaults'에있는 경비원에게 갈거야. 부수적으로, Entity Framework의이 부분이 제대로 문서화되어 있지 않다고 생각합니다. (또는 찾지 못했습니다.) – Nilzor

관련 문제