概述
NopCommerce源码架构详解-EF数据访问实例详解。
内容
今天我来分析一下nop里面怎么访问数据库,我们知道Nop里面的ORM是使用的EF并采用的仓储Repository模式。
1、IRepository
首先,Nop定义了一个通用的泛型接口:
Nop.Core.Data.IRepository

里面定义了常用的增、删、查、改等操作方法,但是由于是接口,只是方法定义没有实现。
声明成泛型的好处只用定义一些通用的方法,这样可以适用于所有的表。而不用每一个表单独定义一个类重复这些增、删、查、改方法。
2、EfRepository
Nop.Data.EfRepository就是上面接口Nop.Core.Data.IRepository的EF具体实现。

可以看到使用了EF相关的API,比如:DbContext,DbSet等,下面我具体来看一下插入、添加一条记录的方法:

3、依赖注入
Nop里面代码到处都充分体现了面向接口编程,所有代码你F12跟踪进去都是只定位到对应的接口。
查看Controller代码看到Controller引用是都是Service的接口,如图:

Nop里是通过Autofac对mvc的Controller进行依赖注入的。
这个时候我们要看这些Service接口的具体实现才能找到其“庐山真面目”。
我们随便找一个Service具体实现
UrlRecordService的一些方法:
public virtual UrlRecord GetBySlug(string slug) { if (String.IsNullOrEmpty(slug)) return null; var query = from ur in _urlRecordRepository.Table where ur.Slug == slug //first, try to find an active record orderby ur.IsActive descending, ur.Id select ur; var urlRecord = query.FirstOrDefault(); return urlRecord; } public virtual UrlRecordForCaching GetBySlugCached(string slug) { if (String.IsNullOrEmpty(slug)) return null; if (_localizationSettings.LoadAllUrlRecordsOnStartup) { //获取已缓存全部Url记录数据 var source = GetAllUrlRecordsCached(); var query = from ur in source where ur.Slug.Equals(slug, StringComparison.InvariantCultureIgnoreCase) //first, try to find an active record orderby ur.IsActive descending, ur.Id select ur; var urlRecordForCaching = query.FirstOrDefault(); return urlRecordForCaching; } //gradual loading string key = string.Format(URLRECORD_BY_SLUG_KEY, slug); return _cacheManager.Get(key, () => { var urlRecord = GetBySlug(slug); if (urlRecord == null) return null; var urlRecordForCaching = Map(urlRecord); return urlRecordForCaching; }); } /// <summary> /// Gets all cached URL records /// </summary> /// <returns>cached URL records</returns> protected virtual IList<UrlRecordForCaching> GetAllUrlRecordsCached() { //cache string key = string.Format(URLRECORD_ALL_KEY); return _cacheManager.Get(key, () => { var query = from ur in _urlRecordRepository.Table select ur; var urlRecords = query.ToList(); var list = new List<UrlRecordForCaching>(); foreach (var ur in urlRecords) { var urlRecordForCaching = Map(ur); list.Add(urlRecordForCaching); } return list; }); }
可以从上面代码看到上面通过Repository.Table和linq来获取数据的。上面有用到Nop的缓存管理cacheManager,我们再回过头来看看.Table是什么? 在接口Nop.Core.Data.IRepository里面

然后我们再来看接口的实现Nop.Data.EfRepository对应的实现:

可以看到采用的EF的的DbSet返回表的数据,对使用过EF的同学都不用我再解释了吧?
上面我们有说Controller引用的IXXXService接口,而IXXXService接口的具体实现XXXXXXService又是引用的IXXXRepository接口,IXXXRepository接口具体实现是XXXRepository。
不同表,T就相应不同,比如UrlRecordService里面Repository。

最后,Nop里面又怎么设置Nop.Core.Data.IRepository使用是Nop.Data.EfRepository呢?
在项目Nop.Web.Framework里面有一个类DependencyRegistrar专门告诉Autofac依赖注册的。

在DependencyRegistrar类里面我们可以找到以下代码:

通过builder.RegisterGeneric可以注册泛型依赖。同理你要可以在这个类里面找到IXXXService的依赖注入。
到此,Nop的使用EF访问数据库就来龙去脉已经清楚,现在你可以打开代码自己DIY。