开发笔记:用不用UnitOfWork以及Repository返回什么集合类型

这2天实际开发中明确的东西,在这篇博文中记录一下。

之前对是否需要自己封装UnitOfWork有些犹豫,因为Entity Framework就是一个UnitOfWork实现, 自己再封装一下显得有些多余。

但是在这次开发中,把涉及数据库操作的实现代码放在最后写,先完成其他层的代码。这种情况下,根本用不了EF,只能先Fake出一个UnitOfWork,这时必须要进行UnitOfWork的封装。

所以,定义了IUnitOfWork接口并实现了一个FakeUnitOfWork,简化的示例代码如下:

IUnitOfWork

public interface IUnitOfWork : IDisposable
{
    TEntity Add<TEntity>(TEntity entity) where TEntity : class; 
    Task CommitAsync();
}

FakeUnitOfWork

public class FakeUnitOfWork : IUnitOfWoerk
{
    private IList _entities = new List<object>();

    public TEntity Add<TEntity>(TEntity entity) where TEntity : class
    {
        var property = typeof(TEntity).GetProperty("ID");
        if(property != null)
        {
            property.SetValue(entity, new Random().Next());
        }
        _entities.Add(entity);            
        return entity;
    } 

    public async Task CommitAsync()
    {
        var bits = Encoding.UTF8.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(_entities, 
            Newtonsoft.Json.Formatting.Indented));
        using (var fs = new FileStream(
            path: @"C:\temp\FakeUnitOfWork.json", 
            mode: FileMode.Create, 
            access: FileAccess.Write, 
            share: FileShare.None, 
            bufferSize: 4096, 
            useAsync: true))
        {
            await fs.WriteAsync(bits, 0, bits.Length);
        }
    }
}

到写数据库操作代码时,基于EF实现一下IUnitOfWork接口即可。

接下来是Repository返回集合类型的问题。

之前Repository接口多数返回的是IList<T>,这样使用的一个考虑就是让涉及数据库查询的操作尽量在Repository层完成,避免在Application层进行数据库查询操作。

但是今天在Application层的Service中用到了AutoMapper的Project功能,Project的好处是让EF生成的SQL只查询DTO中的字段,但Project扩展方法是针对(且只能针对)IQureryable<T>接口的,所以不得不将Repository接口的返回类型改为IQureryable<T>。

考虑到Project的巨大吸引力以及为了保持Repository返回类型的一致,以后Repository就都统一返回IQureryable<T>吧。

示例代码如下:

IBlogCategoryRepository

public interface IBlogCategoryRepository
{
    Task<IQueryable<BlogCategory>> GetCategoriesByBlogId(int blogId, bool activeOnly);
}

BlogCategoryService

public class BlogCategoryService : IBlogCategoryService
{
    private IBlogCategoryRepository _blogCategoryRepository;

    public BlogCategoryServiceImp(IBlogCategoryRepository blogCategoryRepository)
    {
        _blogCategoryRepository = blogCategoryRepository;
    }

    async Task<IList<BlogCategoryDto>> IBlogCategoryService.GetCategoriesByBlogId(int blogId, bool activeOnly)
    {
        return (await _blogCategoryRepository
            .GetCategoriesByBlogId(blogId, activeOnly))
            .Project()
            .To<BlogCategoryDto>()
            .ToList();
    }
}
posted @ 2015-05-19 20:46 dudu 阅读(...) 评论(...) 编辑 收藏