2011-07-26 54 views
0

我有這樣的4款車型 - 2個域模型和2層的DTO幫助改進(重構)我的代碼。 Automapper - EF - asp.net的MVC-3

public class Project 
    { 
     public int ID { get; set; } 
     public string Name { get; set; } 
     public virtual ICollection<Task> Tasks { get; set; } 
    } 

    public class Task 
    { 
     public int ID { get; set; } 
     public virtual int ProjectID { get; set; } 
     public string Name { get; set; } 
     public virtual Project Project { get; set; } 
    } 

    public class ProjectDTO 
    { 
     [Required] 
     public string Name { get; set; } 
     public List<TaskDTO> Tasks { get; set; } 
    } 

    public class TaskDTO 
    { 
     [Required] 
     public string Name { get; set; } 
     public int ID { get; set; } 
     public bool MarkRemove { get; set; } 
    } 

我的繼承人automapper配置

Mapper.CreateMap<Project, ProjectDTO>(); 
Mapper.CreateMap<ProjectDTO, Project>().ForMember(p =>p.ID, opt=>opt.Ignore()).ForMember(p=>p.Tasks, opt=>opt.Ignore()); 
Mapper.CreateMap<Task, TaskDTO>(); 
Mapper.CreateMap<TaskDTO, Task>().ForMember(task=>task.ProjectID, opt=>opt.Ignore()).ForMember(task=>task.Project, opt=>opt.Ignore()); 

我的繼承人HttpPost編輯操作

[HttpPost] 
     public ActionResult Edit(int id, ProjectDTO p) 
     { 
      if (ModelState.IsValid) 
      { 
       var dbProject = db.Projects.Where(pr => pr.ID == id).Single(); 
       Mapper.Map(p, dbProject); 
       foreach (var task in p.Tasks) 
       { 
        Task dbTask; 
        try 
        { 
         dbTask = dbProject.Tasks.Where(t => t.ID == task.ID).Single(); 
        } 
        catch 
        { 
         dbTask = new Task(); 
         Mapper.Map(task, dbTask); 
         dbProject.Tasks.Add(dbTask); 
        } 
        if (task.MarkRemove) 
        { 
         db.Tasks.Remove(dbTask); 
        } 
        else { 
         Mapper.Map(task, dbTask);      
        }     
       } 
       db.Entry(dbProject).State = EntityState.Modified; 
       db.SaveChanges();     
       TempData["Success"] = "Modelo Valido"; 
       return RedirectToAction("Index"); 
      } 
      return View(p); 
     } 

我不完全滿意這個,但我不認爲有一個更清潔的方法來處理這個有點複雜的場景......

現在,它是工作,我想至少重構這個使用存儲庫模式或東西的方式,控制器動作是不是令人費解的..這最終將產品代碼:■

可以

人給我一些關於如何重構這個的建議? 請幫忙。

回答

1

我會用一個服務層,像這樣:

public interface IProjectsService 
{ 
    void RemoveTasks(int projectId, IEnumerable<int> taskIdsToRemove); 
} 

,然後控制器將取決於該服務層上:

public class ProjectsController : Controller 
{ 
    private readonly IProjectsService _service; 
    public ProjectsController(IProjectsService service) 
    { 
     _service = service; 
    } 

    public ActionResult Edit(int id) 
    { 
     // TODO: Add methods to your service layer 
     // allowing to retrieve projects, then map 
     // the resulting project into a view model 
     throw new NotImplementedException(); 
    } 

    [HttpPost] 
    public ActionResult Edit(int id, ProjectDTO p) 
    { 
     if (!ModelState.IsValid) 
     { 
      return View(p); 
     } 

     var taskIdsToRemove = p.Tasks.Where(x => x.MarkRemove).Select(x => x.ID); 
     _service.RemoveTasks(id, taskIdsToRemove); 
     TempData["Success"] = "Modelo Valido"; 
     return RedirectToAction("Index"); 
    } 
} 

通過這種方式,控制器邏輯更弱耦合到所述我們做數據訪問的方式。這是控制器永遠不必擔心的實現細節。

作爲對RemoveTasks方法的進一步改進,您可以使其返回布爾值,表示操作的成功或失敗以及錯誤消息,以便編輯操作可以重新顯示視圖並顯示錯誤以防萬一出現錯誤。

現在就這個服務層而言,RemoveTasks方法是一個業務操作,它可以建立在多個CRUD操作和一些存儲庫之上。所以這個服務層本身會依賴一個存儲庫。只有這個知識庫必須知道EF或任何你正在使用的數據訪問。

因此,基本上每次看到有人在同一時間詢問關於ASP.NET MVC和EF的問題時,對我而言,這是兩個完全不同的問題。 ASP.NET MVC不應該知道EF的任何內容。 EF應該被隱藏在存儲庫的抽象背後。

+0

感謝您的非常全面的答案..唯一的是,我不僅RemovingTasks。我也在添加和更新它們......你會用同樣的方法來做這件事嗎? – ignaciofuentes

+1

@NachoF的確如此。我沒有注意到這個重要的細節。我仍然會在單個服務方法(例如'UpdateTasks')中完成整個操作,但在這種情況下,除了需要移除的任務的ID列表之外,我們還需要傳遞要更新的任務列表。這個要更新的'Task'列表將使用視圖模型中的AutoMapper構造,完全如您在示例中所做的那樣:'var tasksToUpdate = new List (); Mapper.Map(p.Tasks,tasks);'。 –

+0

這是令人困惑的原因,那麼我在DTO中添加的MarkRemove屬性會在映射中丟失...... UpdateTasks方法無法知道要刪除哪些任務。 – ignaciofuentes

1

我意識到這個問題已暫停一段時間,但我有同樣的問題,雖然我會發布我的解決方案,爲任何其他人在編輯過程中不保存嵌套模型掙扎。

[HttpPost] 
    public ActionResult Edit(ProjectDTO p) 
    { 
     if (ModelState.IsValid) 
     { 
      // *****MODIFIED CODE HERE******** 
      for (int i = 0; i < p.Tasks.Count; i++) 
      { 
        db.Entry(p.Tasks[i]).State = EntityState.Modified; 
      } 

      // ************************************* 

      db.Entry(dbProject).State = EntityState.Modified; 
      db.SaveChanges();     
      TempData["Success"] = "Modelo Valido"; 
      return RedirectToAction("Index"); 
     } 
     return View(p); 
    } 

基本上,您希望將每個嵌套模型的狀態設置爲修改以及根模型。