EF 4.1 :: 使用起订量和测试单位

发布于 2024-11-29 05:28:11 字数 3150 浏览 5 评论 0原文

我在当前项目中使用 Entity Framework 4.1 作为 DAL,现在尝试对我的业务对象进行单元测试,同时使用最小起订量模拟我的实体。

我创建了一个通用工作单元

public interface IFRSDbContext
{
    IDbSet<Category> Categories { get; set; }
    IDbSet<Cell> Cells { get; set; }
    IDbSet<DealSummary> DealSummaries { get; set; }
    IDbSet<DealSummaryDetail> DealSummaryDetails { get; set; }
    IDbSet<Node> Nodes { get; set; }
    IDbSet<Rto> Rtos { get; set; }
    IDbSet<Sheet> Sheets { get; set; }
    IDbSet<Version> Versions { get; set; }
    IDbSet<VersionMapping> VersionMappings { get; set; }

    DbEntityEntry Entry(object entity); 
    DbSet<TEntity> Set<TEntity>() where TEntity : class;
    int SaveChanges();
}

以及通用存储库

public abstract class Repository<TEntity> where TEntity : class
{
    protected IFRSDbContext DbContext;

    protected Repository(IFRSDbContext context) 
    { 
        DbContext = context;
    } 


    public virtual TEntity GetById(object id)
    {
        return DbContext.Set<TEntity>().Find(id);
    }


    public virtual void Insert(TEntity entity)
    {
        DbContext.Set<TEntity>().Add(entity);
    }


    public virtual void Delete(object id)
    { 
        var entityToDelete = DbContext.Set<TEntity>().Find(id); 
        Delete(entityToDelete); 
    } 


    public virtual void Delete(TEntity entityToDelete)
    {
        DbContext.Set<TEntity>().Remove(entityToDelete);
    }


    public abstract void Update(TEntity entityToUpdate);
}

,我还为每个实体创建了一个存储库,这是一个示例:

public class DealSummaryRepository : Repository<DealSummary>
{
    public DealSummaryRepository(IFRSDbContext context) : base(context) { }


    public virtual DealSummary GetByFileName(string fileName)
    {
        return DbContext.Set<DealSummary>().FirstOrDefault(d => d.FileName == fileName);
    }


    public override void Update(DealSummary entityToUpdate)
    {
        var existingDealSummary = GetByFileName(entityToUpdate.FileName);

        if (existingDealSummary == null)
        {
            var message = string.Format(@"Error :: Cannot update Deal Summary '{0}' because it does not exist
                                        in the database.", entityToUpdate.FileName);

            throw new Exception(message);
        }

        existingDealSummary.DateModified = DateTime.Now;
        existingDealSummary.StartDate = entityToUpdate.StartDate;
        existingDealSummary.EndDate = entityToUpdate.EndDate;
        existingDealSummary.DueDate = entityToUpdate.DueDate;
        existingDealSummary.WasWon = entityToUpdate.WasWon;
        existingDealSummary.UploadedBy = entityToUpdate.UploadedBy;

        if (existingDealSummary.Details != null)
            existingDealSummary.Details.Clear();

        existingDealSummary.Details = entityToUpdate.Details;
    }
}

我的问题是,有没有办法将 IDbSet 对象实现为我的通用存储库并继承那...或者我应该将我的存储库包含在我的工作单元中,并在存储库内实现 IDbSet ?在存储库内部实现 IDbSet 时遇到的唯一问题是我的存储库依赖于 EF。

任何建议/最佳实践将不胜感激。我试图采用最简单的方法来使我的实体可模拟,这样我就可以在不依赖实体框架/数据库的情况下进行测试。

I am using Entity Framework 4.1 for my DAL on my current project, and am now trying to unit test my business objects while mocking my entities with moq.

I have created a generic Unit of Work

public interface IFRSDbContext
{
    IDbSet<Category> Categories { get; set; }
    IDbSet<Cell> Cells { get; set; }
    IDbSet<DealSummary> DealSummaries { get; set; }
    IDbSet<DealSummaryDetail> DealSummaryDetails { get; set; }
    IDbSet<Node> Nodes { get; set; }
    IDbSet<Rto> Rtos { get; set; }
    IDbSet<Sheet> Sheets { get; set; }
    IDbSet<Version> Versions { get; set; }
    IDbSet<VersionMapping> VersionMappings { get; set; }

    DbEntityEntry Entry(object entity); 
    DbSet<TEntity> Set<TEntity>() where TEntity : class;
    int SaveChanges();
}

As well as a generic Repository

public abstract class Repository<TEntity> where TEntity : class
{
    protected IFRSDbContext DbContext;

    protected Repository(IFRSDbContext context) 
    { 
        DbContext = context;
    } 


    public virtual TEntity GetById(object id)
    {
        return DbContext.Set<TEntity>().Find(id);
    }


    public virtual void Insert(TEntity entity)
    {
        DbContext.Set<TEntity>().Add(entity);
    }


    public virtual void Delete(object id)
    { 
        var entityToDelete = DbContext.Set<TEntity>().Find(id); 
        Delete(entityToDelete); 
    } 


    public virtual void Delete(TEntity entityToDelete)
    {
        DbContext.Set<TEntity>().Remove(entityToDelete);
    }


    public abstract void Update(TEntity entityToUpdate);
}

I also have a repository for each entity, here is an example:

public class DealSummaryRepository : Repository<DealSummary>
{
    public DealSummaryRepository(IFRSDbContext context) : base(context) { }


    public virtual DealSummary GetByFileName(string fileName)
    {
        return DbContext.Set<DealSummary>().FirstOrDefault(d => d.FileName == fileName);
    }


    public override void Update(DealSummary entityToUpdate)
    {
        var existingDealSummary = GetByFileName(entityToUpdate.FileName);

        if (existingDealSummary == null)
        {
            var message = string.Format(@"Error :: Cannot update Deal Summary '{0}' because it does not exist
                                        in the database.", entityToUpdate.FileName);

            throw new Exception(message);
        }

        existingDealSummary.DateModified = DateTime.Now;
        existingDealSummary.StartDate = entityToUpdate.StartDate;
        existingDealSummary.EndDate = entityToUpdate.EndDate;
        existingDealSummary.DueDate = entityToUpdate.DueDate;
        existingDealSummary.WasWon = entityToUpdate.WasWon;
        existingDealSummary.UploadedBy = entityToUpdate.UploadedBy;

        if (existingDealSummary.Details != null)
            existingDealSummary.Details.Clear();

        existingDealSummary.Details = entityToUpdate.Details;
    }
}

The question that I have is, is there a way to implement the IDbSet object as my generic repository and inherit that... or should I contain my repositories in my unit of work, and implement the IDbSet inside of the repositories? The only problem I have with implementing the IDbSet inside of the repository is then my repository is dependant on EF.

Any sugguestions/best practices would be greatly appreciated. I am trying to take the simplest approach possible to make my entities mockable so I can test without the dependency to entity framework/my database.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

那些过往 2024-12-06 05:28:11

我一直在使用 http://efmvc.codeplex.com 中的 EF Code First + Repositories 模式,该模式有一个与您构建自己的工作单元的方式存在一些差异

我注意到的第一件事是您的工作单元与 EF 相关联。 EFMVC 的工作单元很简单,

public interface IUnitOfWork
{
    void Commit();
}

为了避免将存储库与 EF 绑定在一起,我们

public interface IRepository<T> where T : class
{
    void Add(T entity);
    void Update(T entity);
    void Delete(T entity);
    void Delete(Expression<Func<T, bool>> where);
    T GetById(long Id);
    T GetById(string Id);
    T Get(Expression<Func<T, bool>> where);
    IQueryable<T> GetAll();
    IQueryable<T> GetMany(Expression<Func<T, bool>> where);
}

IRepository 实现需要依赖 EF。因此,现在您不再用其 IDbSet (EntityFramework) 来模拟 IFRSDbContext,而是用其 IQueryable 来模拟 IRepository code>s (System.Core)

编辑:对于你的问题,它可能看起来像这样

public class Uploader : IUploader
{ 
    private readonly IReportRepository _reportRepository; 
    private readonly IUnitOfWork _unitOfWork; 

    public Uploader(IReportRepository reportRepository, IUnitOfWork unitOfWork) 
    { 
        _reportRepository = reportRepository;
        _unitOfWork = unitOfWork;
    }

    public void Upload(Report report)
    {
        _reportRepository.Add(report);
        _unitOfWork.Commit();
    }

}

I've been using the EF Code First + Repositories pattern from http://efmvc.codeplex.com which has a couple differences from the way you've constructed yours

First thing I noticed is your Unit of Work is tied to EF. EFMVC's Unit of Work is simply

public interface IUnitOfWork
{
    void Commit();
}

To avoid tying the repositories to EF, we have

public interface IRepository<T> where T : class
{
    void Add(T entity);
    void Update(T entity);
    void Delete(T entity);
    void Delete(Expression<Func<T, bool>> where);
    T GetById(long Id);
    T GetById(string Id);
    T Get(Expression<Func<T, bool>> where);
    IQueryable<T> GetAll();
    IQueryable<T> GetMany(Expression<Func<T, bool>> where);
}

and our implementation of IRepository<T> is what requires the dependency on EF. So now instead of mocking IFRSDbContext with its IDbSets (EntityFramework), you mock an IRepository<T> with its IQueryables (System.Core)

EDIT: To your question, it might look something like this

public class Uploader : IUploader
{ 
    private readonly IReportRepository _reportRepository; 
    private readonly IUnitOfWork _unitOfWork; 

    public Uploader(IReportRepository reportRepository, IUnitOfWork unitOfWork) 
    { 
        _reportRepository = reportRepository;
        _unitOfWork = unitOfWork;
    }

    public void Upload(Report report)
    {
        _reportRepository.Add(report);
        _unitOfWork.Commit();
    }

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文