什么是IRepository?为什么要使用它?简单的例子不会有坏处。
什么是IRepository?为什么要使用它?简单的例子不会有坏处。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Wingspan.Web.Mvc
{
public interface IRepository<TEntity> where TEntity : class
{
List<TEntity> FetchAll();
IQueryable<TEntity> Query {get;}
void Add(TEntity entity);
void Delete(TEntity entity);
void Save();
}
}
这个接口的一个具体实现如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;
using Wingspan.Web.Mvc;
namespace ES.eLearning.Domain
{
public class SqlRepository<T> : IRepository<T> where T : class
{
DataContext db;
public SqlRepository(DataContext db)
{
this.db = db;
}
#region IRepository<T> Members
public IQueryable<T> Query
{
get { return db.GetTable<T>(); }
}
public List<T> FetchAll()
{
return Query.ToList();
}
public void Add(T entity)
{
db.GetTable<T>().InsertOnSubmit(entity);
}
public void Delete(T entity)
{
db.GetTable<T>().DeleteOnSubmit(entity);
}
public void Save()
{
db.SubmitChanges();
}
#endregion
}
}
SqlRepository<UserCourse> UserCoursesRepository = new SqlRepository<UserCourse>(db);
在这里,db是一个注入到服务中的DataContext实例。
有了UserCoursesRepository,我现在可以在我的Service类中编写如下方法:
public void DeleteUserCourse(int courseId)
{
var uc = (UserCoursesRepository.Query.Where(x => x.IdUser == UserId && x.IdCourse == courseId)).Single();
UserCoursesRepository.Delete(uc);
UserCoursesRepository.Save();
}
现在,在我的控制器中,我只需要编写:
MyService.DeleteUserCourse(5);
MyService.Save();
IRepository
是在您想要实现存储库模式时指定的接口。正如Brian Ball所述,它不是.NET的一部分,而是您创建的接口。
广泛使用存储库模式的开发人员推荐使用接口进行实现。例如,在我正在开发的应用程序中,我有5个存储库。其中4个是特定的,1个是通用的。每个存储库都继承自IRepository
,这确保了我将来不会因为实现的差异而出现问题。
至于代码示例,我尝试一下:
interface IRepository<T> where T : class {
IQueryable<T> Select();
}
实现为通用仓库:
public class Repository<T> : IRepository<T> where T : class {
public IQueryable<T> Select() {
return this.ObjectContext.CreateObjectSet<T>();
}
}
作为专门的存储库实现:
public class EmployeeRepository : IRepository<Employee> {
public IQueryable<Employee> Select() {
return this.ObjectContext.Employees;
}
}
Repository<T>
和EmployeeRepository
都实现了IRepository
接口,但它们执行查询的方式略有不同。泛型仓储库必须在尝试执行任何操作之前创建一个T对象集。
请记住,Repository<T>
应该锁定到接口,而EmployeeRepository
可以实现更专业的方法来完成更复杂的逻辑。
希望这能对您有所帮助。
public class EmployeeRepository : Repository<Employee>
。这样你就不必重新编写通用方法,比如 IQueryable<Employee> Select()
,因为它已经在基础存储库中定义了。 - RPM1984IRepository
不是.Net框架中定义的类型。通常,当你看到这样命名的接口时,程序会使用仓储模式(https://web.archive.org/web/20110503184234/http://blogs.hibernatingrhinos.com/nhibernate/archive/2008/10/08/the-repository-pattern.aspx)。一般来说,当人们使用这种模式时,他们会创建一个所有存储库都要遵守的接口。这样做有许多好处。其中一些好处是代码解耦和单元测试。
这也是常见的操作,以便利用IoC(http://en.wikipedia.org/wiki/Inversion_of_control)。
仓库是一个抽象,它将任何底层和任意的数据存储表示为内存中的对象集合。
由于常见实践和系统限制,这个定义变成了更实用的形式,即“内存中的对象集合,表示一些底层和任意的数据存储,可能是一个断开的存储”。在幕后,仓库可能链接到数据库、平面文件、内存中的对象集合或其他任何你能想象到的东西。仓库的使用者不关心。
因此,IRepository
是接口契约,它定义了Api代码希望客户端代码与仓库交互的方式。这通常包括添加、更新、删除和获取契约,例如,这是一个非常常见的仓库契约示例:
public interface IRepository<TEntity> where TEntity : class
{
List<TEntity> GetAll();
void Add(TEntity entity);
void Delete(TEntity entity);
void Save();
}
public interface IRepository<TEntity> where TEntity : class
{
List<TEntity> GetAll();
List<TEntity> Get(Func<TEntity, bool> where);
void Insert(TEntity entity);
void Insert(IEnumerable<TEntity> entities);
void Remove(TEntity entity);
void Remove(IEnumerable<TEntity> entities);
void SyncDisconnected(TEntity entity, bool forDeletion = false);
void SyncDisconnected(IEnumerable<TEntity> entities, bool forDeletion = false);
}
DomainObject
,并给它一个Id
字段,那么你就可以这样做:public interface IRepository<TEntity> where TEntity : DomainObject
{
TEntity GetById(object Id);
List<TEntity> GetAll();
List<TEntity> Get(Func<TEntity, bool> where);
void Insert(TEntity entity);
void Insert(IEnumerable<TEntity> entities);
void Remove(TEntity entity);
void Remove(IEnumerable<TEntity> entities);
void SyncDisconnected(TEntity entity, bool forDeletion = false);
void SyncDisconnected(IEnumerable<TEntity> entities, bool forDeletion = false);
}
如果您不喜欢可选参数forDeletion
,您可以添加一个方法来同步已删除的对象:
void SyncDisconnectedForDeletion(TEntity entity);
你需要这样做的原因是,大多数情况下,将断开连接的对象同步删除与将断开连接的对象同步添加或修改不兼容(请尝试一下。您会发现删除对存储的要求与添加或修改迥然不同)。因此,接口应该定义一个合同,以便实现可以区分两者。
您可以针对任何基础数据存储库(包括其他抽象到基础数据存储的抽象)实现此接口,无论其是否连接或断开连接。