Ehsan Ghanbari

Experience, DotNet, Solutions

How to persist ValueObjects of DDD via Fluent Nhibernate

I'm not going to go throw the DDD concepts again in this article as I did before here, this post is just about how to persist the Value Objects of Domain Driven Design by fluent Nhibernate. first create the basic configuration for Domain Driven Design (I'm using the way that I've learned in Pro Asp.net Design Pattern Book). create an interface and name it IAggregateRoot

  1.     public interface IAggregateRoot
  2.     {
  3.     }

Then add the BusinessRule Class

  1.     public class BusinessRule
  2.     {
  3.         private string _property;
  4.         private string _rule;
  5.  
  6.         public BusinessRule(string property, string rule)
  7.         {
  8.             _rule = rule;
  9.             _property = property;
  10.         }
  11.         public string Property
  12.         {
  13.             get { return _property; }
  14.             set { _property = value; }
  15.         }
  16.         public string Rule
  17.         {
  18.             get { return _rule; }
  19.             set { _rule = value; }
  20.         }
  21.     }

Now create the EntityBase and ValueObjectBase Classes

  1.     public abstract class EntityBase<TId>
  2.     {
  3.         private readonly List<BusinessRule> _brokenRules = new List<BusinessRule>();
  4.         public virtual TId Id { get; set; }
  5.         protected abstract void Validate();
  6.         protected internal virtual IEnumerable<BusinessRule> GetBrokenRules()
  7.         {
  8.             _brokenRules.Clear();
  9.             Validate();
  10.             return _brokenRules;
  11.         }
  12.         protected void AddBrokenRule(BusinessRule businessRule)
  13.         {
  14.             _brokenRules.Add(businessRule);
  15.         }
  16.         public override bool Equals(object entity)
  17.         {
  18.             return entity != null && entity is EntityBase<TId> && this == (EntityBase<TId>)entity;
  19.         }
  20.         public override int GetHashCode()
  21.         {
  22.             return Id.GetHashCode();
  23.         }
  24.         public static bool operator ==(EntityBase<TId> entity1, EntityBase<TId> entity2)
  25.         {
  26.             if ((object)entity1 == null && (object)entity2 == null)
  27.             {
  28.                 return true;
  29.             }
  30.             if ((object)entity1 == null || (object)entity2 == null)
  31.             {
  32.                 return false;
  33.             }
  34.             if (entity1.Id.ToString() == entity2.Id.ToString())
  35.             {
  36.                 return false;
  37.             }
  38.             return false;
  39.         }
  40.         public static bool operator !=(EntityBase<TId> entity1, EntityBase<TId> entity2)
  41.         {
  42.             return (!(entity1 == entity2));
  43.         }
  44.     }

 

And then Value Object Base Class

  1.     public abstract class ValueObjectBase
  2.     {
  3.         private readonly List<BusinessRule> _brokenRules = new List<BusinessRule>();
  4.         protected ValueObjectBase() { }
  5.         protected static bool EqualOperator(ValueObjectBase left, ValueObjectBase right)
  6.         {
  7.             if (ReferenceEquals(left, null) ^ ReferenceEquals(right, null))
  8.             {
  9.                 return false;
  10.             }
  11.             return ReferenceEquals(left, null) || left.Equals(right);
  12.         }
  13.         protected abstract void Validate();
  14.  
  15.         public void ThrowExceptionIfInvalid()
  16.         {
  17.             _brokenRules.Clear();
  18.             Validate();
  19.             if (_brokenRules.Count <= 0) return;
  20.             var issues = new StringBuilder();
  21.             foreach (BusinessRule businessRule in _brokenRules)
  22.             {
  23.                 issues.AppendLine(businessRule.Rule);
  24.             }
  25.         }
  26.         protected void AddBrokenRule(BusinessRule businessRule)
  27.         {
  28.             _brokenRules.Add(businessRule);
  29.         }
  30.     }

Sorry I'm not going to talk about above configurations, but you can use them as a base configurations for DDD in every enterprise application. Now Add a class and name it Address (this is the same Value Object class that we are going to know how to persist in repository)

  1.    public class Address : ValueObjectBase
  2.     {
  3.         public Address(string city, string street, string zipCode)
  4.         {
  5.             ZipCode = zipCode;
  6.             Street = street;
  7.             City = city;
  8.         }
  9.  
  10.         public string City { get; private set; }
  11.         public string Street { get; private set; }
  12.         public string ZipCode { get; private set; }
  13.  
  14.         protected override void Validate()
  15.         {
  16.             throw new NotImplementedException();
  17.         }
  18.     }

 

In DDD we have repository for every aggregate, and having a value object without having any entity doesn't mean anything and also we have to make the properties as private set because Value Object should be immutable. now add the customer class, this class is entity and also Root of the aggregate

  1.    public class Customer : EntityBase<Guid>, IAggregateRoot
  2.     {
  3.         public string UserName { get; set; }
  4.         public string Password { get; set; }
  5.         public Address Address { get; set; }
  6.  
  7.         protected override void Validate()
  8.         {
  9.             throw new NotImplementedException();
  10.         }
  11.     }

It's time to create the CustomerMapping and the goal of this post

  1.    public class CustomerMapping : ClassMap<Customer>
  2.     {
  3.         public CustomerMapping()
  4.         {
  5.             Table("Customer");
  6.             Not.LazyLoad();
  7.             Id(c => c.Id).GeneratedBy.GuidComb();
  8.             Map(c => c.UserName).Not.Nullable();
  9.             Map(c => c.Password).Not.Nullable();
  10.             Component(c => c.Address, a =>
  11.                 {
  12.                     a.Map(x => x.City).Column("City").Not.Nullable();
  13.                     a.Map(x => x.Street).Column("Column").Not.Nullable();
  14.                     a.Map(x => x.ZipCode).Column("ZipCode").Not.Nullable();
  15.                 });
  16.         }
  17.     }

By using component of fluent Nhibernate you can easily map the value object of DDD. Notice that this mapping in Database will be a table named Customer with id, userName, Password, city, Street, ZipCode fields.

About Me

Ehsan Ghanbari

Hi! my name is Ehsan. I'm a developer, passionate technologist, and fan of clean code. I'm interested in enterprise and large-scale applications architecture and design patterns. I spend a lot of time on software architecture. Since 2008, I've been as a developer for different companies and organizations and I've been focusing on Microsoft ecosystem all the time. During the past years, Read More

Post Tags
Pending Blog Posts
using Elmah in asp.net MVC4
Using FluentSecurity in MVC
Strategic design
Factory Pattern
time out pattern in ajax
Redis as a cache server
How to use PagedList In asp.net MVC
Multiple submit buttons in asp.net MVC
Domain driven design VS model driven architecture
What's the DDD-lite?
comments powered by Disqus