Помогите улучшить (рефакторинг) мой код.Automapper - EF - asp.net MVC-3 - PullRequest
0 голосов
/ 26 июля 2011

У меня есть эти 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 Edit

[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

Может кто-нибудь дать мне несколько советов о том, как это изменить?пожалуйста, помогите.

Ответы [ 2 ]

1 голос
/ 23 сентября 2017

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

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

По сути, вы хотите установить состояние каждой вложенной модели в значение Modified, а также корневую модель.

1 голос
/ 26 июля 2011

Я бы использовал сервисный слой, например:

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 вы можете сделать так, чтобы он возвращал логическое значение, указывающее на успешное или неудачное выполнение операции, а также сообщение об ошибке, чтобы действие Edit могло снова отобразить представление и показать ошибку в случае, если что-то идет не так.

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

Так что в основном каждый раз, когда я вижу, что кто-то задает вопрос о ASP.NET MVC и EF одновременно, для меня это два совершенно разных вопроса. ASP.NET MVC не должен ничего знать о EF. EF должен быть похоронен за абстракцией репозитория.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...