簡體   English   中英

使用ViewModels設計MVC存儲庫

[英]Designing an MVC repository using ViewModels

我想創建一個存儲庫類來將我的數據邏輯與控制器分開。 我使用ViewModel來表示將填充來自不同表的數據的一些數據。

以下是我的一些問題:

  1. 對於像GetAll()這樣的方法,我是否返回IQueryable<MyViewModel>IQueryable<Entity> 如果我返回viewmodels,我該如何處理一個可以提取數千條記錄的GetAll()
  2. 我是否為自定義ViewModel類創建構造函數,該類將實體作為參數來進行映射? (我仍然不熟悉automapper,所以只需要從設計的角度理解如何做到這一點)

同樣,我主要擔心的是像GetAll()這樣的方法會拉出很多記錄。 如果我做了一個foreach循環來將每個實體轉換為一個ViewModel似乎需要很多開銷。 我的想法是將自定義ViewModel類中的引用放入IQueryable<Entity>以從集合中訪問,並使ListViewModel只具有索引器或類似引用集合屬性的索引器。

1)對於像GetAll()這樣的方法,我是否返回IQueryable或IQueryable? 如果我返回viewmodels,我該如何處理一個可以提取數千條記錄的GetAll()?

IQueryable<Entity> 存儲庫不處理視圖模型。 可以將存儲庫視為在單獨的類庫中定義的內容,該庫不引用您的視圖模型所在的ASP.NET MVC應用程序。 ASP.NET MVC應用程序引用此庫。

2)我是否為自定義ViewModel類創建一個構造函數,該類將Entity作為參數來進行映射? (我仍然不熟悉automapper,所以只需要從設計的角度理解如何做到這一點)

不。不要在視圖模型中創建構造函數,尤其是當您希望控制器操作將這些視圖模型作為操作參數時(考慮POST操作)。 原因是默認模型綁定器將不再知道如何實例化視圖模型,您必須編寫自定義模型綁定器。

所以AutoMapper或手動映射。

您可以從手冊映射開始的示例:

public ActionResult SomeAction()
{
    IEnumerable<Entity> entities = Repository.GetAll();
    IEnumerable<MyViewModel> model = entities.Select(x => new MyViewModel
    {
        Prop1 = x.Prop1,
        Prop2 = x.Prop2,
        ...
    }); 
    return View(model);
}

一旦你厭倦了編寫這個代碼移動到AutoMapper:

public ActionResult SomeAction()
{
    IEnumerable<Entity> entities = Repository.GetAll();
    IEnumerable<MyViewModel> model = Mapper.Map<IEnumerable<Entity>, IEnumerable<MyViewModel>>(entities); 
    return View(model);
}

或者,如果您編寫自定義操作過濾器,使用OnActionExecuted事件來拉取傳遞給視圖的域模型,使用AutoMapper將其映射到視圖模型,並將模型替換為視圖的視圖模型,則可以進一步簡化重復代碼:

[AutoMap(typeof(IEnumerable<Entity>), typeof(IEnumerable<MyViewModel>))]
public ActionResult SomeAction()
{
    IEnumerable<Entity> entities = Repository.GetAll();
    return View(entities);
}

同樣,我主要擔心的是像GetAll()這樣的方法會拉出很多記錄。 如果我做了一個foreach循環來將每個實體轉換為一個ViewModel似乎需要很多開銷。

不要擔心。 拉取記錄將比循環和映射到視圖模型慢一些。

有很多不同的方法可以做到這一點,但簡單來說,我會為你的GetAll()方法返回一個IEnumerable<T> 但是,您可能希望以某種方式實現分頁。 您可能希望設置一個通用存儲庫,為大多數方案執行基本數據訪問並返回Enumerable。 您可以保留一個應該為更復雜的查詢保留的方法,並返回IQueryable<T> 基本的精簡實現可能如下所示。

public class Repository<T> : IRepository<T> where T : class
{
    internal ObjectContext _objectContext;
    internal ObjectSet<T> _objectSet;

    public Repository(ObjectContext objectContext)
    {
        _objectContext = objectContext;
        _objectSet = objectContext.CreateObjectSet<T>();
    }

    public IQueryable<T> GetQuery()
    {
        return _objectSet;
    }

    public IEnumerable<T> GetAll()
    {
        return GetQuery().ToList();
    } 

    public IEnumerable<T> Find(Func<T, bool> where)
    {
        return _objectSet.Where<T>(where);
    }

    public T Single(Func<T, bool> where)
    {
        return _objectSet.SingleOrDefault<T>(where);
    }

    public List<T> Page<TKey>(Expression<Func<T, bool>> where, int page, int pagesize, Expression<Func<T, TKey>> orderBySelector, bool ascending)
    {
        return ascending
            ? GetQuery().Where(where).OrderBy(orderBySelector).Skip((page - 1) * pagesize).Take(pagesize).ToList()
            : GetQuery().Where(where).OrderByDescending(orderBySelector).Skip((page - 1) * pagesize).Take(pagesize).ToList();
    }


    public void Delete(T entity)
    {
        _objectSet.DeleteObject(entity);
    }

    public void Add(T entity)
    {
        _objectSet.AddObject(entity);
    }

}

界面看起來像

public interface IRepository<T> where T : class
{
    IQueryable<T> GetQuery();

    IEnumerable<T> GetAll();

    IEnumerable<T> Find(Func<T, bool> where);     

    T Single(Func<T, bool> where);

    List<T> Page<TKey>(Expression<Func<T, bool>> where, int page, int pagesize, Expression<Func<T, TKey>> orderBySelector, bool ascending);

    void Delete(T entity);

    void Add(T entity);

}

以上內容可以作為簡單通用存儲庫的開頭。 擁有實體后,您不需要AutoMapper,它只會讓生活更輕松,因為許多ViewModel具有與您的實體相同的屬性。 您可以簡單地定義新的ViewModel或ViewModel列表,並自己映射屬性。

List<ViewModel> vm = new List<ViewModel>();

foreach (var e in entities)
{
    ViewModel v = new ViewModel();
    v.something = e.something;
    // perform the rest
    vm.Add(v);
}

*這是相當多的打字,抱歉任何錯別字:)

我認為你可能對視圖模型及其目的有誤解。 您不需要為數據庫中的每個實體創建視圖模型,因為您似乎想要這樣做; 您只需為要渲染的每個視圖創建一個視圖模型。 因此,術語“視圖模型” - 它以模型的形式組織數據,您的視圖可以強類型化。

例如,您不希望為GetAll()返回的每個實體創建單獨的視圖模型。 在顯示所有記錄的gridview的簡單場景中,您可能只需要一個具有一個屬性的viewmodel:

    public class MyViewModel
    {     
       public List<MyRecord> AllRecords {get;set;}
    }

您將在控制器中填充此視圖模型

public ActionResult SomeAction()
{
   var viewmodel = new MyViewModel{AllRecords = GetAll()};
   return View(viewModel);
}

看看Rachael Appel的這篇博客文章 ,進行一次非常簡潔的討論。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM