歡迎光臨
每天分享高質量文章

基於 EntityFramework 生成 Repository 樣式程式碼

藉助 WeihanLi.EntityFramework 實現簡單的 Repository

Intro

很多時候一些簡單的業務都是簡單的增刪改查,動態生成一些程式碼完成基本的增刪改查,而這些增刪改查程式碼大多類似,只有一些有複雜業務邏輯的可能需要手動去寫。於是實現了一個基於 EF Core 的 Repository。

GetStarted

0. 新增包取用

在專案裡增加對 WeihanLi.EntityFramework 的取用

  1. dotnet add package WeihanLi.EntityFramework

來看個使用例子:

使用方式:

1. 不需要定義自己的Repository,預設使用泛型的Repository

  1. // 註冊 EFREpository
  2. services.AddEFRepostory();
  3.  
  4. // 在需要的地方使用,直接獲取一個 `IEFRepository` 服務
  5. DependencyResolver.Current.TryInvokeService<IEFRepository<TestDbContext, TestEntity>>(repo =>
  6. {
  7. repo.Update(new TestEntity
  8. {
  9. CreatedAt = DateTime.UtcNow,
  10. Extra = new { Name = "Abcde", Count = 4 }.ToJson(),
  11. Id = 3
  12. }, t => t.CreatedAt, t => t.Extra);
  13. repo.Insert(new[]
  14. {
  15. new TestEntity
  16. {
  17. Extra = new {Name = "Abcdes"}.ToJson(),
  18. CreatedAt = DateTime.Now
  19. },
  20. new TestEntity
  21. {
  22. Extra = new {Name = "Abcdes"}.ToJson(),
  23. CreatedAt = DateTime.Now
  24. }
  25. });
  26. var list = repo.GetAll().Select(_ => _.Id).ToArray();
  27. Console.WriteLine($"Ids: {list.StringJoin(",")}");
  28.  
  29. repo.Get(_ => _.Id, queryBuilder => queryBuilder
  30. .WithOrderBy(q => q.OrderByDescending(_ => _.Id)));
  31.  
  32. var lastItem = repo.FirstOrDefault(queryBuilder => queryBuilder
  33. .WithOrderBy(q => q.OrderByDescending(_ => _.Id)));
  34.  
  35. var list1 = repo.Get(x => x.Id, queryBuilder => queryBuilder
  36. .WithOrderBy(query => query.OrderByDescending(q => q.Id))
  37. );
  38.  
  39. repo.Delete(t => DbFunctions.JsonValue(t.Extra, "$.Name") == "Abcdes");
  40. Console.WriteLine($"Count: {repo.Count()}");
  41. });

2. 生成自己的 Repository 程式碼

你可以生成自己的 基於 預設的 Repository 的程式碼,預設的 Repository 的所有方法都是虛方法,可以重寫也可以,預設會生成介面和類,如果不要生成介面可以配置 EFRepositoryGeneratorOptions

  1. // 配置不生成介面
  2. services.Configure<EFRepositoryGeneratorOptions>(options=>options.GenerateInterface=false);
  3.  
  4. // 配置生成的 Repository 型別名稱, 預設是 EntityName+"Repository",可以透過 RepositoryNameResolver 自定義
  5. services.Configure<EFRepositoryGeneratorOptions>(options=>options.RepositoryNameResolver = entityName=> $"{entityName}Service");

預設生成的程式碼類似於這樣子:

  1. using WeihanLi.EntityFramework;
  2. using WeihanLi.EntityFramework.Samples;
  3.  
  4. namespace WeihanLi.EntityFramework.Samples.Business
  5. {
  6.  
  7. public partial interface ITestEntityRepository : IEFRepository<TestDbContext, TestEntity> { }
  8. public partial class TestEntityRepository : EFRepository<TestDbContext, TestEntity>, ITestEntityRepository
  9. {
  10. public TestEntityRepository(TestDbContext dbContext) : base(dbContext) { }
  11. }
  12. }

如果對生成的程式碼內容部分要修改,可以自定義自己的 IEFRepositoryGenerator,然後 services.AddSingleton<IEFRepositoryGenerator,CustomEFRepositoryGenerator>() 改寫掉預設的就可以了,或者可以 Replace 直接替換也是可以的~

呼叫下麵的程式碼去生成程式碼:

  1. DependencyResolver.Current.ResolveService<IEFRepositoryGenerator>()
  2. .GenerateRepositoryCodeFor<TestDbContext>("WeihanLi.EntityFramework.Samples.Business");

QueryBuilder 使用

為 EF 添加了 FluentAPI 的 QueryBuilder 支援,使得可以更方便的進行資料查詢。

預設的 QueryBuilder 會 AsNoTracking(),如果不要 AsNoTracking可以使用 WithNoTracking(false) 來設定,EFCore 新增了一個 QueryFilter 可以全域性過濾,預設查詢也是啟動全域性過濾的,如果要在查詢中禁用這個全域性過濾可以透過 IgnoreQueryFilters() 來設定。

基本方法:

  1. EFRepositoryQueryBuilder<TEntity> WithPredict(Expression<Func<TEntity, bool>> predict);// 設定查詢條件
  2. EFRepositoryQueryBuilder<TEntity> WithOrderBy(Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderByExpression); // 設定排序
  3. EFRepositoryQueryBuilder<TEntity> WithNoTracking(bool noTracking = true); // 設定是否 Tracking
  4. EFRepositoryQueryBuilder<TEntity> IgnoreQueryFilters(bool ignoreQueryFilters = true);// 是否忽略查詢
  5. EFRepositoryQueryBuilder<TEntity> WithInclude(Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>> include); // 設定 include
  6. EFRepositoryQueryBuilder<TEntity> WithCount(int count);// 如果要查 Top N 的時候可以設定

使用示例如下:

  1. var repository = serviceProvider.GetService<IEFRepository<TestDbContext, TestEntity>>();
  2.  
  3. // query lastItem
  4. var lastItem = repo.FirstOrDefault(queryBuilder => queryBuilder
  5. .WithOrderBy(q => q.OrderByDescending(_ => _.Id)));
  6.  
  7. // query id list orderBy id desending
  8. var idList = repo.Get(x => x.Id, queryBuilder => queryBuilder
  9. .WithOrderBy(query => query.OrderByDescending(q => q.Id))
  10. );
  11.  
  12. var blockList = serviceProvider.GetService<IEFRepository<TestDbContext, BlockEntity>>().GetPagedList(queryBuilder => queryBuilder
  13. .WithPredict(whereLambda)
  14. .WithInclude(q => q.Include(b => b.BlockType))
  15. .WithOrderBy(q => q.OrderByDescending(b => b.BlockTime)), search.PageIndex, search.PageSize);
  16.  
  17. //load data
  18. var list = _reservationBLL.GetPagedList(queryBuilder => queryBuilder
  19. .WithPredict(whereLambda)
  20. .WithOrderBy(query => query.OrderByDescending(r => r.ReservationForDate).ThenByDescending(r => r.ReservationTime))
  21. .WithInclude(query => query.Include(r => r.Place))
  22. , 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 

贊(0)

分享創造快樂