我是ASP.NET MVC新手(但是.NET经验丰富的开发者),我正在努力学习如何正确设置Web应用程序基础结构。 存储库模式是我现在正在考虑的,在过去几天阅读了几十篇博客/文章/答案后,我仍然不确定如何以正确的方式使用它。我正在学习Pro ASP.NET MVC 4 Adam Freeman,这里是基于本书的存储库接口代码:
public interface IRepository<T>
{
IQueryable<T> FindAll();
IQueryable<T> Find(Expression<Func<T, bool>> predicate);
void Add(T newEntity);
void Remove(T entity);
T FindById(long id);
}
经过更多的在线研究后,我意识到许多人认为从存储库中返回IQueryable是不好的做法,我可以(大部分)理解为什么。但是,我似乎无法找到具体替代方案的答案?我知道有一个自定义存储库的想法,对于每个实体,每个可能的查询都有专门的方法,基本上会返回IEnumerable而不是IQueryable ......但这对我来说似乎不对(它也不是优雅的解决方案)许多代码编写和可能的代码冗余等...)。
还有什么其他选择?
答案 0 :(得分:7)
你有两种选择。
第一个是使用specification pattern。您创建了一组用于限制搜索结果的类。
维基百科的文章有点差,因为它没有显示如何编写业务规范(即“真实”规范)。但是你基本上在业务规范中使用较低级别的规范(和/或等)。
通过这样做,您可以拥有更简单的存储库类,而不是编写这些规范。
为每个根聚合(订单,用户等)创建存储库。每个存储库都具有适用于特定业务需求的唯一查询方法。
用户存储库可以有例如
IPagedResult<User> FindDisabledUser(int pageNumber, int pageSize);
订单存储库可以有
IPagedResult<User> GetOrdersReadyForShipping(DateTime orderAfterThisDate);
我写了一组数据层文章:http://blog.gauffin.org/tag/data-access/。其中一个也解释了为什么在您的存储库中公开IQueryable<T>
不是一个好主意。
答案 1 :(得分:4)
根据我在原始问题下面的评论,这就是我如何实现需要更复杂查询要求的存储库。我还为实体框架包含了我的DbContext对象。
我喜欢这种模式,因为它隐藏了存储库后面的实体框架实现,确保实体框架不与您的应用程序紧密耦合。
public class PersonRepository: IPersonRepository
{
public List<Person> ReadAll()
{
using (var context = new EfContext())
return context.Persons.ToList();
}
public List<Person> ReadPage(int pageIndex, int itemCount)
{
using (var context = new EfContext())
return context.Persons
.Skip(pageIndex * itemCount)
.Take(itemCount)
.ToList();
}
public List<Person> ReadAllWhoseNamesStartWith(string nameExpression)
{
using (var context = new EfContext())
return context.Persons
.Where(r => r.Name.StartsWith(nameExpression)
.ToList();
}
public List<Person> ReadAllWhoseFavouriteColorIs(string color)
{
using (var context = new EfContext())
return context.Persons
.Where(r => r.FavoriteColor.StartsWith(color)
.ToList();
}
}
public class EfContext: DbContext
{
public EfContext(): base("DefaultConnection")
{
}
public DbSet<Person> Persons { get; set; }
public DbSet<Car> Cars { get; set; }
public DbSet<Car> Houses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<EfContext>(null);
base.OnModelCreating(modelBuilder);
}
}