本章节所要实现的功能和定义的方法种类比较多样,我就按照本章节名称中的顺序一个个的剖析nopCommerce_4.10应用程序是如何通过定义相应的类和方法实现这些功能的。
一、数据库映射的定义及实现
1、在nopCommerce_4.10应用程序中数据库映射的实现被定义在Nop.Data项目的Mapping文件夹中,而我则是把它们定义在Data项目的FluentAPI文件夹中(FluentAPI这个名称更能体现这些定义的作用及功能)。我在使用这些定义时把原类名称中的“Nop”去除了。这些类的实现如图1-8所示:
图1-8
2、修改NopObjectContext类:
修改其拷贝构造方法如下:
#region 拷贝构造方法
/// <summary>
/// 【拷贝构造方法】
/// </summary>
public NopObjectContext(DbContextOptions<NopObjectContext> options) : base(options)
{
/*
使用Code First模式时,在第一次生成数据库时,如果使用“Database.EnsureCreated()”语句,
可以直接生成模型所对应的数据库。如果没有定义“Database.EnsureCreated()”语句,则需要使用
执行迁移和更新命令:
Add-Migration Initialize
Update-Databas
下面语句是为了自动生成数据库自己添加,在原nopCommerce_4.10程序中并不存在。
*/
Database.EnsureCreated();
}
#endregion
在nopCommerce_4.10应用程序中数据是使用者创建的,其初始数据是通过程序自动装载的,但是我为了尽量的突出纵向的调用逻辑,弱化功能的实现只通过使用Code First模式自动生成相应的数据库和Setting实体所对应的表。
修改重写方法OnModelCreating如下:
/// <summary>
/// 【创建模型配置】
/// <param name="modelBuilder">用于为数据库上下文模型的构造生成器。</param>
/// <remarks>
/// 摘要:
/// 进一步配置模型。
/// </remarks>
/// </summary>
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//动态加载所有实体和查询类型配置
var _typeConfigurations = Assembly.GetExecutingAssembly().GetTypes()
.Where(type => (type.BaseType?.IsGenericType ?? false)
&& (type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>)
|| type.BaseType.GetGenericTypeDefinition() == typeof(QueryTypeConfiguration<>)));
foreach (var item in _typeConfigurations)
{
IMappingConfiguration _configuration = (IMappingConfiguration)Activator.CreateInstance(item);
_configuration.ApplyConfiguration(modelBuilder);
}
base.OnModelCreating(modelBuilder);
}
二、仓储定义及实现
仓储IRepository接口和EfRepository类的定义在第四节数据库启动配置已经实现,这里不再赘述。当前流行的使用领域驱动思想开发的应用程序数据层对数据库的操作有两种方式:一种即是nopCommerce_4.10应用程序所使用的通过调用指定实体的仓储实例实现数据层对数据库的操作;另一是通过工作单元封装仓储,通过工作单元调用指定实体的仓储实例实现数据层对数据库的操作,这里仓储的职能从对数据库时行操作,转变为把终端用户在进行数据操作时,把这些数据注册并存储到服务器的内存中,最终由工作单元把用户操作产生的多条数据一次提交到数据库中,这样可以提高应用程序的整体性能(注意:相对来说本人更为习惯选择第二种方法来开发程序,如有时间会对nopCommerce_4.10应用程序进行工作单元功能的重构)。
三、连接的定义及实现
1、先去除语句//optionsBuilder.UseSqlServerWithLazyLoading(services);注释使用该句可以被执行。
2、定义在Framework.Infrastructure.Extensions.DbContextOptionsBuilderExtensions类的定义。
3、在Core项目的Data文件夹中添加DataProviderType类、DataSettings类、DataSettingsManager类和NopDataSettingsDefaults类的定义,其中NopDataSettingsDefaults类中初始化了与数据连接的文件的存储的相对路径:“"~/App_Data/dataSettings.json"”。
4、DbContextOptionsBuilderExtensions类的UseSqlServerWithLazyLoading方法中的optionsBuilder.UseLazyLoadingProxies方法是Data项目通过NuGet引用Microsoft.EntityFrameworkCore.Proxies进行间接的引用(注意:这是间接引用在nopCommerce_4.10应用程序中的第三次体现),最终实现效果如图1-9
图1-9
5、在Web项目中新建文件夹App_Data,同时添加数据库连接字符串定义的dataSettings.json文
6、按F5执行程序时会在DbContextOptionsBuilderExtensions类UseSqlServerWithLazyLoading方法中的var nopConfig = services.BuildServiceProvider().GetRequiredService<NopConfig>();语句处发生异常:“System.InvalidOperationException:“No service for type 'Core.Configuration.NopConfig' has been registered.””。
7、要解决上术异常首先在Framework.Infrastructure.Extensions.ServiceCollectionExtensions 类中添加下面方法定义;
/// <summary>
/// 【配置启动配置】
/// <typeparam name="TConfig">动态配置类型。</typeparam>
/// <param name="services">服务集合实例集合。</param>
/// <param name="configuration">键/值应用程序配置属性集实例。</param>
/// <returns>
/// 返回:
/// 返回,一个指定配置类型实例,作为配置应用程序服务的参数。
/// </returns>
/// <remarks>
/// 摘要:
/// 创建、绑定和注册为指定配置参数的服务。
/// </remarks>
/// </summary>
public static TConfig ConfigureStartupConfig<TConfig>(this IServiceCollection services, IConfiguration configuration) where TConfig : class, new()
{
if (services == null)
throw new ArgumentNullException(nameof(services));
if (configuration == null)
throw new ArgumentNullException(nameof(configuration));
//创建初始化配置。
var config = new TConfig();
//将其绑定到配置的相应部分。
configuration.Bind(config);
//并将其注册为服务。
services.AddSingleton(config);
return config;
}
其次在Framework.Infrastructure.Extensions.ServiceCollectionExtensions 类中的public static ConfigureApplicationServices(this IServiceCollection services, IConfiguration configuration)方法中添加语句:
services.ConfigureStartupConfig<NopConfig>(configuration.GetSection("Nop"));
8、按F5发现能够正常启动默认的Setting.Create页面,同时打开SQL数据库发现名称为“My_nopCommerce”的数据库及其Setting实现所对应的表已经被创建出来了(如果数据库已经打开请刷新)。
9、修改Controllers.SettingControllerod类中的Create方法为:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(Setting model)
{
Setting _model = new Setting
{
StoreId = model.StoreId,
Name = model.Name,
Value = model.Value,
};
_settingService.InsertSetting(_model);
return View();
}
10、在Service.Configuration.SettingService类中添加下面方法的定义,同时在其接口中声明该方法:
/// <summary>
/// 【插入设置】
/// <param name="model">一个设置实体实例</param>
/// <remarks>
/// 摘要:
/// 插入一个指定设置实体实例到数据库相应的表中。
/// </remarks>
/// </summary>
public virtual void InsertSetting(Setting model)
{
_settingRepository.Insert(model);
}
11、去除Create.cshtml页面中的:
<div class="form-group">
<label asp-for="Id" class="control-label"></label>
<input asp-for="Id" class="form-control" />
<span asp-validation-for="Id" class="text-danger"></span>
</div>
,同时按F5启动到Setting.Create页面,然后输入一些数据,提交后 “My_nopCommerce”数据库的Setting表中已经存储了所提交的信息。
11、在第四节 数据库启动配置中我提出不定义三关于个Resolve的方法,依然可以把前台数据提交到数据库中,在这里大家可以验证一下。
到此为止我从纵向上详细的剖析了nopCommerce_4.10应用程序是如何把前台数据提交到数据库中的。总的来说这并不容易,从8月22日起至今天,用了大致两个月的时间,才以简洁的方法定义和调用逻辑,并以nopCommerce_4.10开发者的思路为前提,反向构建了前台数据到数据库的纵向操作实现。至于更新详细的信息请见我所上传代码“MyNopCommerce(不删004_数据库映射、仓储及连接). (https://download.csdn.net/download/zhoujian_911/10713023)”中的“日志”与“.vsdx”文件。