2015-07-20 17 views
10

ViewModel'i her oluşturduğumda veritabanından getirmem gereken ülkeler, ürünler, kategoriler vb. Gibi birçok veriye sahip karmaşık görünüm modelim olduğunu varsayalım.Deposu görünüm modelinde kullanmak tamam mı?

düzeltmek istiyorum asıl sorun ben POST işlemleri işlemek ve bazı TestModelfalse olmak ModelState.IsValid neden yanlış değerlerle ne zaman gönderildiğini, daha sonra şu anda Yayınlanan model ile aynı görünüm dönmek zorunda olmasıdır. Bu, GET eyleminde bunu yaptığım için tekrar kategoriler listemi almaya zorluyor. Bu, denetleyicide çok sayıda çoğaltılan kod ekler ve onu kaldırmak istiyorum.

Benim modelim ve görünümü modelleri: Şu anda aşağıdaki yapıyorum

Modeli, varlık veritabanında saklanan:

public class Category 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 

    public IEnumerable<Category> SubCategories { get; set; } 
} 

Görünüm modelleri:

public class CategoryModel 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

public class TestModel 
{ 
    [Required] 
    [MaxLength(5)] 
    public string Text { get; set; } 

    public int SelectedCategory { get; set; } 
    public IEnumerable<CategoryModel> Categories { get; set; } 
    public SelectList CategoriesList 
    { 
     get 
     { 
      var items = Categories == null || !Categories.Any() 
       ? Enumerable.Empty<SelectListItem>() 
       : Categories.Select(c => new SelectListItem 
       { 
        Value = c.Id.ToString(), 
        Text = c.Name 
       }); 

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

Benim denetleyicisi: Ben, temelde bu kodu alma ve haritalama yinelenen Kategoriler kaldırmak istediğiniz

public class HomeController : Controller 
{ 
    private readonly Repository _repository = ObjectFactory.GetRepositoryInstance(); 

    public ActionResult Index() 
    { 
     var model = new TestModel 
     { 
      Categories = _repository.Categories.Select(c => new CategoryModel 
      { 
       Id = c.Id, 
       Name = c.Name 
      }) 
     }; 
     return View(model); 
    } 

    [HttpPost] 
    public ActionResult Index(TestModel model) 
    { 
     if (ModelState.IsValid) 
     { 
      return RedirectToAction("Succes"); 
     } 

     model.Categories = _repository.Categories.Select(c => new CategoryModel 
     { 
      Id = c.Id, 
      Name = c.Name 
     }); 
     return View(model); 
    } 

    public ActionResult Succes() 
    { 
     return View(); 
    } 
} 

: denetleyicisinden

.Categories = _repository.Categories.Select(c => new CategoryModel 
      { 
       Id = c.Id, 
       Name = c.Name 
      }) 

. Ayrıca ben ModelState geçerlilik denetimi kaldırmak istiyorum, ben sadece ModelState.IsValid denetleyici kodu AS TEMIZ OLARAK OLMAYAN OLARAK tutmak için eylemi yürütmek istiyorum.

eylem yürütmeden önce Şimdi modeli doğrulandığında

public class ValidateModelAttribute : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     var viewData = filterContext.Controller.ViewData; 

     if(viewData.ModelState.IsValid) return; 

     viewData.Model = filterContext.ActionParameters["model"]; 
     filterContext.Result = new ViewResult 
     { 
      ViewData = viewData, 
     }; 
    } 
} 

özel ValidateModelAttribute oluşturun: Şimdiye kadar ModelState geçerlilik kontrolünü kaldırmak için aşağıdaki çözümü var. Doğrulama hataları durumunda, aynı görüntüyü aynı son yayınlanan modelle kullanırız. Dolayısıyla, denetleyici POST eylem şuna benzer:

[HttpPost] 
[ValidateModelAttribute] 
public ActionResult Index(TestModel model) 
{ 
    // Do some important stuff with posted data 
    return RedirectToAction("Success"); 
} 

Bu güzel, ama ben veritabanından kategorileri getirir ve onları uygun şekilde eşleştirmek zorunda çünkü artık benim TestModel benim Categories özelliği, boş. Yani şuna benzer benim bakış modelini değiştirmek için OK:

public class TestModel 
{ 
    private readonly Repository _repository = ObjectFactory.GetRepositoryInstance(); 

    ... 

    public int SelectedCategory { get; set; } 
    public IEnumerable<CategoryModel> Categories { 
     get 
     { 
      return _repository.Categories.Select(c => new CategoryModel 
      { 
       Id = c.Id, 
       Name = c.Name 
      }); 
     } 
    } 

    ... 
} 

Bu bize çok temiz denetleyiciniz sağlayacak, ancak performansı veya mimari konularda çeşit neden olmaz? Bakış modelleri için tek sorumluluk ilkesini kırmaz mıydı? ViewModels, ihtiyaç duyduğu verileri almaktan sorumlu olmalı mı?

+2

İdeal hayır, senin bakış modelleri depo ile doğrudan etkileşim olmaz, böyle yapardım. Modelinizi depodan doldurmanız gerekiyorsa, bu kontrol cihazınızda gerçekleşir. Kategoriler popülasyonunu ayrı denetleyici yollarında çoğaltmak istemiyorsanız, bu mantığı yeniden ayrı bir yönteme yerleştirmeyi deneyebilirsiniz. – timothyclifford

cevap

3

Sorun değil. Görünüm modelinin esas olarak bir servis/sorgu veya kontrolör tarafından doldurulan bir DTO olması gerekir. Önceki sürümde sorun yok, kontrol cihazınız sadece birkaç satır koddur.

Ancak, deponuz gerçekten bir depo değil, bir ORM'dir.Uygun bir depo (iyi burada sadece bir sorgu nesnesi olurdu) doğrudan görünüm modeli için Kategoriler listesine dönecekti.

Otomatik doğrulama özelliğiniz hakkında, tekerleği yeniden icat etmeyin, başka biri (bu durumda bana) before yaptı.

3

Hayır, görünüm modellerine depo referansı ve mantığı koymamalısınız. İhtiyacınız olan tek şey, doğrulamanın başarısız olması durumunda modeli yeniden inşa edebilmek olduğunu düşünüyorum. Örneğin, otomatik ModelState doğrulama birini deneyebilirsiniz: Ben senin yaklaşımla görebileceğiniz birkaç akımları vardır http://benfoster.io/blog/automatic-modelstate-validation-in-aspnet-mvc

0

,

  1. depo kullanma ve gerçek sorgulama yapmak kontrolör,

    var model = new TestModel 
    { 
        Categories = _repository.Categories.Select(c => new CategoryModel 
        { 
         Id = c.Id, 
         Name = c.Name 
        }) 
    }; 
    

Daha iyi bir yaklaşım ya mo etmektir ve bunu depoya ya da daha iyi bir şekilde servisler gibi daha mantıklı bir seviyeye koy.

Yeni çözümünüzde, görünüm modelindeki depoyu işaret ettiğinizden daha da kötüdür. İdeal

public class TestService : ITestService{ 
    private IReposotory repo; 

    public TestService(IReposotory repo){ 
    this.repo = repo; 
    } 

    public TestModel GetModel() 
    { 
     return new TestModel() 
{ 
    Categories = _repository.Categories.Select(c => new CategoryModel 
    { 
     Id = c.Id, 
     Name = c.Name 
    }) 
};  
    } 
} 

public class HomeController : Controller 
{ 
    private readonly ITestService _service; 

    public HomeController (ITestService service){ 
     _service = service; 
    } 

    public ActionResult Index() 
    {   
     return View(_service.GetModel()); 
    } 

    [HttpPost] 
    public ActionResult Index(TestModel model) 
    { 
     if (ModelState.IsValid) 
     { 
      return RedirectToAction("Succes"); 
     } 
     return View(model); 
    } 

    public ActionResult Succes() 
    { 
     return View(); 
    } 
} 
İlgili konular