7

我想创建一个存储库类来将我的数据逻辑与我的控制器分开。我正在使用 ViewModel 来表示一些数据,这些数据将填充来自不同表的数据。

以下是我的一些问题:

  1. 对于像这样的方法GetAll(),我应该返回IQueryable<MyViewModel>orIQueryable<Entity>吗?如果我返回视图模型,我该如何处理GetAll()拉动数千条记录的问题?
  2. 我是否为我的自定义 ViewModel 类创建了一个构造函数,该构造函数将实体作为参数来进行映射?(我仍然不熟悉 automapper,所以只需要从设计的角度了解如何做到这一点)

同样,我主要关心的是一种GetAll()可以提取许多记录的方法。如果我做了一个 foreach 循环将每个实体转换为 ViewModel 似乎会产生很多开销。我的想法是在自定义 ViewModel 类中放置一个引用IQueryable<Entity>以从集合中访问,并让 ListViewModel 只有索引器或类似引用集合属性的东西。

4

3 回答 3

5

1) 对于像 GetAll() 这样的方法,我是返回 IQueryable 还是 IQueryable?如果我返回视图模型,我该如何处理获取数千条记录的 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 似乎会产生很多开销。

不要担心那个。提取记录将比循环和映射到视图模型慢一个数量级。

于 2012-08-14T05:42:23.350 回答
1

有许多不同的方法可以做到这一点,但首先,我会IEnumerable<T>为您的 GetAll() 方法返回一个。但是,您可能希望以某种方式实现分页。您可能想要设置一个通用存储库,该存储库对大多数情况进行基本数据访问并返回一个 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);
}

*写的有点多,抱歉有错别字:)

于 2012-08-13T23:33:59.463 回答
1

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

例如,您不会希望为 GetAll() 返回的每个实体创建单独的视图模型。在显示所有记录的网格视图的简单场景中,您可能只需要一个具有一个属性的视图模型:

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

您将在控制器中填充此视图模型

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

请查看Rachael Appel 的这篇博客文章,以获得非常简洁的讨论。

于 2012-08-14T00:40:36.917 回答