我正在玩最新的實體框架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