我想创建一个存储库类从我的控制器分离出我的数据的逻辑。 我使用的是视图模型来表示一些数据,将充满了来自不同表的数据。
这里有一些问题,我有:
- 对于像的方法
GetAll()
我返回IQueryable<MyViewModel>
或IQueryable<Entity>
? 如果我回来的ViewModels,我怎么有应付GetAll()
拉几千条记录? - 难道我创建我的自定义ViewModel类构造函数,是以实体为参数进行映射? (我还没有熟悉automapper所以只需要关于如何从设计的角度来看这样做的理解)
再次,我主要关心的是像一个方法GetAll()
这会拉动多条记录。 如果我做了一个foreach循环每个实体转变成一个ViewModel似乎是一个很大的开销。 我的想法是把自定义的视图模型类里面引用IQueryable<Entity>
从集合访问,并有ListViewModel只是索引或类似的引用该集合属性的东西。
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似乎是一个很大的开销。
不要担心这一点。 拉你的记录将是一个数量级比循环和映射到视图模型慢。
有许多不同的方法可以做到这一点,但简单地开始,我将返回IEnumerable<T>
为您GETALL()方法。 然而,你可能想实现以某种方式分页。 你可能想建立一个通用的存储库确实为大多数情况下你的基本的数据访问,并返回一个枚举。 你可以保留应保留用于更复杂的查询,并返回一个单一方法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,它只是让尽可能多的ViewModels具有相同的属性,你的实体的生活更轻松。 你可以简单地定义的ViewModels的一个新的视图模型或列表和地图上自己的属性。
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控件的一个简单的场景你可能只需要一个属性的单一视图模型:
public class MyViewModel
{
public List<MyRecord> AllRecords {get;set;}
}
你会填充在控制器此视图模型
public ActionResult SomeAction()
{
var viewmodel = new MyViewModel{AllRecords = GetAll()};
return View(viewModel);
}
看看这个博客帖子由瑞秋阿佩尔一个真正简洁的讨论。