基於 EntityFramework 生成 Repository 模式代碼


借助 WeihanLi.EntityFramework 實現簡單的 Repository

Intro

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

GetStarted

  1. 添加包引用

在項目里增加對 WeihanLi.EntityFramework 的引用

dotnet add package WeihanLi.EntityFramework

來看個使用例子

使用方式:

  1. 不需要定義自己的Repository,默認使用泛型的Repository
// 注冊 EFREpository
services.AddEFRepostory();

// 在需要的地方使用,直接獲取一個 `IEFRepository<TestDbContext, TestEntity>` 服務
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()}");
            });
  1. 生成自己的 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); // 設置是否 Tracking
EFRepositoryQueryBuilder<TEntity> IgnoreQueryFilters(bool ignoreQueryFilters = true);// 是否忽略查詢
EFRepositoryQueryBuilder<TEntity> WithInclude(Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>> include); // 設置 include
EFRepositoryQueryBuilder<TEntity> WithCount(int count);// 如果要查 Top N 的時候可以設置

使用示例如下:

var repository = serviceProvider.GetService<IEFRepository<TestDbContext, TestEntity>>();

// query lastItem
var lastItem = repo.FirstOrDefault(queryBuilder => queryBuilder
                    .WithOrderBy(q => q.OrderByDescending(_ => _.Id)));  

// query id list orderBy id desending
var 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 data
var 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);

部分更新

來看下面的示例:

repo.Update(new TestEntity
       {
            Extra = new { Name = "Abcde", Count = 4 }.ToJson(),
            CreatedAt = DateTime.UtcNow,
            Id = 1
       }, t => t.CreatedAt, t => t.Extra); // 更新 CreatedAt 和 Extra 字段

repo.UpdateWithout(new TestEntity() { Id = 2, Extra = new { Name = "ADDDDD" }.ToJson() }, x => x.CreatedAt); // 更新 CreatedAt 之外的其他字段

Reference


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM