DDD实战进阶第一波(五):开发一般业务的大健康行业直销系统(实
DDD实战进阶第一波(五):开发一般业务的大健康行业直销系统(实现产品上下文领域层)
从这篇文章开始,我们根据前面的DDD理论与DDD框架的约束,正式进入直销系统案例的开发。
本篇文章主要讲产品上下文中的领域层的主要实现,先简单讲下业务方面的需求:产品SPU与产品SKU,产品SPU主要是产品的名字和相关描述,
产品SKU包括产品SPU的多个规格,每个规格有不同的价格与PV值。从我们对DDD概念的理解,产品SPU与产品SKU属于同一个聚合,产品SPU是聚合根。
产品上下文主要实现产品的上架功能,为了实现上架功能,我们首先要实现产品上下文的领域POCO模型与领域逻辑,
我们将产品的POCO模型与领域逻辑建立到一个叫Product.Domain的项目中。
产品SPU领域对象POCO代码:
publicpartialclass ProductSPU : IAggregationRoot
{
[Key]
publicGuid Id {get;set; }
publicstringCode {get;set; }
publicstringProductSPUName {get;set; }
publicstringProductSPUDes {get;set; }
publicList ProductSKUS {get;set; }
}
产品SKU领域对象POCO代码:
publicpartialclass ProductSKU : IEntity
{
public ProductSKU() { }
[Key]
publicGuid Id {get;set; }
publicstringCode {get;set; }
publicstringSpec {get;set; }
publicUnit Unit {get;set; }
publicdecimalPV {get;set; }
publicdecimalDealerPrice {get;set; }
publicbyte[] Image {get;set; }
publicGuid ProductSPUId {get;set; }
publicstringProductSPUName {get;set; }
}
从上面代码可以看到,ProductSPU从聚合根接口继承,ProductSKU从实体接口继承,ProductSPU包含了一个ProductSKU的集合(也就是引用),这就代表它们同属一个聚合,在具体使用EF Core做
持久化时,会作为一个事务统一持久化。
领域对象除了包含自身的属性,也应该包括自身的业务逻辑,产品上架的功能比较简单,业务逻辑也比较简单,主要就是如何生成整个领域对象,以及聚合根与实体业务标识符Code的生成规则。
产品SPU领域对象业务逻辑代码:
publicpartialclass ProductSPU
{
publicProductSPU CreateProductSPU(Guid id,stringspuname,stringspudesc,List productskus)
{
this.Id = id;
this.Code ="Code "+ spuname;
this.ProductSPUName = spuname;
this.ProductSKUS = productskus;
this.ProductSPUDes = spudesc;
returnthis;
}
}
产品SKU领域对象业务逻辑代码:
publicpartialclass ProductSKU
{
publicProductSKU CreateProductSKU(string productspuname,Guid productspuid,
byte[] image,decimaldealerprice,decimalpv,stringunit,string spec)
{
this.Id = Guid.NewGuid();
this.ProductSPUId = productspuid;
this.Code ="Code "+ productspuname + spec;
this.ProductSPUName = productspuname;
this.Image = image;
this.DealerPrice = dealerprice;
this.PV = pv;
switch (unit)
{
case"盒":
this.Unit = Unit.盒;
break;
case"包":
this.Unit = Unit.包;
break;
case"瓶":
this.Unit = Unit.瓶;
break;
}
this.Spec = spec;
returnthis;
}
}
我将领域对象的属性与领域对象的逻辑分到不同的cs文件中,便于不同职责人开发与管理,而且采用相同的名称空间和Partial关键字。
Product.Domain除了要实现领域逻辑之外,还要定义ProductSPU的仓储接口、通过EF Core定义产品上下文与数据库上下文之间的映射关系。
仓储接口定义:
publicinterface IProductRepository
{
voidCreateProduct(T productspu)whereT :class, IAggregationRoot;
}
从上面可以看到,这个接口其实就是定义了将ProductSPU这个聚合根持久化到数据库与的接口。
产品上下文与数据库上下文映射关系:
1.因为映射关系使用EF Core实现,未来可能被替换掉,所以先定义一个产品上下文接口:
publicinterface IProductContext
{
}
2.EF Core映射实现
publicclass ProductEFCoreContext:DbContext,IProductContext
{
publicDbSet ProductSPU {get;set; }
publicDbSet ProductSKU {get;set; }
protectedoverridevoid OnConfiguring(DbContextOptionsBuilder optionBuilder)
{
optionBuilder.UseSqlServer("数据库连接字符串");
}
}
3.使用EF Core工具生成数据库脚本并更新数据库,在生成脚本时,需要编辑项目文件,并采用EF Core Tools命令生成,这里就不细讲EF Core技术方面的内容。
到这里,我们就基本实现了产品上下文的领域层,可以看到领域层主要是领域逻辑,定义了一个仓储接口,将数据库技术解耦,当然要定义领域对象与数据库之间的映射关系,否则用例无法完成真正对领域对象的持久化。
cnblog博文地址:http://www.cnblogs.com/malaoko/
QQ讨论群:309287205
DDD实战进阶视频请关注微信公众号: