2016-09-06 2 views
0

Мне показалось, что я начинаю понимать, как использовать DDL в MVC, но я думаю, что я до сих пор не получаю их надлежащей настройки.MVC 5 DropDownList говорит, что DbContext удален?

У меня есть DropDownList, который я заполняю из Entity Framework и использую репозиторий. Я могу отлаживать код и видеть, что ViewModel заполняется значениями, но как только я доберусь до View I get и ошибки "The operation cannot be completed because the DbContext has been disposed". Я думал, что к тому времени, когда я добрался до просмотра, DbContext больше не нужен?

Я пробовал разные комбинации Html.DropDownList и Html.DropDownListFor и каждый раз, когда я придумываю одно и то же сообщение. Я уверен, что это что-то простое, что я просто не понимаю, но я искал разные примеры и пробовал пару разных комбинаций без везения.

Это мой ViewModel

public class AssignCounselorViewModel 
{ 
    public IEnumerable<SelectListItem> listMerits { get; set; } 

    public int MeritSelectedId { get; set; } 
} 

Это мой контроллер:

public ActionResult AssignCounselor() 
{ 
    var viewModel = new AssignCounselorViewModel(); 
    viewModel.listMerits = MeritCounselorRepository.GetAllMerits(); 

    return View(viewModel); 
} 

Это мой Repository:

public static IEnumerable<SelectListItem> GetAllMerits() 
{ 
    using (DataContext ctx = new DataContext()) 
    { 
     var results = (from m in ctx.MeritBadges 
         select new SelectListItem 
         { 
          Value = m.ID.ToString(), 
          Text = m.MeritBadgeName 
         } 
         ).OrderBy(o => o.Text); 

     return new SelectList(results, "Value", "Text"); 
    } 
} 

Это мой Вид:

<div class="row"> 
    <div class="col-md-12"> 
     @Html.DropDownListFor(m => m.listMerits, 
       new SelectList(Model.listMerits, "Text", "Value")) 
    </div> 
</div> 

Вот некоторые другие комбинации, которые я пробовал.

@Html.DropDownList("ddlMerit", new SelectList(Model.listMerits, "Value", "Text"), new { style = "width:100px;height:31px" }) 


@Html.DropDownListFor(m => Model.listMerits, Model.listMerits, "--Select--"); 

ответ

2

Попробуйте

public static IEnumerable<SelectListItem> GetAllMerits() 
{ 
    using (DataContext ctx = new DataContext()) 
    { 
     var results = (from m in ctx.MeritBadges 
         select new SelectListItem 
         { 
          Value = m.ID.ToString(), 
          Text = m.MeritBadgeName 
         } 
         ).OrderBy(o => o.Text).ToArray(); // .ToArray() => materialize collection. After this data will be returned from database. 

     return new SelectList(results, "Value", "Text"); 
    } 
} 
+0

Отредактировано. Неправильная линия, извините. – tym32167

+0

Я вижу, что .ToList() работает также. Существует ли какая-либо реальная разница между использованием .ToArray() и .ToList()? – Caverman

+0

@Caverman только какой тип коллекции вы хотите получить.Оба они перечисляют сбор источников, поэтому оба они будут вынуждены извлекать данные из БД. Я выбрал Array, потому что он только для чтения и потратил немного меньше памяти. – tym32167

0

Чтобы расширить ответ tym32167, которая должна решить эту проблему ...

using (DataContext ctx = new DataContext()) 
{ 
    var results = (from m in ctx.MeritBadges 
        select new SelectListItem 
        { 
         Value = m.ID.ToString(), 
         Text = m.MeritBadgeName 
        } 
        ).OrderBy(o => o.Text); 

    return new SelectList(results, "Value", "Text"); 
} 

Это возвращает IQueryable<SelectListItem>, что запрос, который не является но выполняется в отношении базы данных, но содержит инструкции для вызова при отправке команды для выполнения. Это возвращается в пределах облачный DbContext, который будет удален после завершения вызова. После выполнения IQueryable результаты будут преобразованы в IEnumerable (.ToList становится List<T>, .ToArray() становится массивом и т. Д.), А DbContext.

Итак, когда вы вызываете IQueryable<MeritBadge> в два раза, как это:

<div class="row"> 
    <div class="col-md-12"> 
     @Html.DropDownListFor(m => m.listMerits, 
       new SelectList(Model.listMerits, "Text", "Value")) 
    </div> 
</div> 

Первый экземпляр m => m.listMerits выполняет запрос и утилизовать контекст; затем вызывается model.ListMerits, который попытается снова выполнить IQueryable, чтобы перечислить данные, но контекст уже удален.

Редактировать: tym32167 указал, что у меня был тип IQueryable.

+1

Просто выполните clerify, метод repo вернет '' 'SelectList'''. Все остальные ок. :) – tym32167

+1

Спасибо за объяснение. Это имеет большее значение, почему я получаю контекстную ошибку. – Caverman

+0

Просто, чтобы уточнить, способ, которым я изначально звонил, чтобы заполнить DDL, выполнял запрос дважды, один раз с использованием {m => m.listMerits} и снова с помощью SelectList (Model.listMerits), и это был второй вызов что вызывало ошибку, потому что контекст уже был удален. Однако использование .ToArray() или, возможно, .ToList() заставляет EF немедленно вызывать запрос и заполнять ViewModel. Не вызвав .ToArray, код ожидал заполнения, пока он не был вызван в представлении? – Caverman