天天看點

開發筆記:用不用UnitOfWork以及Repository傳回什麼集合類型

這2天實際開發中明确的東西,在這篇博文中記錄一下。之前對是否需要自己封裝UnitOfWork有些猶豫,因為Entity Framework就是一個UnitOfWork實作, 自己再封裝一下顯得有些多餘。但是在這次開發中,把涉及資料庫操作的實作代碼放在最後寫,先完成其他層的代碼。這種情況下,根本用不了EF,隻能先Fake出一個UnitOfWork,這時必須要進行UnitOfWork的封裝。

這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();
    }
}      

繼續閱讀