在ABP实际使用过程有时候需要对IRepository进行扩展,增加一些自定义方法。
先创建一个自定义仓储接口对IRepository<TEntity, TPrimaryKey>进行扩展。
using System; using System.Linq.Expressions; using Abp.Dependency; using Abp.Domain.Entities; using Abp.Domain.Repositories; namespace MyProject.Domain { /// <summary> /// 定义仓储模型中的扩展操作 /// </summary> public interface IMyRepository<TEntity, TPrimaryKey> : IRepository<TEntity, TPrimaryKey> where TEntity : class, IEntity<TPrimaryKey> { /// <summary> /// 为<see cref="IRepository{TEntity, TPrimaryKey}"/>扩展一个可以获取关联实体的FirstOrDefault操作 /// </summary> /// <param name="predicate"></param> /// <param name="includeExpression"></param> /// <returns></returns> TEntity FirstOrDefault(Expression<Func<TEntity, bool>> predicate, params Expression<Func<TEntity, object>>[] includeExpression); } public interface IMyRepository<TEntity> : IMyRepository<TEntity, int>, IRepository, ITransientDependency where TEntity : class, IEntity<int> { } }
创建IMyRepository的实现类MyRepository,它继承自ABP自动创建的MyProjectRepositoryBase的这个基类。
using System; using System.Linq; using System.Linq.Expressions; using Abp.Domain.Entities; using Abp.EntityFrameworkCore; using Abp.EntityFrameworkCore.Repositories; using MyProject.Domain; namespace MyProject.EntityFrameworkCore.Repositories { /// <summary> /// 实现仓储模型中的扩展操作 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <typeparam name="TPrimaryKey"></typeparam> public class MyRepository<TEntity, TPrimaryKey> : MyProjectRepositoryBase<TEntity, TPrimaryKey>, IMyRepository<TEntity, TPrimaryKey> where TEntity : class, IEntity<TPrimaryKey> { public MyRepository(IDbContextProvider<MyProjectDbContext> dbContextProvider) : base(dbContextProvider) { } public TEntity FirstOrDefault(Expression<Func<TEntity, bool>> predicate, params Expression<Func<TEntity, object>>[] includeExpression) { return GetAllIncluding(includeExpression).FirstOrDefault(predicate); } } public class MyRepository<TEntity> : MyRepository<TEntity, int>, IMyRepository<TEntity> where TEntity : class, IEntity<int> { public MyRepository(IDbContextProvider<MyProjectDbContext> dbContextProvider) : base(dbContextProvider) { } } }
创建MyEfCoreAutoRepositoryTypes用于关联仓储接口和其默认实现。
using System; using Abp.Domain.Repositories; using MyProject.Domain; namespace MyProject.EntityFrameworkCore.Repositories { /// <summary> /// 关联仓储接口和其默认实现。 /// </summary> public class MyEfCoreAutoRepositoryTypes { public static AutoRepositoryTypesAttribute Default { get; } static MyEfCoreAutoRepositoryTypes() { Default = new AutoRepositoryTypesAttribute( typeof(IMyRepository<>), typeof(IMyRepository<,>), typeof(MyRepository<>), typeof(MyRepository<,>) ); } } }
修改MyProjectEntityFrameworkModule为其添加RegisterGenericRepositoriesAndMatchDbContexes方法为DbContext中每个实体注册一个IMyRepository的默认实现,并在Initialize中调用这个注册方法。
using System; using System.Reflection; using Abp.Collections.Extensions; using Abp.Dependency; using Abp.EntityFramework; using Abp.EntityFramework.Repositories; using Abp.EntityFrameworkCore; using Abp.EntityFrameworkCore.Configuration; using Abp.Modules; using Abp.Orm; using Abp.Reflection; using Abp.Reflection.Extensions; using Abp.Zero.EntityFrameworkCore; using Castle.MicroKernel.Registration; using MyProject.EntityFrameworkCore.Repositories; using MyProject.EntityFrameworkCore.Seed; namespace MyProject.EntityFrameworkCore { [DependsOn( typeof(MyProjectCoreModule), typeof(AbpZeroCoreEntityFrameworkCoreModule))] public class MyProjectEntityFrameworkModule : AbpModule { /* Used it tests to skip dbcontext registration, in order to use in-memory database of EF Core */ public bool SkipDbContextRegistration { get; set; } public bool SkipDbSeed { get; set; } private readonly ITypeFinder _typeFinder; public MyProjectEntityFrameworkModule(ITypeFinder typeFinder) { _typeFinder = typeFinder; } public override void PreInitialize() {
... } public override void Initialize() { IocManager.RegisterAssemblyByConvention(typeof(MyProjectEntityFrameworkModule).GetAssembly()); //调用注册方法 RegisterGenericRepositoriesAndMatchDbContexes(); } public override void PostInitialize() { ... } /// <summary> /// 为DbContext中表达的实体注册通用的Repository /// </summary> private void RegisterGenericRepositoriesAndMatchDbContexes() { //获取所有注入的数据库上下文 var dbContextTypes = _typeFinder.Find(type => { var typeInfo = type.GetTypeInfo(); return typeInfo.IsPublic && !typeInfo.IsAbstract && typeInfo.IsClass && typeof(AbpDbContext).IsAssignableFrom(type); }); if (dbContextTypes.IsNullOrEmpty()) { Logger.Warn("No class found derived from AbpDbContext."); return; } using (IScopedIocResolver scope = IocManager.CreateScope()) { foreach (var dbContextType in dbContextTypes) { Logger.Debug("Registering DbContext: " + dbContextType.AssemblyQualifiedName); //为数据上下文中的所有实体注册MyEfCoreAutoRepositoryTypes的定义的Repository。 scope.Resolve<IEfGenericRepositoryRegistrar>().RegisterForDbContext(dbContextType, IocManager, MyEfCoreAutoRepositoryTypes.Default); IocManager.IocContainer.Register( Component.For<ISecondaryOrmRegistrar>() .Named(Guid.NewGuid().ToString("N")) .Instance(new EfCoreBasedSecondaryOrmRegistrar(dbContextType, scope.Resolve<IDbContextEntityFinder>())) .LifestyleTransient() ); } } } } }
写个单元测试使用IMyRepository调用自定义的FirstOrDefault对User进行查询,并且Roles把作为关联实体进行预加载。
public class MyRepository_Test:MyProjectTestBase { private readonly IMyRepository<User, long> _myRepository; public MyRepository_Test() { //MyRepository<User, long>已经被自动注册 _myRepository = Resolve<IMyRepository<User, long>>(); } [Fact] public void GetUsers_IncludeRoles_Test() { // Act var User = _myRepository.FirstOrDefault(t => t.Name == "admin", t => t.Roles); //Assert User.Roles.ShouldNotBeNull(); } }