藉助 WeihanLi.EntityFramework 實現簡單的 Repository
Intro
很多時候一些簡單的業務都是簡單的增刪改查,動態生成一些程式碼完成基本的增刪改查,而這些增刪改查程式碼大多類似,只有一些有複雜業務邏輯的可能需要手動去寫。於是實現了一個基於 EF Core 的 Repository。
GetStarted
0. 新增包取用
在專案裡增加對 WeihanLi.EntityFramework 的取用
dotnet add package WeihanLi.EntityFramework
來看個使用例子:
使用方式:
1. 不需要定義自己的Repository,預設使用泛型的Repository
// 註冊 EFREpositoryservices.AddEFRepostory();// 在需要的地方使用,直接獲取一個 `IEFRepository` 服務DependencyResolver.Current.TryInvokeService<IEFRepository<TestDbContext, TestEntity>>(repo =>{repo.Update(new TestEntity{CreatedAt = DateTime.UtcNow,Extra = new { Name = "Abcde", Count = 4 }.ToJson(),Id = 3}, t => t.CreatedAt, t => t.Extra);repo.Insert(new[]{new TestEntity{Extra = new {Name = "Abcdes"}.ToJson(),CreatedAt = DateTime.Now},new TestEntity{Extra = new {Name = "Abcdes"}.ToJson(),CreatedAt = DateTime.Now}});var list = repo.GetAll().Select(_ => _.Id).ToArray();Console.WriteLine($"Ids: {list.StringJoin(",")}");repo.Get(_ => _.Id, queryBuilder => queryBuilder.WithOrderBy(q => q.OrderByDescending(_ => _.Id)));var lastItem = repo.FirstOrDefault(queryBuilder => queryBuilder.WithOrderBy(q => q.OrderByDescending(_ => _.Id)));var list1 = repo.Get(x => x.Id, queryBuilder => queryBuilder.WithOrderBy(query => query.OrderByDescending(q => q.Id)));repo.Delete(t => DbFunctions.JsonValue(t.Extra, "$.Name") == "Abcdes");Console.WriteLine($"Count: {repo.Count()}");});
2. 生成自己的 Repository 程式碼
你可以生成自己的 基於 預設的 Repository 的程式碼,預設的 Repository 的所有方法都是虛方法,可以重寫也可以,預設會生成介面和類,如果不要生成介面可以配置 EFRepositoryGeneratorOptions
// 配置不生成介面services.Configure<EFRepositoryGeneratorOptions>(options=>options.GenerateInterface=false);// 配置生成的 Repository 型別名稱, 預設是 EntityName+"Repository",可以透過 RepositoryNameResolver 自定義services.Configure<EFRepositoryGeneratorOptions>(options=>options.RepositoryNameResolver = entityName=> $"{entityName}Service");
預設生成的程式碼類似於這樣子:
using WeihanLi.EntityFramework;using WeihanLi.EntityFramework.Samples;namespace WeihanLi.EntityFramework.Samples.Business{public partial interface ITestEntityRepository : IEFRepository<TestDbContext, TestEntity> { }public partial class TestEntityRepository : EFRepository<TestDbContext, TestEntity>, ITestEntityRepository{public TestEntityRepository(TestDbContext dbContext) : base(dbContext) { }}}
如果對生成的程式碼內容部分要修改,可以自定義自己的 IEFRepositoryGenerator,然後 services.AddSingleton<IEFRepositoryGenerator,CustomEFRepositoryGenerator>() 改寫掉預設的就可以了,或者可以 Replace 直接替換也是可以的~
呼叫下麵的程式碼去生成程式碼:
DependencyResolver.Current.ResolveService<IEFRepositoryGenerator>().GenerateRepositoryCodeFor<TestDbContext>("WeihanLi.EntityFramework.Samples.Business");
QueryBuilder 使用
為 EF 添加了 FluentAPI 的 QueryBuilder 支援,使得可以更方便的進行資料查詢。
預設的 QueryBuilder 會 AsNoTracking(),如果不要 AsNoTracking可以使用 WithNoTracking(false) 來設定,EFCore 新增了一個 QueryFilter 可以全域性過濾,預設查詢也是啟動全域性過濾的,如果要在查詢中禁用這個全域性過濾可以透過 IgnoreQueryFilters() 來設定。
基本方法:
EFRepositoryQueryBuilder<TEntity> WithPredict(Expression<Func<TEntity, bool>> predict);// 設定查詢條件EFRepositoryQueryBuilder<TEntity> WithOrderBy(Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderByExpression); // 設定排序EFRepositoryQueryBuilder<TEntity> WithNoTracking(bool noTracking = true); // 設定是否 TrackingEFRepositoryQueryBuilder<TEntity> IgnoreQueryFilters(bool ignoreQueryFilters = true);// 是否忽略查詢EFRepositoryQueryBuilder<TEntity> WithInclude(Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>> include); // 設定 includeEFRepositoryQueryBuilder<TEntity> WithCount(int count);// 如果要查 Top N 的時候可以設定
使用示例如下:
var repository = serviceProvider.GetService<IEFRepository<TestDbContext, TestEntity>>();// query lastItemvar lastItem = repo.FirstOrDefault(queryBuilder => queryBuilder.WithOrderBy(q => q.OrderByDescending(_ => _.Id)));// query id list orderBy id desendingvar idList = repo.Get(x => x.Id, queryBuilder => queryBuilder.WithOrderBy(query => query.OrderByDescending(q => q.Id)));var blockList = serviceProvider.GetService<IEFRepository<TestDbContext, BlockEntity>>().GetPagedList(queryBuilder => queryBuilder.WithPredict(whereLambda).WithInclude(q => q.Include(b => b.BlockType)).WithOrderBy(q => q.OrderByDescending(b => b.BlockTime)), search.PageIndex, search.PageSize);//load datavar list = _reservationBLL.GetPagedList(queryBuilder => queryBuilder.WithPredict(whereLambda).WithOrderBy(query => query.OrderByDescending(r => r.ReservationForDate).ThenByDescending(r => r.ReservationTime)).WithInclude(query => query.Include(r => r.Place)), search.PageIndex, search.PageSize);
Reference
- https://github.com/WeihanLi/ActivityReservation/blob/dev/ActivityReservation/Controllers/HomeController.cs#L43
- https://github.com/WeihanLi/ActivityReservation/blob/dev/ActivityReservation.AdminLogic/Controllers/BlockEntityController.cs#L39
- https://github.com/WeihanLi/WeihanLi.EntityFramework/blob/dev/samples/WeihanLi.EntityFramework.Samples/Program.cs
.NET社群新聞,深度好文,歡迎訪問公眾號文章彙總 http://www.csharpkit.com
知識星球
朋友會在“發現-看一看”看到你“在看”的內容