ABP VNext 微服務搭建入門(3)-- 業務邏輯寫在哪里


業務邏輯可以分為領域邏輯非領域邏輯。一般來說,領域邏輯包含新增修改,由領域驅動且不易變,非領域邏輯包含查詢刪除,由數據驅動且易變

一、領域邏輯

1、領域模型

單個實體內部的領域邏輯,不進行持久化,持久化交給上層處理,如領域服務,應用服務。

public class Product : AuditedAggregateRoot<Guid>
    {
        [NotNull]
        public string Code { get; private set; }

        [NotNull]
        public string Name { get; private set; }

        public float Price { get; private set; }

        public int StockCount { get; private set; }

        public string ImageName { get; private set; }

        private Product()
        {
            //Default constructor is needed for ORMs.
        }

        internal Product(
            Guid id,
            [NotNull] string code, 
            [NotNull] string name, 
            float price = 0.0f, 
            int stockCount = 0,
            string imageName = null)
        {
            Check.NotNullOrWhiteSpace(code, nameof(code));

            if (code.Length >= ProductConsts.MaxCodeLength)
            {
                throw new ArgumentException($"Product code can not be longer than {ProductConsts.MaxCodeLength}");
            }

            Id = id;
            Code = code;
            SetName(Check.NotNullOrWhiteSpace(name, nameof(name)));
            SetPrice(price);
            SetImageName(imageName);
            SetStockCountInternal(stockCount, triggerEvent: false);
        }

        public Product SetName([NotNull] string name)
        {
            Check.NotNullOrWhiteSpace(name, nameof(name));

            if (name.Length >= ProductConsts.MaxNameLength)
            {
                throw new ArgumentException($"Product name can not be longer than {ProductConsts.MaxNameLength}");
            }

            Name = name;
            return this;
        }
          ...
      }

2、領域服務

涉及一個或多個完整實體的領域邏輯。實現 DomainService

public class ProductManager : DomainService
{
    private readonly IRepository<Product, Guid> _productRepository;

    public ProductManager(IRepository<Product, Guid> productRepository)
    {
        _productRepository = productRepository;
    }

    public async Task<Product> CreateAsync(
        [NotNull] string code,
        [NotNull] string name,
        float price = 0.0f,
        int stockCount = 0)
    {
        var existingProduct = 
            await _productRepository.FirstOrDefaultAsync(p => p.Code == code);
            
        if (existingProduct != null)
        {
            throw new ProductCodeAlreadyExistsException(code);
        }

        return await _productRepository.InsertAsync(
            new Product(
                GuidGenerator.Create(),
                code,
                name,
                price,
                stockCount
            )
        );
    }
}

3、領域事件

通過事件的發布訂閱來處理領域邏輯,對復雜的流程業務進行解耦,實現事務的最終一致性。領域事件可以分為本地事件和分布式事件。

public class Product : AuditedAggregateRoot<Guid>
    {
        ...

        public Product SetStockCount(int stockCount)
        {
            return SetStockCountInternal(stockCount);
        }

        private Product SetStockCountInternal(int stockCount, bool triggerEvent = true)
        {
            if (StockCount < 0)
            {
                throw new ArgumentException($"{nameof(stockCount)} can not be less than 0!");
            }

            if (StockCount == stockCount)
            {
                return this;
            }

            if (triggerEvent)
            {
                AddDistributedEvent(
                    new ProductStockCountChangedEto(
                        Id,
                        StockCount,
                        stockCount
                    )
                );
            }

            StockCount = stockCount;
            return this;
        }
     }

二、非領域邏輯

倉儲

倉儲用於保存和獲取聚合對象。倉儲分為兩種,一種是基於集合的,一種是基於持久化的。Abp 的 IRespository 實現了常用的CRUD方法。
如果不夠用(極少情況),可以自定義倉儲實現IRespository。所有不含業務邏輯的CRUD都寫在這里。代碼實現寫在基礎架構層,接口定義在Domian層。

應用服務

負責調用領域邏輯增改和處理非領域邏輯的查刪,並持久化。實現 ApplicationService。

[Authorize(ProductManagementPermissions.Products.Default)]
public class ProductAppService : ApplicationService, IProductAppService
{
	private readonly ProductManager _productManager;
	private readonly IRepository<Product, Guid> _productRepository;

	public ProductAppService(ProductManager productManager, IRepository<Product, Guid> productRepository)
	{
		_productManager = productManager;
		_productRepository = productRepository;
	}

	public async Task<PagedResultDto<ProductDto>> GetListPagedAsync(PagedAndSortedResultRequestDto input)
	{
		await NormalizeMaxResultCountAsync(input);

		var products = await _productRepository
			.OrderBy(input.Sorting ?? "Name")
			.Skip(input.SkipCount)
			.Take(input.MaxResultCount)
			.ToListAsync();

		var totalCount = await _productRepository.GetCountAsync();

		var dtos = ObjectMapper.Map<List<Product>, List<ProductDto>>(products);

		return new PagedResultDto<ProductDto>(totalCount, dtos);
	}

	public async Task<ListResultDto<ProductDto>> GetListAsync() //TODO: Why there are two GetList. GetListPagedAsync would be enough (rename it to GetList)!
	{
		var products = await _productRepository.GetListAsync();

		var productList =  ObjectMapper.Map<List<Product>, List<ProductDto>>(products);

		return new ListResultDto<ProductDto>(productList);
	}

	public async Task<ProductDto> GetAsync(Guid id)
	{
		var product = await _productRepository.GetAsync(id);

		return ObjectMapper.Map<Product, ProductDto>(product);
	}

	[Authorize(ProductManagementPermissions.Products.Create)]
	public async Task<ProductDto> CreateAsync(CreateProductDto input)
	{
		var product = await _productManager.CreateAsync(
			input.Code,
			input.Name,
			input.Price,
			input.StockCount,
			input.ImageName
		);

		return ObjectMapper.Map<Product, ProductDto>(product);
	}

	[Authorize(ProductManagementPermissions.Products.Update)]
	public async Task<ProductDto> UpdateAsync(Guid id, UpdateProductDto input)
	{
		var product = await _productRepository.GetAsync(id);

		product.SetName(input.Name);
		product.SetPrice(input.Price);
		product.SetStockCount(input.StockCount);
		product.SetImageName(input.ImageName);

		return ObjectMapper.Map<Product, ProductDto>(product);
	}

	[Authorize(ProductManagementPermissions.Products.Delete)]
	public async Task DeleteAsync(Guid id)
	{
		await _productRepository.DeleteAsync(id);
	}

	private async Task NormalizeMaxResultCountAsync(PagedAndSortedResultRequestDto input)
	{
		var maxPageSize = (await SettingProvider.GetOrNullAsync(ProductManagementSettings.MaxPageSize))?.To<int>();
		if (maxPageSize.HasValue && input.MaxResultCount > maxPageSize.Value)
		{
			input.MaxResultCount = maxPageSize.Value;
		}
	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM