• NOP源码分析五,文件位置等详细内容,感冒真难受,嗓子痒又疼。。


    前面我们知道,依赖注入是通过实现IDependencyRegistrar接口的Register方法实现的。而NOP的依赖类是在Nop.Web.Framework下的DependencyRegistrar类,里面注册了好多类,就不黏贴了。我们再回头看一下上节介绍的任务计划。里面有个 IScheduleTaskService类 查找其实现类,代码如下:

    namespace Nop.Services.Tasks
    {
        /// <summary>
        /// Task service
        /// </summary>
        public partial class ScheduleTaskService : IScheduleTaskService
        {
            #region Fields
    
            private readonly IRepository<ScheduleTask> _taskRepository;
    
            #endregion
    
            #region Ctor
    
            public ScheduleTaskService(IRepository<ScheduleTask> taskRepository)
            {
                this._taskRepository = taskRepository;
            }
    
            #endregion
    
            #region Methods
    
            /// <summary>
            /// Deletes a task
            /// </summary>
            /// <param name="task">Task</param>
            public virtual void DeleteTask(ScheduleTask task)
            {
                if (task == null)
                    throw new ArgumentNullException("task");
    
                _taskRepository.Delete(task);
            }
    
            /// <summary>
            /// Gets a task
            /// </summary>
            /// <param name="taskId">Task identifier</param>
            /// <returns>Task</returns>
            public virtual ScheduleTask GetTaskById(int taskId)
            {
                if (taskId == 0)
                    return null;
    
                return _taskRepository.GetById(taskId);
            }
    
            /// <summary>
            /// Gets a task by its type
            /// </summary>
            /// <param name="type">Task type</param>
            /// <returns>Task</returns>
            public virtual ScheduleTask GetTaskByType(string type)
            {
                if (String.IsNullOrWhiteSpace(type))
                    return null;
    
                var query = _taskRepository.Table;
                query = query.Where(st => st.Type == type);
                query = query.OrderByDescending(t => t.Id);
    
                var task = query.FirstOrDefault();
                return task;
            }
    
            /// <summary>
            /// Gets all tasks
            /// </summary>
            /// <param name="showHidden">A value indicating whether to show hidden records</param>
            /// <returns>Tasks</returns>
            public virtual IList<ScheduleTask> GetAllTasks(bool showHidden = false)
            {
                var query = _taskRepository.Table;
                if (!showHidden)
                {
                    query = query.Where(t => t.Enabled);
                }
                query = query.OrderByDescending(t => t.Seconds);
    
                var tasks = query.ToList();
                return tasks;
            }
    
            /// <summary>
            /// Inserts a task
            /// </summary>
            /// <param name="task">Task</param>
            public virtual void InsertTask(ScheduleTask task)
            {
                if (task == null)
                    throw new ArgumentNullException("task");
    
                _taskRepository.Insert(task);
            }
    
            /// <summary>
            /// Updates the task
            /// </summary>
            /// <param name="task">Task</param>
            public virtual void UpdateTask(ScheduleTask task)
            {
                if (task == null)
                    throw new ArgumentNullException("task");
    
                _taskRepository.Update(task);
            }
    
            #endregion
        }
    }

    我们看到所有的操作都是通过IRepository类(仓库,存储类),进行的 。然后再到DependencyRegistrar里查找实现类,接口就不贴代码了,实现类都实现了。如下:

    namespace Nop.Data
    {
        /// <summary>
        /// Entity Framework repository
        /// </summary>
        public partial class EfRepository<T> : IRepository<T> where T : BaseEntity
        {
            #region Fields
    
            private readonly IDbContext _context;
            private IDbSet<T> _entities;
    
            #endregion
    
            #region Ctor
    
            /// <summary>
            /// Ctor
            /// </summary>
            /// <param name="context">Object context</param>
            public EfRepository(IDbContext context)
            {
                this._context = context;
            }
            
            #endregion
            
            #region Methods
    
            /// <summary>
            /// Get entity by identifier
            /// </summary>
            /// <param name="id">Identifier</param>
            /// <returns>Entity</returns>
            public virtual T GetById(object id)
            {
                //see some suggested performance optimization (not tested)
                //http://stackoverflow.com/questions/11686225/dbset-find-method-ridiculously-slow-compared-to-singleordefault-on-id/11688189#comment34876113_11688189
                return this.Entities.Find(id);
            }
    
            /// <summary>
            /// Insert entity
            /// </summary>
            /// <param name="entity">Entity</param>
            public virtual void Insert(T entity)
            {
                try
                {
                    if (entity == null)
                        throw new ArgumentNullException("entity");
    
                    this.Entities.Add(entity);
    
                    this._context.SaveChanges();
                }
                catch (DbEntityValidationException dbEx)
                {
                    var msg = string.Empty;
    
                    foreach (var validationErrors in dbEx.EntityValidationErrors)
                        foreach (var validationError in validationErrors.ValidationErrors)
                            msg += string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage) + Environment.NewLine;
    
                    var fail = new Exception(msg, dbEx);
                    //Debug.WriteLine(fail.Message, fail);
                    throw fail;
                }
            }
    
            /// <summary>
            /// Insert entities
            /// </summary>
            /// <param name="entities">Entities</param>
            public virtual void Insert(IEnumerable<T> entities)
            {
                try
                {
                    if (entities == null)
                        throw new ArgumentNullException("entities");
    
                    foreach (var entity in entities)
                        this.Entities.Add(entity);
    
                    this._context.SaveChanges();
                }
                catch (DbEntityValidationException dbEx)
                {
                    var msg = string.Empty;
    
                    foreach (var validationErrors in dbEx.EntityValidationErrors)
                        foreach (var validationError in validationErrors.ValidationErrors)
                            msg += string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage) + Environment.NewLine;
    
                    var fail = new Exception(msg, dbEx);
                    //Debug.WriteLine(fail.Message, fail);
                    throw fail;
                }
            }
    
            /// <summary>
            /// Update entity
            /// </summary>
            /// <param name="entity">Entity</param>
            public virtual void Update(T entity)
            {
                try
                {
                    if (entity == null)
                        throw new ArgumentNullException("entity");
    
                    this._context.SaveChanges();
                }
                catch (DbEntityValidationException dbEx)
                {
                    var msg = string.Empty;
    
                    foreach (var validationErrors in dbEx.EntityValidationErrors)
                        foreach (var validationError in validationErrors.ValidationErrors)
                            msg += Environment.NewLine + string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
    
                    var fail = new Exception(msg, dbEx);
                    //Debug.WriteLine(fail.Message, fail);
                    throw fail;
                }
            }
    
            /// <summary>
            /// Delete entity
            /// </summary>
            /// <param name="entity">Entity</param>
            public virtual void Delete(T entity)
            {
                try
                {
                    if (entity == null)
                        throw new ArgumentNullException("entity");
    
                    this.Entities.Remove(entity);
    
                    this._context.SaveChanges();
                }
                catch (DbEntityValidationException dbEx)
                {
                    var msg = string.Empty;
    
                    foreach (var validationErrors in dbEx.EntityValidationErrors)
                        foreach (var validationError in validationErrors.ValidationErrors)
                            msg += Environment.NewLine + string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
    
                    var fail = new Exception(msg, dbEx);
                    //Debug.WriteLine(fail.Message, fail);
                    throw fail;
                }
            }
    
            /// <summary>
            /// Delete entities
            /// </summary>
            /// <param name="entities">Entities</param>
            public virtual void Delete(IEnumerable<T> entities)
            {
                try
                {
                    if (entities == null)
                        throw new ArgumentNullException("entities");
    
                    foreach (var entity in entities)
                        this.Entities.Remove(entity);
    
                    this._context.SaveChanges();
                }
                catch (DbEntityValidationException dbEx)
                {
                    var msg = string.Empty;
    
                    foreach (var validationErrors in dbEx.EntityValidationErrors)
                        foreach (var validationError in validationErrors.ValidationErrors)
                            msg += Environment.NewLine + string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
    
                    var fail = new Exception(msg, dbEx);
                    //Debug.WriteLine(fail.Message, fail);
                    throw fail;
                }
            }
            
            #endregion
    
            #region Properties
    
            /// <summary>
            /// Gets a table
            /// </summary>
            public virtual IQueryable<T> Table
            {
                get
                {
                    return this.Entities;
                }
            }
    
            /// <summary>
            /// Gets a table with "no tracking" enabled (EF feature) Use it only when you load record(s) only for read-only operations
            /// </summary>
            public virtual IQueryable<T> TableNoTracking
            {
                get
                {
                    return this.Entities.AsNoTracking();
                }
            }
    
            /// <summary>
            /// Entities
            /// </summary>
            protected virtual IDbSet<T> Entities
            {
                get
                {
                    if (_entities == null)
                        _entities = _context.Set<T>();
                    return _entities;
                }
            }
    
            #endregion
        }
    }

    我们就从下面这个方法开始研究:

    public virtual IList<ScheduleTask> GetAllTasks(bool showHidden = false)
            {
                var query = _taskRepository.Table;
                if (!showHidden)
                {
                    query = query.Where(t => t.Enabled);
                }
                query = query.OrderByDescending(t => t.Seconds);
    
                var tasks = query.ToList();
                return tasks;
            }

    其中这是虚方法:简单一点说就是子类中override的方法能够覆盖基类中的virtual方法,当你把一个子类的实例转换为基类时,调用该方法时还是调用的子类的override的方法。

    我们看下_taskRepository.Table的代码如下:

    public virtual IQueryable<T> Table
            {
                get
                {
                    return this.Entities;
                }
            }

    调用的是Entities。代码如下:

    protected virtual IDbSet<T> Entities
            {
                get
                {
                    if (_entities == null)
                        _entities = _context.Set<T>();
                    return _entities;
                }
            }

    _entities的声明时: private IDbSet<T> _entities; 是通过_context获得的。是通过构造传入的如下:

    ublic EfRepository(IDbContext context)
            {
                this._context = context;
            }

    IDbContext 从依赖注入查到代码如下:

    if (dataProviderSettings != null && dataProviderSettings.IsValid())
                {
                    var efDataProviderManager = new EfDataProviderManager(dataSettingsManager.LoadSettings());
                    var dataProvider = efDataProviderManager.LoadDataProvider();
                    dataProvider.InitConnectionFactory();
    
                    builder.Register<IDbContext>(c => new NopObjectContext(dataProviderSettings.DataConnectionString)).InstancePerLifetimeScope();
                }
                else
                {
                    builder.Register<IDbContext>(c => new NopObjectContext(dataSettingsManager.LoadSettings().DataConnectionString)).InstancePerLifetimeScope();
                }

    如果数据库正常配置成功(我们一般用SQL),则LoadDataProvider方法返回如下代码

    case "sqlserver":
                        return new SqlServerDataProvider();

    下面是SqlServerDataProvider实现类:

    namespace Nop.Data
    {
        public class SqlServerDataProvider : IDataProvider
        {
            #region Utilities
    
            protected virtual string[] ParseCommands(string filePath, bool throwExceptionIfNonExists)
            {
                if (!File.Exists(filePath))
                {
                    if (throwExceptionIfNonExists)
                        throw new ArgumentException(string.Format("Specified file doesn't exist - {0}", filePath));
                    
                    return new string[0];
                }
    
    
                var statements = new List<string>();
                using (var stream = File.OpenRead(filePath))
                using (var reader = new StreamReader(stream))
                {
                    string statement;
                    while ((statement = ReadNextStatementFromStream(reader)) != null)
                    {
                        statements.Add(statement);
                    }
                }
    
                return statements.ToArray();
            }
    
            protected virtual string ReadNextStatementFromStream(StreamReader reader)
            {
                var sb = new StringBuilder();
    
                while (true)
                {
                    var lineOfText = reader.ReadLine();
                    if (lineOfText == null)
                    {
                        if (sb.Length > 0)
                            return sb.ToString();
                        
                        return null;
                    }
    
                    if (lineOfText.TrimEnd().ToUpper() == "GO")
                        break;
    
                    sb.Append(lineOfText + Environment.NewLine);
                }
    
                return sb.ToString();
            }
    
            #endregion
    
            #region Methods
    
            /// <summary>
            /// Initialize connection factory
            /// </summary>
            public virtual void InitConnectionFactory()
            {
                var connectionFactory = new SqlConnectionFactory();
                //TODO fix compilation warning (below)
                #pragma warning disable 0618
                Database.DefaultConnectionFactory = connectionFactory;
            }
    
            /// <summary>
            /// Initialize database
            /// </summary>
            public virtual void InitDatabase()
            {
                InitConnectionFactory();
                SetDatabaseInitializer();
            }
    
            /// <summary>
            /// Set database initializer
            /// </summary>
            public virtual void SetDatabaseInitializer()
            {
                //pass some table names to ensure that we have nopCommerce 2.X installed
                var tablesToValidate = new[] { "Customer", "Discount", "Order", "Product", "ShoppingCartItem" };
    
                //custom commands (stored proedures, indexes)
    
                var customCommands = new List<string>();
                //use webHelper.MapPath instead of HostingEnvironment.MapPath which is not available in unit tests
                customCommands.AddRange(ParseCommands(HostingEnvironment.MapPath("~/App_Data/Install/SqlServer.Indexes.sql"), false));
                //use webHelper.MapPath instead of HostingEnvironment.MapPath which is not available in unit tests
                customCommands.AddRange(ParseCommands(HostingEnvironment.MapPath("~/App_Data/Install/SqlServer.StoredProcedures.sql"), false));
    
                var initializer = new CreateTablesIfNotExist<NopObjectContext>(tablesToValidate, customCommands.ToArray());
                Database.SetInitializer(initializer);
            }
    
            /// <summary>
            /// A value indicating whether this data provider supports stored procedures
            /// </summary>
            public virtual bool StoredProceduredSupported
            {
                get { return true; }
            }
    
            /// <summary>
            /// Gets a support database parameter object (used by stored procedures)
            /// </summary>
            /// <returns>Parameter</returns>
            public virtual DbParameter GetParameter()
            {
                return new SqlParameter();
            }
    
            #endregion
        }
    }

    查看调用dataProvider.InitConnectionFactory(); 方法的代码如下:

    /// <summary>
            /// Initialize connection factory
            /// </summary>
            public virtual void InitConnectionFactory()
            {
                var connectionFactory = new SqlConnectionFactory();
                //TODO fix compilation warning (below)
                #pragma warning disable 0618
                Database.DefaultConnectionFactory = connectionFactory;
            }

    就是设置了默认连接工厂类,  是EF6里自带的一个类,下面是无参构造函数的说明:

    // 摘要: 
            //     Creates a new connection factory with a default BaseConnectionString property
            //     of 'Data Source=.SQLEXPRESS; Integrated Security=True; MultipleActiveResultSets=True;'.
            public SqlConnectionFactory();

    最终 注册的是NopObjectContext 代码如下:

    public class NopObjectContext : DbContext, IDbContext
        {
            #region Ctor
    
            public NopObjectContext(string nameOrConnectionString)
                : base(nameOrConnectionString)
            {
                //((IObjectContextAdapter) this).ObjectContext.ContextOptions.LazyLoadingEnabled = true;
            }

    然后调用他的Set方法,就是调用父类,EF自带类功能的方法:因为继承自DbContext,所以基本都可以调用它的功能进行操作,事实也是这么做的,比如插入实体insert.

    public new IDbSet<TEntity> Set<TEntity>() where TEntity : BaseEntity
            {
                return base.Set<TEntity>();
            }

    内部有一个很重要的方法:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                //dynamically load all configuration
                //System.Type configType = typeof(LanguageMap);   //any of your configuration classes here
                //var typesToRegister = Assembly.GetAssembly(configType).GetTypes()
    
                var typesToRegister = Assembly.GetExecutingAssembly().GetTypes()
                .Where(type => !String.IsNullOrEmpty(type.Namespace))
                .Where(type => type.BaseType != null && type.BaseType.IsGenericType &&
                    type.BaseType.GetGenericTypeDefinition() == typeof(NopEntityTypeConfiguration<>));
                foreach (var type in typesToRegister)
                {
                    dynamic configurationInstance = Activator.CreateInstance(type);
                    modelBuilder.Configurations.Add(configurationInstance);
                }
                //...or do it manually below. For example,
                //modelBuilder.Configurations.Add(new LanguageMap());
    
    
    
                base.OnModelCreating(modelBuilder);
            }

    获取当前执行代码的程序集的类型并筛选,筛选出有命名空间、有父类并且父类是NopEntityTypeConfiguration类型的 类 ,循环得到类型的示例,并加入的配置。

    NopEntityTypeConfiguration 继承自 EntityTypeConfiguration,作用是可以修改是实体类的对应关系, 这里的映射类都继承自NopEntityTypeConfiguration ,实现了关系映射。

    所有的关系映射类几乎都在Nop.Data.Mapping下。

  • 相关阅读:
    Qt为啥从4.8直接就跳到5.3了呢?这不科学吧
    一段程序的人生 第10章: server
    项目记录23--unity-tolua框架MediatorManager
    Raft 为什么是更易理解的分布式一致性算法
    Caused by: java.lang.UnsatisfiedLinkError: Couldn&#39;t load BaiduMapVOS_v2_1_3: findLibrary returned nu
    Apache OFBIZ高速上手(二)--MVC框架
    Eclipse 导入逆向工程
    mysql 报错从 新安装
    maven项目创建4
    maven报错
  • 原文地址:https://www.cnblogs.com/runit/p/4178572.html
Copyright © 2020-2023  润新知