Mappings classes into entities using Domain Driven Design with NHibernate as ORM

Viewed 37

Hello I want to map class with encapsulated fields. Earlier i used EF Core to map my domain models on entities but this time i want to try something new and i choosed NHibernate as ORM. Below is my domain classes:

public class Order
{
    public virtual EntityId Id { get; }
    public virtual OrderNumber OrderNumber { get; private set; }
    public virtual DateTime Created { get; }
    public virtual string Note { get; private set; } = null;

    public virtual IEnumerable<ProductSale> Products => _products;
    private IList<ProductSale> _products = new List<ProductSale>();

    protected Order() { }

    public Order(EntityId id, OrderNumber orderNumber, DateTime created, string note = null, IEnumerable<ProductSale> products = null)
    {
        Id = id;
        ChangeOrderNumber(orderNumber);
        Created = created;

        if (products != null)
        {
            AddProducts(products);
        }

        Note = note;
    }

    public virtual void ChangeOrderNumber(string orderNumber)
    {
        OrderNumber = orderNumber;
    }

    public virtual void ChangeNote(string note)
    {
        Note = note;
    }

    public virtual void AddProducts(IEnumerable<ProductSale> products)
    {
        // some logic and operations
    }

    public virtual void AddProduct(ProductSale product)
    {
        // some logic and operations
    }

    public virtual void RemoveProduct(ProductSale product)
    {
        // some logic and operations
    }
}

public sealed class ProductSale
{
    public virtual EntityId Id { get; }
    public virtual Order Order { get; private set; } = null;
    public virtual ProductSaleState ProductSaleState { get; private set; } = ProductSaleState.New; // enum

    protected ProductSale() { }

    public ProductSale(EntityId id, ProductSaleState productSaleState, Order order)
    {
        Id = id;
        Order = order;
        ProductSaleState = productSaleState;
    }

    public virtual void AddOrder(Order order)
    {
        // logic
    }

    public virtual void RemoveOrder()
    {
        // logic
    }
}

My value objects:

public class EntityId : IEquatable<EntityId>
{
    public virtual Guid Value { get; protected set; }

    protected EntityId() { }

    public EntityId(Guid value)
    {
        // validation

        Value = value;
    }

    public static EntityId Create() => new(Guid.NewGuid());

    public override bool Equals(object obj)
    {
        return Equals(obj as EntityId);
    }

    public bool Equals(EntityId other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return Value == other.Value;
    }

    public override int GetHashCode()
    {
        return GetEqualityComponents()
                .Select(x => x != null ? x.GetHashCode() : 0)
                .Aggregate((x, y) => x ^ y);
    }

    private IEnumerable<object> GetEqualityComponents()
    {
        yield return Value;
    }
}

public sealed class OrderNumber : IEquatable<OrderNumber>
{
    public virtual string Value { get; protected set; }

    public OrderNumber(string productName)
    {
        ValidProductName(productName);
        Value = productName;
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as OrderNumber);
    }

    public bool Equals(OrderNumber other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return Value == other.Value;
    }

    public override int GetHashCode()
    {
        return GetEqualityComponents()
                .Select(x => x != null ? x.GetHashCode() : 0)
                .Aggregate((x, y) => x ^ y);
    }

    private IEnumerable<object> GetEqualityComponents()
    {
        yield return Value;
    }

    private static void ValidProductName(string productName)
    {
        // validation
    }
}

My mappings:

public sealed class OrderConfiguration : ClassMapping<Order>
{
    public AdditionConfiguration()
    {
        Table("Orders");
        ComponentAsId(a => a.Id, map =>
        {
            map.Access(Accessor.ReadOnly);
            map.Property(id => id.Value, prop =>
            {
                prop.Access(Accessor.ReadOnly);
                prop.Column(nameof(Order.Id));
            });
        });
        Component(a => a.OrderNumber, map =>
        {
            map.Property(ad => ad.Value, prop => 
            {
                prop.Access(Accessor.ReadOnly);
                prop.Column(nameof(Order.OrderNumber));
            });
        });
        Property(a => a.Created, prop=> {
            prop.Access(Accessor.ReadOnly);
            prop.Column(nameof(Order.Created));
        });
        Property(a => a.Note, map => map.Column(nameof(Order.Note)));
        Bag(o => o.ProductSales, map =>
        {
            map.Table("ProductSales");
            map.Key(k => k.Column(col => col.Name("OrderId")));
        }, map => map.OneToMany());
    }
}

public class ProductSaleConfiguration : ClassMapping<ProductSale>
{
    public ProductSaleConfiguration()
    {
        Table("ProductSales");
        ComponentAsId(a => a.Id, map =>
        {
            map.Access(Accessor.ReadOnly);
            map.Property(id => id.Value, prop =>
            {
                prop.Access(Accessor.ReadOnly);
                prop.Column(nameof(ProductSale.Id));
            });
        });
        Property(p => p.ProductSaleState, map => {
            map.Column(nameof(ProductSale.ProductSaleState));
            map.Type<EnumStringType<ProductSaleState>>();
        });
        ManyToOne(p => p.Order, map =>
        {
            map.Column("OrderId");
        });
    }
}

When I inserted object for example order, EntityId was always set as null. I havent used NHibernate as ORM so far, so I couldnt check if mappings were correct. Maybe there is something missing. I used .Net 6, SQLite database.

0 Answers
Related