2012-08-13 45 views
6

我想创建一个存储库类来从我的控制器中分离出我的数据逻辑。我使用ViewModel来表示一些数据,这些数据将用来自不同表格的数据填充。使用ViewModels设计MVC存储库

这里有一些问题,我有:

  1. 对于像GetAll()的方法,我返回IQueryable<MyViewModel>IQueryable<Entity>?如果我返回viewmodels,我该如何处理能够拉动数千条记录的GetAll()
  2. 是否为我的自定义ViewModel类创建了一个构造函数,该实例将实体作为参数进行映射? (我还没有熟悉automapper所以只需要关于如何从设计的角度来看这样做的理解)

再次,我主要关心的是像GetAll()的方法,它会拉动多条记录。如果我做了一个foreach循环来将每个实体翻译成ViewModel看起来像是一个很大的开销。我的想法是将自定义ViewModel类中的引用放入IQueryable<Entity>以从集合中进行访问,并让ListViewModel具有索引器或类似引用集合属性的索引器。

回答

5

1)对于像GetAll()这样的方法,是否返回IQueryable或IQueryable?如果我返回viewmodels,我该如何处理一个GetAll(),它可以提取数千条记录?

IQueryable<Entity>。存储库不处理视图模型。将存储库看作是在单独的类库中定义的,它不引用您的视图模型所在的ASP.NET MVC应用程序。它是引用这个库的ASP.NET MVC应用程序。

2)是否为我的自定义ViewModel类创建了一个构造函数,该实例将实体作为参数进行映射? (我还没有熟悉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看起来像是一个很大的开销。

不要担心这一点。拉动你的记录将比循环和映射到视图模型的速度慢。

1

有很多不同的方法可以做到这一点,但简单地说,我会为您的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); 
} 

*这是相当多的打字,抱歉拼写错误:)

1

我认为你可能有视图模型的误解,它的目的。您不需要为数据库中的每个实体创建视图模型,因为它似乎是您想要的;您只需为要渲染的每个视图创建一个视图模型。因此,术语“视图模型” - 它以一种模型的形式组织数据,您的视图可以被强制类型化。

例如,您不想为由GetAll()返回的每个实体创建单独的视图模型。在显示的所有记录的GridView控件的一个简单的场景你可能只需要一个单一的视图模型与一个属性:

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

你会在控制器

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

填充这个视图模型看一看Rachael Appel的this blog post进行了非常简洁的讨论。