1.依赖IRepository接口而不是直接使用EntityFramework
  使用IRepository不只是架构上解耦的需要,更重要的意义在于Service的单元测试,Repository模式本身是采用集合操作的方式简化数据访问,IRepository更容易Mock。先上图:

  鉴于目前接触到的项目中,即使业务逻辑相对复杂的项目也只是应用逻辑复杂而非领域逻辑复杂,在实际使用中聚合根和单独Repository接口只是引入了更多的代码和类型定义,因此一般情况下使用泛型版本的Repository<T>接口即可。nopcommerce等开源项目中也是如此。Java中的伪泛型无法实现泛型版本的Repository<T>,简单的说你无法在Repository<T>的方法中获取T的类型。
1 namespace Example.Application
2 {
3     public interface IRepository<T> where T : class
4     {
5         T FindBy(object id);
6
7         IQueryable<T> Query { get; }
8
9         void Add(T entity);
10
11         void Remove(T entity);
12
13         void Update(T entity);
14
15         int Commit();
16     }
17 }
  2.封装DbContext的依赖项
  (1)定义一个通用的EfDbContext,将DbContext对IDbConnectionFactory、ConnectionString、实体类配置等的依赖封装到DbSettings中,既可以在使用使方便依赖注入也方便进行单元测试。
1 namespace Example.Infrastructure.Repository
2 {
3     public class EfDbContext : DbContext, IDbContext
4     {
5         private DbSettings _dbSettings;
6
7         public 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             }
15             if (configuration.Get<bool>("database.log:", false))
16             {
17                 this.Database.Log = sql => logger.Information(sql);
18             }
19             this.Database.Log = l => System.Diagnostics.Debug.WriteLine(l);
20         }
21
22         protected override void 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         }
42
43         public void 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             }
55             else
56             {
57                 Database.SetInitializer<T>(null);
58             }
59         }
60
61         public new IDbSet<T> Set<T>() where T : class
62         {
63             return base.Set<T>();
64         }
65
66         public int Commit()
67         {
68             return base.SaveChanges();
69         }
70     }
71 }