借助 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);

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