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