mercredi 28 septembre 2022

How to organize the validation, so as not to violate the DDD principles?

I have decided to use 'Execute / CanExecute pattern' for validation of my entities. Also, I want to move my validation values (length of string, messages, etc) to XML file, but I am not sure that XmlReader logic in the Domain layer is an appropriate solution for it. (New to DDD.)

Where would you place the logic for reading an xml file according to DDD? Perhaps you can suggest another way to store validation data?

For example my Item class:

public class Item : Entity, IAggregateRoot
{
    public string IdentityGuid { get; private set; }

    public string Name { get; private set; }

    public string Description { get; private set; }

    public decimal Price { get; private set; }

    public string PictureFileName { get; private set; }

    public string PictureUri { get; private set; }

    public string CatalogTypeId { get; private set; }

    public CatalogType CatalogType { get; private set; }

    public string BrandId { get; private set; }

    public Brand Brand { get; private set; }

    // Quantity in stock
    public int AvailableStock { get; private set; }

    // Available stock at which we should reorder
    public int RestockThreshold { get; private set; }


    // Maximum number of units that can be in-stock at any time (due to physicial/logistical constraints in warehouses)
    public int MaxStockThreshold { get; private set; }

    /// <summary>
    /// True if item is on reorder
    /// </summary>
    public bool OnReorder { get; private set; }

    public Item(
        string name,
        string description,
        decimal price,
        string pictureFileName,
        string pictureUri,
        string catalogTypeId,
        CatalogType catalogType,
        string brandId,
        Brand brand,
        int availableStock,
        int restockThreshold,
        int maxStockThreshold,
        bool onReorder)
    {
        if (CanCreateItem(name, description, price, pictureFileName,
            pictureUri, catalogTypeId, catalogType, brandId, brand,
            availableStock, restockThreshold, maxStockThreshold).Any())
        {
            throw new CatalogDomainException($"Unable to create object {typeof(Item)} data is invalid.");
        }

        Name = name;
        Description = description;
        Price = price;
        PictureFileName = pictureFileName;
        PictureUri = pictureUri;
        CatalogTypeId = catalogTypeId;
        CatalogType = catalogType;
        BrandId = brandId;
        Brand = brand;
        AvailableStock = availableStock;
        MaxStockThreshold = maxStockThreshold;
        OnReorder = onReorder;
    }

    /// <summary>
    /// Validation for Creation of Item. Execute / CanExecute pattern
    /// <param name="name"></param>
    /// <param name="description"></param>
    /// <param name="price"></param>
    /// <param name="pictureFileName"></param>
    /// <param name="pictureUri"></param>
    /// <param name="catalogTypeId"></param>
    /// <param name="catalogType"></param>
    /// <param name="brandId"></param>
    /// <param name="brand"></param>
    /// <param name="availableStock"></param>
    /// <param name="restockThreshold"></param>
    /// <param name="maxStockThreshold"></param>
    /// <returns>int: Collection of string error message</returns>
    /// </summary>
    public IReadOnlyList<string> CanCreateItem(string name,
        string description,
        decimal price,
        string pictureFileName,
        string pictureUri,
        string catalogTypeId,
        CatalogType catalogType,
        string brandId,
        Brand brand,
        int availableStock,
        int restockThreshold,
        int maxStockThreshold
        )
    {
        var errors = new List<string>();

        // name
        if (string.IsNullOrEmpty(name))
            errors.Add("Name must be at least three characters long.");
        if (name.Length < 3)
            errors.Add("Name must be at least three characters long.");
        if (name.Length > 50)
            errors.Add("A name cannot be more than fifty characters long.");

        // description
        if (string.IsNullOrEmpty(description))
            errors.Add("Description must be at least fifth characters long.");
        if (name.Length < 5)
            errors.Add("Name must be at fifth three characters long.");
        if (name.Length > 1000)
            errors.Add("A name cannot be more than thousand characters long.");

        // price
        if (price < 0)
            errors.Add("Price must be greater than zero.");

        // pictureFileName
        if (string.IsNullOrEmpty(pictureFileName))
            errors.Add("PictureFileName cannot be empty.");

        // pictureUri
        if (string.IsNullOrEmpty(pictureUri))
            errors.Add("PictureUri cannot be empty.");

        // catalogTypeId
        if (string.IsNullOrEmpty(pictureUri))
            errors.Add("CatalogTypeId cannot be empty.");

        // catalogType
        if (string.IsNullOrEmpty(catalogTypeId))
            errors.Add("CatalogTypeId cannot be у.");

        // catalogType
        if (catalogType == null)
            errors.Add("CatalogType cannot be null.");

        // brandId
        if (string.IsNullOrEmpty(brandId))
            errors.Add("BrandId cannot be empty.");

        // brand
        if (brand == null)
            errors.Add("Brand cannot be null.");

        // availableStock
        if (availableStock < 0)
            errors.Add("AvailableStock must be Zero or greater.");

        // restockThreshold
        if (restockThreshold < 0)
            errors.Add("RestockThreshold must be Zero or greater.");

        // maxStockThreshold
        if (maxStockThreshold < 0)
            errors.Add("MaxStockThreshold must be Zero or greater.");

        return errors;
    }
}

My XML file with validation data. (Just for example)

<ItemValidationData>
  <ItemProperty>
    <Name>Name</Name>
    <ConstraintName>MinNameLength</ConstraintName>
    <Value>3</Value>
    <Message>Name must be at least three characters long.</Message>
  </ItemProperty>
  <ItemProperty>
    <Name>Name</Name>
    <ConstraintName>MaxNameLength</ConstraintName>
    <Value>50</Value>
    <Message>A name cannot be more than fifty characters long.</Message>
  </ItemProperty>
</ItemValidationData>

Aucun commentaire:

Enregistrer un commentaire