NOP拆分一:EF初步拆分,支持SqlServer,Oracle,Mysql
主要内容
根据NopCommerce一步步拆分出自己的一套架构,在这个过程中完成对过去知识的梳理。主要拆分包括EF,Autofac,MVC,缓存等。这篇文章是有关EF拆分的第一步,可以支持多个数据库,并可以使用CodeFirst模式初始化数据库。
项目基于.Net Framework4.5, Entity Framework6
目录结构
目前涉及到的文件夹:
- NOP.Code项目中的Data ,DataProvider的接口定义,以及Provider管理类;
- NOP.Code项目中的Domain ,数据库模型类;
- NOP.Data项目中的Initializers ,不同数据库的初始化类;
- NOP.Data项目中的Mapping ,实体模型映射类;
- NOP.Data项目中的Providers ,不同数据库的Provider;
基础架构
导包
使用NuGet导入EntityFramework6.0.0.0
DataProvider
- 在NOP.Core的Data文件夹下创建IDataProvider接口:
namespace Nop.Core.Data
{
public interface IDataProvider
{
/// <summary>
/// 初始化数据库连接
/// </summary>
void InitConnectionFactory();
/// <summary>
/// 数据库初始化配置,可以在该方法中为Database配置初始化方式
/// </summary>
void SetDatabaseInitializer();
/// <summary>
///初始化数据库
/// </summary>
void InitDatabase();
/// <summary>
/// A value indicating whether this data provider supports stored procedures
/// </summary>
bool StoredProceduredSupported { get; }
/// <summary>
/// Gets a support database parameter object (used by stored procedures)
/// </summary>
/// <returns>Parameter</returns>
DbParameter GetParameter();
}
}
这个接口很重要,不同数据库实现该接口后,可以自定义数据库初始化方式,连接工厂等,Oracle和Mysql才可以使用EF.
- 在NOP.Core的Data文件夹下创建DataSettings类:
namespace Nop.Core.Data
{
/// <summary>
/// 链接配置
/// </summary>
public partial class DataSettings
{
public DataSettings()
{
RawDataSettings = new Dictionary<string, string>();
}
/// <summary>
/// 数据库类型
/// </summary>
public string DBType { get; set; }
/// <summary>
/// Data provider
/// </summary>
public string DataProvider { get; set; }
/// <summary>
/// Connection string
/// </summary>
public string DataConnectionString { get; set; }
/// <summary>
/// Raw settings file
/// </summary>
public IDictionary<string, string> RawDataSettings { get; private set; }
/// <summary>
/// A value indicating whether entered information is valid
/// </summary>
/// <returns></returns>
public bool IsValid()
{
return !String.IsNullOrEmpty(this.DataProvider) && !String.IsNullOrEmpty(this.DataConnectionString);
}
}
}
就是保存数据库连接配置的,没什么
- 在NOP.Core的Data文件夹下创建BaseDataProviderManager类:
namespace Nop.Core.Data
{
public abstract class BaseDataProviderManager
{
/// <summary>
/// Ctor
/// </summary>
/// <param name="settings">Data settings</param>
protected BaseDataProviderManager(DataSettings settings)
{
if (settings == null)
throw new ArgumentNullException("settings");
this.Settings = settings;
}
/// <summary>
/// Gets or sets settings
/// </summary>
protected DataSettings Settings { get; private set; }
/// <summary>
/// Load data provider
/// </summary>
/// <returns>Data provider</returns>
public abstract IDataProvider LoadDataProvider();
}
}
这是一个虚方法, Provider管理类通过继承BaseDataProviderManager,并重写LoadDataProvider方法,返回不同数据库的Provider
- 在Nop.Data项目中创建EfDataProviderManager类:
namespace Nop.Data
{
public partial class EfDataProviderManager : BaseDataProviderManager
{
public EfDataProviderManager(DataSettings settings) : base(settings)
{
}
public override IDataProvider LoadDataProvider()
{
var dbType = Settings.DBType;
if (string.IsNullOrEmpty(dbType))
{
throw new NopException("Data Settings doesn't contain a dbType");
}
switch (dbType.ToLowerInvariant())
{
case "sqlserver":
return new MSDataProvider();
case "oracle":
return new OracleDataProvider();
case "mysql":
return new MySqlDataProvider();
default:
throw new NopException(string.Format("Not supported dataprovider name: {0}", dbType));
}
}
}
}
根据数据库类型,返回相应的Provider,这个不用多说了。
DbContext
- 在Nop.Data项目中创建IDbContext接口,实现该接口, 对EF原始DBContext进行封装:
namespace Nop.Data
{
public interface IDbContext
{
/// <summary>
/// Get DbSet
/// </summary>
/// <typeparam name="TEntity">Entity type</typeparam>
/// <returns>DbSet</returns>
IDbSet<TEntity> Set<TEntity>() where TEntity : BaseEntity;
/// <summary>
/// Save changes
/// </summary>
/// <returns></returns>
int SaveChanges();
/// <summary>
/// 执行存储过程,并返回列表
/// </summary>
/// <typeparam name="TEntity">Entity type</typeparam>
/// <param name="commandText">Command text</param>
/// <param name="parameters">Parameters</param>
/// <returns>Entities</returns>
IList<TEntity> ExecuteStoredProcedureList<TEntity>(string commandText, params object[] parameters)
where TEntity : BaseEntity, new();
/// <summary>
/// Creates a raw SQL query that will return elements of the given generic type. The type can be any type that has properties that match the names of the columns returned from the query, or can be a simple primitive type. The type does not have to be an entity type. The results of this query are never tracked by the context even if the type of object returned is an entity type.
/// 执行SQL查询,返回TElement列表,TElement可以是任何类型,且不会对查询结果进行追踪
///