NOP拆分一:EF初步拆分,支持SqlServer,Oracle,Mysql

本文介绍了从NopCommerce项目中逐步拆分出独立的EF架构过程,支持多种数据库,包括SqlServer、Oracle和Mysql。文章详细阐述了各个数据库的DataProvider、DbContext和IDatabaseInitializer的实现,并提供了测试步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

主要内容

根据NopCommerce一步步拆分出自己的一套架构,在这个过程中完成对过去知识的梳理。主要拆分包括EF,Autofac,MVC,缓存等。这篇文章是有关EF拆分的第一步,可以支持多个数据库,并可以使用CodeFirst模式初始化数据库。
项目基于.Net Framework4.5, Entity Framework6

目录结构

目录结构
目前涉及到的文件夹:

  1. NOP.Code项目中的Data ,DataProvider的接口定义,以及Provider管理类;
  2. NOP.Code项目中的Domain ,数据库模型类;
  3. NOP.Data项目中的Initializers ,不同数据库的初始化类;
  4. NOP.Data项目中的Mapping ,实体模型映射类;
  5. NOP.Data项目中的Providers ,不同数据库的Provider;

基础架构

导包

如图
使用NuGet导入EntityFramework6.0.0.0

DataProvider

  1. 在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.

  1. 在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);
        }
    }
}

就是保存数据库连接配置的,没什么

  1. 在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

  1. 在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

  1. 在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可以是任何类型,且不会对查询结果进行追踪
        /// 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值