使用IRepository不只是架构上解耦的需要,更重要的意义在于Service的单元测试,Repository模式本身就是采用集合操作的方式简化数据访问,IRepository更容易Mock。先上图:
鉴于目前接触到的项目中,即使业务逻辑相对复杂的项目也只是应用逻辑复杂而非领域逻辑复杂,在实际使用中聚合根和单独Repository接口只是引入了更多的代码和类型定义,因此一般情况下使用泛型版本的Repository<T>接口即可。nopcommerce等开源项目中也是如此。Java中的伪泛型无法实现泛型版本的Repository<T>,简单的说你无法在Repository<T>的方法中获取T的类型。
1 namespace Example.Application 2 { IRepository<T> where T : class 4 { 5 T FindBy(object id); 6 7 IQueryable<T> Query { get; } Add(T entity); Remove(T entity); Update(T entity); Commit(); 16 } 17 }
2.封装DbContext的依赖项(1)定义一个通用的EfDbContext,将DbContext对IDbConnectionFactory、ConnectionString、实体类配置等的依赖封装到DbSettings中,既可以在使用使方便依赖注入也方便进行单元测试。
1 namespace Example.Infrastructure.Repository 2 { EfDbContext : DbContext, IDbContext 4 { 5 private DbSettings _dbSettings; EfDbContext(IConfiguration configuration, ILogger logger, DbSettings dbSettings) : base(dbSettings.NameOrConnectionString) 8 { 9 this._dbSettings = dbSettings; 10 if (this._dbSettings.DbConnectionFactory != null) 11 { 12 #pragma warning disable 13 Database.DefaultConnectionFactory = this._dbSettings.DbConnectionFactory; 14 } , false)) 16 { 17 this.Database.Log = sql => logger.Information(sql); 18 } 19 this.Database.Log = l => System.Diagnostics.Debug.WriteLine(l); 20 } OnModelCreating(DbModelBuilder modelBuilder) 23 { 24 base.OnModelCreating(modelBuilder); 25 26 modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); 27 if (_dbSettings.EntityMaps != null) 28 { 29 foreach (var item in _dbSettings.EntityMaps) 30 { 31 modelBuilder.Configurations.Add((dynamic)item); 32 } 33 } 34 if (_dbSettings.ComplexMaps != null) 35 { 36 foreach (var item in _dbSettings.ComplexMaps) 37 { 38 modelBuilder.Configurations.Add((dynamic)item); 39 } 40 } 41 } SetInitializer<T>() where T : DbContext 44 { 45 if (this._dbSettings.Debug) 46 { 47 if (this._dbSettings.UnitTest) 48 { 49 Database.SetInitializer(new DropCreateDatabaseAlways<T>()); 50 } 51 { 52 Database.SetInitializer(new DropCreateDatabaseIfModelChanges<T>()); 53 } 54 } { 57 Database.SetInitializer<T>(null); 58 } 59 } IDbSet<T> Set<T>() where T : class 62 { .Set<T>(); 64 } Commit() 67 { .SaveChanges(); 69 } 70 } 71 }
(2)在DbSettings中按需定义依赖,这里将实体类的配置也通过DbSettings注入。