2014-11-25 2 views
1

EnitityFramework обрабатывает многие-ко-многим (*: *) с Collection s в модели. Итак, у меня есть таблицы SupportEvent и Employee с (*: *) отношениями и коллекциями в каждом. Мне нужно добавить сотрудников в службу поддержки на странице Razor.Почему изменения в моих Коллекциях не сохраняются в базе данных?

Первоначально, я делал это не так элегантно, передавая данные отдельно через форму. Когда метод Edit(SupportEvent) был назван изменениями, внесенными в коллекцию Employees. Однако, когда я позвонил SaveChanges(supportEvent), изменения не были сохранены в db.

Осмотревшись, я обнаружил, что ViewModels - это способ правильно справиться с этим, поэтому я последовал за MVC 5, Entity Framework 6 and Many to Many Relationship : a step by step View Model approach.

Непосредственная «проблема» я нашел, хотя этот путь может быть больше в соответствии с рисунком, когда я вошел в метод Edit()supportEvent был точно таким же, и результат SaveChanges() тоже. Имена и опечатки в стороне, я не вижу нигде, где мой код отличается значимым образом.

Вот мой код:

// ViewModel 
public class SupportEventViewModel 
{ 
    public SupportEvent SupportEvent { get; set; } 
    public IEnumerable<SelectListItem> AllEmployees { get; set; } 

    private List<int> selectedEmployees; 
    public List<int> SelectedEmployees 
    { 
     get 
     { 
      if (selectedEmployees == null) 
      { 
       selectedEmployees = SupportEvent 
        .Employees 
        .Select(m => m.Id) 
        .ToList(); 
      } 
      return selectedEmployees; 
     } 
     set { selectedEmployees = value; } 
    } 
} 

И Edit():

// SupportEventController - Edit() 
    [HttpPost] 
    [ValidateAntiForgeryToken] 
    public ActionResult Edit(SupportEventViewModel model, bool? active) 
    { 
     foreach(var e in model.SelectedEmployees) 
     { 
      model.SupportEvent.Employees 
       .Add(db.Employees.Find(e)); 
     } 
     if (ModelState.IsValid) 
     { 
      db.Entry(model.SupportEvent).State = EntityState.Modified; 
      db.SaveChanges(); 
      return RedirectToAction(((bool)active) ? 
       "ActiveTicketDetails" : "Details", "Ticket", new { id = model.SupportEvent.TicketId }); 
     } 
     return View(model); 
    } 

И частичное редактирование:

// The partial view/form 
@model ProjectWhiteWave.ViewModels.SupportEventViewModel 

@{ 
    Layout = null; 
} 

<!DOCTYPE html> 

<html> 
<head> 
    <meta name="viewport" content="width=device-width" /> 
    <title></title> 
</head> 
<body> 
    @Html.AntiForgeryToken() 
    <div class="form-horizontal"> 
     <h4>SupportEvent</h4> 
     <hr /> 
     @Html.ValidationSummary(true) 
     @Html.HiddenFor(model => model.SupportEvent.SupportEventId) 

     <div class="form-group"> 
      @Html.LabelFor(model => model.SupportEvent.DateOpened, new { @class = "control-label col-md-2" }) 
      <div class="col-md-10"> 
       @Html.EditorFor(model => model.SupportEvent.DateOpened) 
       @Html.ValidationMessageFor(model => model.SupportEvent.DateOpened) 
      </div> 
     </div> 
     <div class="form-group"> 
      @Html.LabelFor(model => model.SupportEvent.DateClosed, new { @class = "control-label col-md-2" }) 
      <div class="col-md-10"> 
       @Html.EditorFor(model => model.SupportEvent.DateClosed) 
       @Html.ValidationMessageFor(model => model.SupportEvent.DateClosed) 
      </div> 
     </div> 
     <div class="form-group"> 
      @Html.LabelFor(model => model.AllEmployees, "Technicians", new { @class = "control-label col-md-2" }) 
      <div class="col-md-10"> 
       @Html.ListBoxFor(model => model.SelectedEmployees, Model.AllEmployees) 
      </div> 
     </div> 
     <div class="form-group"> 
      @Html.LabelFor(model => model.SupportEvent.Description, new { @class = "control-label col-md-2" }) 
      <div class="col-md-10"> 
       @Html.EditorFor(model => model.SupportEvent.Description) 
       @Html.ValidationMessageFor(model => model.SupportEvent.Description) 
      </div> 
     </div> 
     <div class="form-group"> 
      <div class="col-md-offset-2 col-md-10"> 
       <input type="submit" value="Save" class="btn btn-default" /> 
      </div> 
     </div> 
    </div> 
</body> 
</html> 

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

Что мне не хватает/делает что-то плохое, что предотвращает сохранение данных в базе данных?

ответ

0

я думаю, что эта линия:

model.SupportEvent.Employees.Add(db.Employees.Find(e)); 

должны быть заменены на этой линии:

model.SupportEvent.Employees.Add(db.Employees.Find(emp => emp.Id = e)); 

после е на самом деле идентификатор конкретного работника (то есть смысл от Выберите (m => m.Id) on SelectedEmployees)

+0

Это не похоже на это. Хотя, e, это Id, find находит, что он основан на этом. Когда вызывается «Сохранить», сотрудники добавлены в локальный экземпляр, ModelState действителен, но ничего не записывается. – ChiefTwoPencils

0

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

Если вы уже это сделали, просто проигнорируйте предыдущий оператор, но посмотрите на следующий код, чтобы увидеть, как я устанавливаю простые отношения многих-многих и вижу, помогает ли это.

public class Employee 
{ 
    [Key] 
    public Guid Id { get; set; } 
    public virtual ICollection<SupportEvent> SupportEvents { get; set; } 
} 

public class SupportEvent 
{ 
    [key] 
    public Guid Id { get; set; } 
    public virtual ICollection<Employee> Employees { get; set; } 
} 

// DbContext 
public DbSet<Employee> Employees { get; set; } 
public DbSet<SupportEvent> SupportEvents { get; set; } 

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 

    modelBuilder.Entity<Employee>() 
      .HasMany(x => x.SupportEvents) 
      .WithMany(x => x.Employees) 
      .Map(m => 
      { 
       m.ToTable("EmployeeSupportEvents"); 
       m.MapLeftKey("EmployeeId"); 
       m.MapRightKey("SupportEventId"); 
      } 
} 
var event = db.SupportEvents.FirstOrDefault(x => x.Id == "whatever"); 
var employee = db.Employee.FirstOrDefault(x => x.Id = "blah"); 
if(event == null || employee == null) return NotFound(); 

event.Employees.Add(employee); 
// OR 
employee.SupportEvents.Add(event); 

db.SaveChanges(); 
+0

Да, вот что я говорю. Итак, я видел этот подход, ища решения. Я начал этот проект с Model First; когда я запускаю проект с точками останова, установленными в построителе моделей, никто не попадает. Вы знаете, как его вызвать, и если это нарушит мой рабочий поток. – ChiefTwoPencils

+0

Как вы вводите свой DbContext в свой контроллер? он должен вызывать этот метод при его создании. В моем случае, когда экземпляр контроллера создается через Unity DI. Вы уверены, что используете новый экземпляр для каждого звонка? –

+0

Контроллеры автоматически генерируются. Внутри контроллера создается единый контекст db. Это не так, как должно быть? Я передаю модель представления в контроллер из формы, как указано выше. – ChiefTwoPencils

Смежные вопросы