我正在玩最新的实体框架CTP 5版本,并构建了一个简单的asp.net MVC博客,我只有两个表格:Post和Comments。这完全是在POCO中完成的,我只需要DbContext部分的帮助,我需要它是单元可测试的(使用IDbSet?),我需要一个简单/通用的存储库模式来添加,更新,删除和检索。任何帮助表示赞赏。实体框架4 CTP 4/CTP 5通用存储库模式和单元可测试
谢谢。
我正在玩最新的实体框架CTP 5版本,并构建了一个简单的asp.net MVC博客,我只有两个表格:Post和Comments。这完全是在POCO中完成的,我只需要DbContext部分的帮助,我需要它是单元可测试的(使用IDbSet?),我需要一个简单/通用的存储库模式来添加,更新,删除和检索。任何帮助表示赞赏。实体框架4 CTP 4/CTP 5通用存储库模式和单元可测试
谢谢。
开始与你的DbContext,创建一个名为Database.cs新文件:
Database.cs
public class Database : DbContext
{
private IDbSet<Post> _posts;
public IDbSet<Post> Posts {
get { return _posts ?? (_posts = DbSet<Post>()); }
}
public virtual IDbSet<T> DbSet<T>() where T : class {
return Set<T>();
}
public virtual void Commit() {
base.SaveChanges();
}
}
定义IDatabaseFactory与DatabaseFactory实现它:
IDatabaseFactory。 cs
public interface IDatabaseFactory : IDisposable
{
Database Get();
}
个
DatabaseFactory.cs
public class DatabaseFactory : Disposable, IDatabaseFactory {
private Database _database;
public Database Get() {
return _database ?? (_database = new Database());
}
protected override void DisposeCore() {
if (_database != null)
_database.Dispose();
}
}
一次性扩展方法:
Disposable.cs
public class Disposable : IDisposable
{
private bool isDisposed;
~Disposable()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if(!isDisposed && disposing)
{
DisposeCore();
}
isDisposed = true;
}
protected virtual void DisposeCore()
{
}
}
现在,我们可以定义我们的IRepository和我们RepositoryBase
个IRepository.cs
public interface IRepository<T> where T : class
{
void Add(T entity);
void Delete(T entity);
void Update(T entity);
T GetById(long Id);
IEnumerable<T> All();
IEnumerable<T> AllReadOnly();
}
RepositoryBase.cs
public abstract class RepositoryBase<T> where T : class
{
private Database _database;
private readonly IDbSet<T> _dbset;
protected RepositoryBase(IDatabaseFactory databaseFactory)
{
DatabaseFactory = databaseFactory;
_dbset = Database.Set<T>();
}
protected IDatabaseFactory DatabaseFactory
{
get; private set;
}
protected Database Database
{
get { return _database ?? (_database = DatabaseFactory.Get()); }
}
public virtual void Add(T entity)
{
_dbset.Add(entity);
}
public virtual void Delete(T entity)
{
_dbset.Remove(entity);
}
public virtual void Update(T entity)
{
_database.Entry(entity).State = EntityState.Modified;
}
public virtual T GetById(long id)
{
return _dbset.Find(id);
}
public virtual IEnumerable<T> All()
{
return _dbset.ToList();
}
public virtual IEnumerable<T> AllReadOnly()
{
return _dbset.AsNoTracking().ToList();
}
}
现在你可以创建你的IPostRepository和PostRepository:
IPostRepository.cs
public interface IPostRepository : IRepository<Post>
{
//Add custom methods here if needed
Post ByTitle(string title);
}
个
PostRepository.cs
public class PostRepository : RepositoryBase<Post>, IPostRepository
{
public PostRepository(IDatabaseFactory databaseFactory) : base(databaseFactory)
{
}
public Post ByTitle(string title) {
return base.Database.Posts.Single(x => x.Title == title);
}
}
最后,UOW:
IUnitOfWork.cs
public interface IUnitOfWork
{
void Commit();
}
的UnitOfWork。CS
private readonly IDatabaseFactory _databaseFactory;
private Database _database;
public UnitOfWork(IDatabaseFactory databaseFactory)
{
_databaseFactory = databaseFactory;
}
protected Database Database
{
get { return _database ?? (_database = _databaseFactory.Get()); }
}
public void Commit()
{
Database.Commit();
}
使用在你的控制器:
private readonly IPostRepository _postRepository;
private readonly IUnitOfWork_unitOfWork;
public PostController(IPostRepository postRepository, IUnitOfWork unitOfWork)
{
_postRepository = postRepository;
_unitOfWork = unitOfWork;
}
public ActionResult Add(Post post) {
_postRepository.Add(post);
_unitOfWork.Commit();
}
您将需要使用IoC容器像StructureMap,使这项工作。您可以通过NuGet安装结构图,或者如果您使用的是MVC 3,则可以安装StructureMap-MVC NuGet包。 (链接下面)
Install-Package StructureMap.MVC4
Install-Package StructureMap.MVC3
如果你有问题,只是让我知道。希望能帮助到你。
我唯一不同的做法是在实现中,即暴露服务层中的IPostRepository,并在控制器中有一个类型为IPostService的接口字段,就像另一个抽象层一样,否则这是一个很好的例子 - 好的,保罗。
我在我的项目中也做了同样的事情。这是一个很好的抽象,并保持控制器的动作干净和简单。 – Paul 2011-01-12 01:37:25
嗨保罗,这已经有一段时间了,你在这里展示的功能非常好。但是我没有做过任何单元测试:)就在今天我正在考虑做单元测试,并且使用MOQ框架来模拟数据,我该如何做呢?我是否必须重新创建仓库作为模拟仓库,或者我可以重新使用我已有的仓库?非常感谢你。 – Saxman 2011-01-18 17:16:30
@Saxman - 我会问一个新的questoins。如何单元测试我的仓库
我很喜欢这种深入的文章关于实体框架4 POCO,库和规范模式
http://huyrua.wordpress.com/2010/07/13/entity-framework-4-poco-repository-and-specification-pattern/
+ 1为伟大的链接 – 2011-03-22 23:20:01
+1为链接,正是最近一直寻找最近 – Baldy 2011-05-04 11:04:42
它是一个良好的开端? http://romiller.com/2010/09/07/ef-ctp4-tips-tricks-testing-with-fake-dbcontext/ – Devart 2010-12-15 13:22:04
我喜欢那个Devart,但它有点远离通用存储库模式,我会喜欢查看采用单一类型的存储库。也许基于DBSet而不是? –
mxmissile
2010-12-15 15:23:27