Почему Entity Framework не инициализирует мои навигационные коллекции?

StackOverflow https://stackoverflow.com//questions/21043998

Вопрос

Я создаю систему администрирования турниров ASP.NET MVC4, которая в качестве содержащего класса Tournament с коллекцией Round объекты.Сначала я новичок в коде EF, но я понял, что EF - это предполагается инициализировать объекты моей коллекции с наблюдаемыми прокси-классами при создании экземпляра, если я объявил их виртуальными.Почему они равны нулю, когда я пытаюсь добавить к ним элементы из контроллера ASP.NET в приведенном ниже коде?

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

обновление

Повторная инициализация DataContext после сохранения объекта решает мою проблему.Но не в том смысле, в каком нужно.Первоначальный вопрос остается в силе.

Измененный 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 });
}
Это было полезно?

Решение

Это сработало бы только так, как вы ожидаете если бы ты был присоединение созданный dbTournament к контексту.Только в этом случае создание коллекции и подготовка ее к отложенной загрузке имеет смысл.Но ты такой добавление то dbTournament как новая сущность, и в этом случае не может быть никаких зависимых Rounds в базе данных, которые могли бы ссылаться на новый турнир, следовательно, запрос отложенной загрузки в любом случае не вернул бы результат, и EF в первую очередь не создает коллекцию для отложенной загрузки.

Вы мог бы применять хитрости например, прикрепление dbTournament сначала и после этого добавляем его в контекст.Но это привело бы только к ненужным запросам к базе данных, вызванным отложенной загрузкой, без результата и довольно халтурно.На мой взгляд, самым простым и разумным решением является либо стандартная инициализация коллекции в конструкторе по умолчанию...

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);
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top