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