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