我有4个模型-2个域模型和2个DTO
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; }
}下面是我的自动映射程序配置
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);
}我对此并不完全满意,但我不认为有更干净的方法来处理这个有点复杂的场景……
现在它可以工作了,我想至少重构它,使用存储库模式,或者以一种控制器操作不那么复杂的方式。这最终将成为产品代码:s
有人能给我一些关于如何重构的建议吗?请帮帮忙。
发布于 2011-07-26 14:59:15
我会使用一个服务层,如下所示:
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应该隐藏在存储库的抽象之后。
发布于 2017-09-24 04:55:31
我意识到这个问题已经停用了一段时间,但我也遇到了同样的问题,尽管我会把我的解决方案发布给其他任何在编辑过程中无法保存嵌套模型的人。
[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);
}基本上,您希望将每个嵌套模型的State设置为Modified,以及将根模型设置为Modified。
https://stackoverflow.com/questions/6826225
复制相似问题