領域驅動設計DDD實戰進階第一波(六):開發通常業務的大健康行業直銷系統(實現產品上下文倉儲與應用服務層)

前一篇文章咱們完成了產品上下文的領域層,咱們已經有了關於產品方面的簡單領域邏輯,咱們接着來實現產品上下文關於倉儲持久化與應用層的用例如何來協調領域邏輯與倉儲持久化。前端

首先你們須要明確的是,產品上下文的領域邏輯是系統的核心,它不該該依賴倉儲,而倉儲應該要依賴領域層,這樣倉儲才能夠把領域邏輯執行完後,纔可能將領域對象持久化到數據庫中,這一點與傳統的架構有本質的區別。數據庫

通常咱們會在解決方案中創建一個項目,這個項目就是包含了全部聚合的倉儲實現,具體不一樣上下文的倉儲實現,能夠在這個項目下創建不一樣的文件夾。微信

1.產品上下文倉儲實現:

public class ProductEFCoreRepository : IProductRepository
{
    private readonly DbContext context;
    public ProductEFCoreRepository(DbContext context)
    {
        this.context = context;
    }
    public void CreateProduct<T>(T productspu) where T:class,IAggregationRoot
    {
        var productdbcontext = this.context as ProductEFCoreContext;
        var productspunew = productspu as ProductSPU;
        try
        {
            productdbcontext.ProductSPU.Add(productspunew);
        }
        catch(Exception error)
        {
            throw error;
        }
    }
  
}
複製代碼

上面的代碼有幾個要注意的方面:架構

a.首先會從產品的倉儲接口作繼承,經過EFCore的機制,實現了倉儲接口的CreateProduct方法。ui

b.使用了產品上下文的EFCore數據訪問上下文ProductEFCoreContext完成了Productspu的數據庫預添加。this

c.上一個說法中,可能你們有兩個疑惑,一是爲何不使用productdbcontext標記ProductSPU爲Added狀態,而是使用.Add方法,二是爲何只是完成了添加狀態, 而再也不後續調用Commit或SaveChange方法真正持久化到數據庫中?首先,由於將來持久化要將這個聚合中的ProductSPU聚合根與ProductSKU實體做爲一個總體持久化到數據庫中,而Added狀態只能將當前聚合根做爲添加狀態,而不能同時將引用的ProductSKU對象做爲添加狀態,因此不能使用Added狀態而使用.Add方法;其次倉儲實現聚合提交時,只進行數據庫預添,是由於協調領域邏輯與倉儲的應用服務層用例可能涉及到多個聚合,因此可能要同時調用多個領域對象的業務邏輯,多個倉儲,完成後,將多聚合做爲一個總體事務作提交,因此真正的提交應該放到應用服務層更合適,而不是倉儲層。spa

2.產品上架應用服務層實現:

應用服務層實際就是完成用例,經過應用服務層調用領域邏輯,而後經過應用服務層調用倉儲,最後應用服務層作真正的提交,這樣就把職責分的很是清楚,也在領域邏輯不依賴倉儲的前提下,完成了整個用例和持久化。code

a.首先咱們在產品上下文的應用服務層項目中,創建須要添加的產品SPU與對應產品SKU的DTO對象cdn

public class AddProductSPUDTO
{
    public string SPUName { get; set; }
    public string SPUDesc { get; set; }
    public List<string> SKUSpecs { get; set; }
    public List<string> SKUUnits { get; set; }
    public List<decimal> SKUDealerPrices { get; set; }
    public List<byte[]> SKUImages { get; set; }
    public List<decimal> SKUPvs { get; set; }
}
複製代碼

b.創建一個上架產品的用例服務,協調領域邏輯與倉儲完成用例視頻

public class AddProductSPUUseCase:BaseAppSrv
{
    private readonly IRepository irepositorycontext;
    private readonly IProductRepository iproductrepository;
    public AddProductSPUUseCase(IRepository irepositorycontext,IProductRepository iproductrepository)
    {
        this.irepositorycontext = irepositorycontext;
        this.iproductrepository = iproductrepository;
    }

    public ResultEntity<bool> AddProduct(AddProductSPUDTO addproductspudto)
    {
        var productspuid = Guid.NewGuid();
        var productskus = new List<ProductSKU>();
        for(int i = 0; i < addproductspudto.SKUSpecs.Count; i++)
        {
            var productsku = new ProductSKU().CreateProductSKU(addproductspudto.SPUName,
                productspuid, addproductspudto.SKUImages[i], addproductspudto.SKUDealerPrices[i],
                addproductspudto.SKUPvs[i], addproductspudto.SKUUnits[i], addproductspudto.SKUSpecs[i]);
            productskus.Add(productsku);
        }
        var productspu = new ProductSPU().CreateProductSPU(productspuid, addproductspudto.SPUName,
            addproductspudto.SPUDesc, productskus);
        try
        {
            using (irepositorycontext)
            {
                iproductrepository.CreateProduct(productspu);
                irepositorycontext.Commit();
            }
            return GetResultEntity(true);
        }
        catch(Exception error)
        {
            throw error;
        }
    }
}
複製代碼

BaseAppSrv是你要定義的一個類,它的GetResultEntity方法功能是完成用例後後,返回接口層的數據格式,這個數據格式會進一步經過接口層返回給前端,返回的數據格式就是ResultEntity,這兩個部分你們能夠本身去實現,也能夠參考個人微信公衆號中的課程。

DDD實戰進階視頻請關注微信公衆號:MSSHCJ

相關文章
相關標籤/搜索