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.



Fluent Nhibernate Sample Project in Asp.net MVC

Nhibernate is an ORM designed for Microsoft.Net, it's free and open source and it's a port of java mapper to Dot Net. And fluent Nhibernate is a separate version of Nhibernate which lets you write your entities according to your business instead of starting from creating tables, fluent Nhibernate is just a fluent API for mapping classes with NHibernate. what an ORM does, is persisting object In database and then retrieving when it is needed, indeed it translates the object to database and vice versa.

In Entity Framework you use DbContext or objectContext(in earlier versions) to make configuration, in this case Models or properties acts as a UnitOfWork pattern but In Nhibernate by Using ISessionFactory Models are keep in a separate in-memory database. I'm going to show a simple Nhibernate configuration in this article ,Now let's start!

create a new MVC4 project and get the latest version of Fluent Nhibernate by Nuget:

NH

Or you can go to the web site and get the latest version and reference the Fluent Nhibernate ,now create a new class named Product : 

  1.     public class Product
  2.     {
  3.         public virtual int Id { get; set; }
  4.         public virtual string Name { get; set; }
  5.         public virtual Category Category { get; set; }
  6.     }

 and then add the Category Class to your Model folder in your project :

  1.     public class Category
  2.     {
  3.         public virtual int Id { get; set; }
  4.         public virtual string Name { get; set; }
  5.     }

you should define the properties as virtual because of lazy loading(retrieving an object or so-called data from database when it's needed is lazy loading) ,now create two separate class for mapping this Model classes via Fluent Nhibernate :

  1.     public sealed class ProductMapping : ClassMap<Product>
  2.     {
  3.         public ProductMapping()
  4.         {
  5.             LazyLoad();
  6.             Table("Product");
  7.             Id(p => p.Id);
  8.             Id(p => p.Id).GeneratedBy.Identity();
  9.             Map(p => p.Name);
  10.             References(p => p.Category);
  11.         }
  12.     }
 
  1.     public sealed class CategoryMapping : ClassMap<Category>
  2.     {
  3.         public CategoryMapping()
  4.         {
  5.             LazyLoad();
  6.             Table("Category");
  7.             Id(c => c.Id);
  8.             Id(c => c.Id).GeneratedBy.Identity();
  9.             Map(c => c.Name);
  10.         }
  11.      }

Now the most important and goal of this article is about configuration class of Fluent Nhibernate, create the class with this definition

  1.     public class SessionFactory : IHttpModule
  2.     {
  3.         private static readonly ISessionFactory _SessionFactory;
  4.         static SessionFactory()
  5.         {
  6.             _SessionFactory = CreateSessionFactory();
  7.         }
  8.         public void Init(HttpApplication context)
  9.         {
  10.             context.BeginRequest += BeginRequest;
  11.             context.EndRequest += EndRequest;
  12.         }
  13.  
  14.         public void Dispose()
  15.         {
  16.         }
  17.  
  18.         public static ISession GetCurrentSession()
  19.         {
  20.             return _SessionFactory.GetCurrentSession();
  21.         }
  22.  
  23.         private static void BeginRequest(object sender, EventArgs e)
  24.         {
  25.             ISession session = _SessionFactory.OpenSession();
  26.             session.BeginTransaction();
  27.             CurrentSessionContext.Bind(session);
  28.         }
  29.  
  30.         private static void EndRequest(object sender, EventArgs e)
  31.         {
  32.             ISession session = CurrentSessionContext.Unbind(_SessionFactory);
  33.             if (session == null) return;
  34.             try
  35.             {
  36.                 session.Transaction.Commit();
  37.             }
  38.             catch (Exception)
  39.             {
  40.                 session.Transaction.Rollback();
  41.             }
  42.             finally
  43.             {
  44.                 session.Close();
  45.                 session.Dispose();
  46.             }
  47.         }
  48.  
  49.         private static ISessionFactory CreateSessionFactory()
  50.         {
  51.             return Fluently.Configure()
  52.                            .Database(MsSqlConfiguration.MsSql2008.ConnectionString(c =>    c.FromConnectionStringWithKey("DefaultConnection")))
  53.                            .Mappings(m => m.AutoMappings.Add(CreateMappings()))
  54.                            .CurrentSessionContext<WebSessionContext>()
  55.                            .BuildSessionFactory();
  56.         }
  57.  
  58.         private static AutoPersistenceModel CreateMappings()
  59.         {
  60.             return AutoMap
  61.                 .Assembly(System.Reflection.Assembly.GetCallingAssembly())
  62.                 .Where(t => t.Namespace != null && t.Namespace.EndsWith("Models"))
  63.                 .Conventions.Setup(c => c.Add(DefaultCascade.SaveUpdate()));
  64.         }
  65.     }

 

Now Open Web.Config file and set the connectionString tag :

  1. <connectionStrings>
  2.     <add name="DefaultConnection" connectionString="Server=EHSAN\EHSAN;Database=NhMvcDB;Integrated Security=True" providerName="System.Data.SqlClient" />
  3.   </connectionStrings>

Notice that NhMvcDB is my database name and DefaultConnection is my connectionString Name and EHSAN\EHSAN is my SQL server instance name!

You should create the Repository class to talk to database, to make it simple I just create the ProductRepository Class (Not a Generic class for using all entities), to do that add an Interface to your Model :

  1.     public interface IProductRepository
  2.     {
  3.         void Add(Product product);
  4.         Product Get(int id);
  5.         void Remove(Product product);
  6.         IEnumerable<Product> GetAll();
  7.         IEnumerable<Product> GetAllProductsByCategoryQuery(int categoryId);
  8.         IEnumerable<Category> GetAllCategoriesQuery();
  9.     }

And then  implement the members in ProductRepository class like this

  1.     public class ProductRepository : IProductRepository
  2.     {
  3.         private readonly ISession _session;
  4.  
  5.         public ProductRepository()
  6.         {
  7.             _session = SessionFactory.GetCurrentSession();
  8.         }
  9.         public void Add(Product product)
  10.         {
  11.             SessionFactory.GetCurrentSession().Save(product);
  12.         }
  13.  
  14.         public Product Get(int id)
  15.         {
  16.             return SessionFactory.GetCurrentSession().Get<Product>(id);
  17.         }
  18.  
  19.         public void Remove(Product product)
  20.         {
  21.             SessionFactory.GetCurrentSession().Delete(product);
  22.         }
  23.  
  24.         public IEnumerable<Product> GetAll()
  25.         {
  26.             return _session.Query<Product>();
  27.         }
  28.  
  29.         public IEnumerable<Product> GetAllProductsByCategoryQuery(int categoryId)
  30.         {
  31.             var products= _session.Query<Product>();
  32.             var productsByCategory = from c in products
  33.                                      where c.Id == categoryId
  34.                                      select c;
  35.             return productsByCategory;
  36.         }
  37.  
  38.         public IEnumerable<Category> GetAllCategoriesQuery()
  39.         {
  40.             return _session.Query<Category>();
  41.         }
  42.     }

Now create the Service interface

  1.     public interface IProductService
  2.     {
  3.         void AddProduct(Product product);
  4.         void RemoveProduct(Product productId);
  5.         Product GetProduct(int productId);
  6.         IEnumerable<Product> GetAllProducts();
  7.         IEnumerable<Product> GetAllProductsByCategory(int categoryId);
  8.         IEnumerable<Category> GetAllCategory();
  9.     }

And Service implementation :

  1.     public class ProductService : IProductService
  2.     {
  3.         private readonly IProductRepository _productRepository;
  4.         public ProductService(IProductRepository productService)
  5.         {
  6.             _productRepository = productService;
  7.         }
  8.         public void AddProduct(Product product)
  9.         {
  10.             _productRepository.Add(product);
  11.         }
  12.         public void RemoveProduct(Product productId)
  13.         {
  14.             _productRepository.Remove(productId);
  15.         }
  16.         public Product GetProduct(int productId)
  17.         {
  18.             var product = new Product { Id = productId };
  19.             return product;
  20.         }
  21.         public IEnumerable<Product> GetAllProducts()
  22.         {
  23.             var products = _productRepository.GetAll();
  24.             return products;
  25.         }
  26.         public IEnumerable<Product> GetAllProductsByCategory(int categoryId)
  27.         {
  28.             var products = _productRepository.GetAllProductsByCategoryQuery(categoryId);
  29.             return products;
  30.         }
  31.         public IEnumerable<Category> GetAllCategory()
  32.         {
  33.             var categories = _productRepository.GetAllCategoriesQuery();
  34.             return categories;
  35.         }
  36.     }
 

 and in Controllers folder create the ProductController with this definition

 

  1.     public class ProductController : Controller
  2.     {
  3.       private readonly IProductService _productService;
  4.  
  5.         public ProductController(IProductService productService)
  6.         {
  7.             _productService = productService;
  8.         }
  9.  
  10.         public ActionResult List()
  11.         {
  12.             var products = _productService.GetAllProducts();
  13.             return View(products);
  14.         }
  15.  
  16.         public ActionResult Add()
  17.         {
  18.             return View();
  19.         }
  20.  
  21.         [HttpPost]
  22.         public ActionResult Add(Product product)
  23.         {
  24.             if (ModelState.IsValid)
  25.             {
  26.                 _productService.AddProduct(product);
  27.             }
  28.             return View();
  29.         }
  30.   }

 

Which list action returns the list of products and by Add action you can add a product , about the Dependency Resolver , add Ninject by Nuget :

 

Nuget

 

Then add this configuration class to you project

  1.     public class NinjectConfig
  2.     {
  3.         private static IKernel _ninjectKernel;
  4.         public class NinjectDependencyResolver : DefaultControllerFactory
  5.         {
  6.             public NinjectDependencyResolver()
  7.             {
  8.                 _ninjectKernel = new StandardKernel();
  9.                 ConfigurDepndency();
  10.             }
  11.             protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
  12.             {
  13.                 return controllerType == null ? null : (IController)_ninjectKernel.Get(controllerType);
  14.             }
  15.         }
  16.         private static void ConfigurDepndency()
  17.         {
  18.             _ninjectKernel.Bind<IProductRepository>().To<ProductRepository>();
  19.             _ninjectKernel.Bind<IProductService>().To<ProductService>();
  20.         }
  21.     }

 

And add this line of code to your global.asax in Application_Start()

  1.  ControllerBuilder.Current.SetControllerFactory(new NinjectConfig.NinjectDependencyResolver()); 

 end!



Nhibernate vs Entity Framework

Entity framework and nhibernate are two famous ORM for developers. Both of them have been used in many projects and each of them has it's own cons and pros and common features as well. I'm gonna list some of them here. I personally like both of them and experienced in several projects. both Frameworks are used for processing relational data to domain specific objects. Both NHibernate and the Entity Framework provide the capabilities required to implement an ORM using the Model First approach.

 

How they work?

nHibernate: The ISessionFactory holds model and metadata that is tied to a particular database and to the settings that came from the Configuration object. Finally, you create instances of ISession from the ISessionFactory.

Entity Framework: the ObjectContext or DbContext  holds the configuration, model and acts as the Unit of Work, holding references to all of the known entity instances. 

 

Migrations

Entity Framework: Built-in schema migration support since version 6 and supports seeding of the initial database

NHibernate: Supports only initial schema generation

 

Code First Mapping?

Both NHibernate and Entity Framework support the Code First Mapping feature.

 

Database Support?

NHibernate: SQL Server, SQL Server Compact, SQL Server Azure, Oracle, DB2, PostgreSQL, MySQL, Firebird, SQLLite, Informix

Entity Framework: Entity famework only supports SQL Server (but by using some extensions you can use Oracle and MySQL too).

 

Caching?

Both of them support for first level cache. Nhibernate also support for second level caching.

 

References:

I tried to list the features I've worked with and for complete information you can see the following post:

https://weblogs.asp.net/ricardoperes/differences-between-nhibernate-and-entity-framework



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?