How to Dependency Injection with NHibernate and Autofac in domain layer ?

There are two ways to DI with nhibernate and Autofac in domain layer (Entities) :
1. You can use directly autofacContainerProvider.Resolve().
Pros:
- simple and quickly
Cons :
- strong coupling between IoC and Entities
- cannot create unit tests for domain layer
- don't support with different UI (Wcf, Web, ..)
2. To resolve these cons, we have implemented this solution :
In Global.asax.cs, in Application_Start add this code after builder.Build() :


var builder = new ContainerBuilder();
builder.RegisterType<SomeDependency>();
// ... continue registering dependencies...
// Once you're done registering things, set the container
// provider up with your registrations.
builder.RegisterAssemblyTypes(typeof (ProductEntity).Assembly).InstancePerDependency();
_containerProvider = new ContainerProvider(builder.Build());


Web Application :

Nhibernate.Cfg.Environment.BytecodeProvider
= new AutofacBytecodeProvider
(new ContainerProviderContainer(AutofacContainerProvider)
, new ProxyFactoryFactory()
, new DefaultCollectionTypeFactory());

WCF Application :
Nhibernate.Cfg.Environment.BytecodeProvider
= new AutofacBytecodeProvider(AutofacContainer
, new ProxyFactoryFactory()
, new DefaultCollectionTypeFactory());

In nhibernate.cfg.xml you should use this factory :
<property name="proxyfactory.factory_class">NHibernate.ByteCode.Castle.ProxyFactoryFactory
, NHibernate.ByteCode.Castle</property>

and in Entities of domain layer, you should declare the repository interfaces in constructors.

How to bulk insert data with Nhibernate Stateless Session ?

With following code we can use NHibernate in bulk data operations, an area where ORM's traditionally perform pretty badly. To deal this, we use the nhibernate StatelessSession.
"A IStatelessSession has no persistence context associated with it and does not provide many of the higher-level life cycle semantics. In particular, a stateless session does not implement a first-level cache nor interact with any second-level or query cache. It does not implement transactional write-behind or automatic dirty checking."

using (IStatelessSession statelessSession = sessionFactoryHelper.OpenStatelessSession())
{
using (ITransaction transaction = statelessSession.BeginTransaction())
{
try
{
statelessSession.Insert(objEntity);
transaction.Commit();
return objEntity;
}
catch (Exception ex)
{
transaction.Rollback();
throw ex;
}
}
}

How to Soft Delete with Nhibernate event listener ?

1. First, we need to define the domain specific interface ISoftDeletable to implement on the entities for which we need to keep a permanent record.
public interface ISoftDeletable
{
DateTime? DateDelete { set; get; }
}


2. Next, we should create the SoftDeleteEventListener class that inherit from NHibernate.Event.Default.DefaultDeleteEventListener, and simply override the DeleteEntity method.


public class SoftDeleteEventListener : DefaultDeleteEventListener
{
protected override void DeleteEntity(IEventSource session, object entity,
EntityEntry entityEntry, bool isCascadeDeleteEnabled,
IEntityPersister persister, ISet transientEntities)
{
if (entity is ISoftDeletable)
{
var e = (ISoftDeletable)entity;
e.DateDelete = DateTime.Now;

//CascadeBeforeDelete(session, persister, entity, entityEntry, transientEntities);
//CascadeAfterDelete(session, persister, entity, transientEntities);
}
else
{
base.DeleteEntity(session, entity, entityEntry, isCascadeDeleteEnabled,
persister, transientEntities);
}
}
}



3. Finally, we need to configure the listener with nhibernate :

Nhibernate.cfg.Configuration configuration = new Configuration().Configure();
configuration.SetListener(ListenerType.Delete, new SoftDeleteEventListener());
configuration.BuildSessionFactory();


4. Now, to hide a deleted data, we define a soft delete filter in mapping file for which we need to keep a permanent record :

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" ...>
<class ...>

<property name="DateDelete" column="DateDelete" type="DateTime" />
<filter name="SoftDeleteFilter"> </filter>
</class>
<filter-def name="SoftDeleteFilter" condition="DateDelete IS NULL">
</filter-def>
</hibernate-mapping>



5. and, in the application_beginrequest, you should enable soft delete filter on the nhibernate session :

nhibernateSession.EnableFilter(“SoftDeleteFilter”).Validate();

Create Multi-Language domain model (dynamic resource) with Nhibernate and database ?



1. Create a Culture Filter on one nhibernate mapping file :

 <?xml version="1.0" encoding="utf-8" ?>  
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" ...>
<class ...>
...
</class>
<filter-def name="CultureFilter">
<filter-param name="CultureCode" type="System.String" />
</filter-def>
</hibernate-mapping>


2. Declare the following tag of culture code in the mapping files related to the language table :

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping ...>
<class name="ProductTypeCulture" table="Product_Type_Culture" mutable="false">
<id name="ID" column="ProductTypeId" type="Int64" unsaved-value="0" >
<generator class="native" />
</id>
<property name="Label" column="Label" type="String" not-null="true"/>
<property name="CultureCode" column="CultureCode" type="String" not-null="true"/>
<filter name="CultureFilter" condition=":CultureCode = CultureCode"/>
</class>
</hibernate-mapping>



3. In the application_beginrequest, you should enable filter on the nhibernate session :

CultureCode = CultureInfo.CurrentCulture.TwoLetterISOLanguageName;
public string CultureCode
{
get { return CultureInfo.CurrentCulture.TwoLetterISOLanguageName; }
set
{
nhSession.EnableFilter(“CultureFilter”).SetParameter(“CultureCode”,value)
.Validate();
}
}



4. Now, the entity ProductTypeCulture should inherit the following class :

public class EntityCulture : Entity<EntityCulture>, ICloneable, IEntityCulture
{
#region Constructors
public EntityCulture() {}

public EntityCulture(string label)
{
_label = label;
}
#endregion

#region Properties
private string _label;
public virtual string CultureCode { get; set; }
public virtual string Label
{
get { return _label; }
set { _label = value; }
}
#endregion

#region ICloneable Members
public virtual object Clone()
{
var cloned = new EntityCulture {Label = Label};
return cloned;
}
#endregion

#region override
private int? _oldHashCode;
public override bool IsTransient()
{
return ID.Equals(0) || string.IsNullOrEmpty(CultureCode);
}
public virtual bool Equals(EntityCulture other)
{
if (ReferenceEquals(this, other))
return true;

if (other == null || !GetType().Equals(other.GetType()))
return false;

if (!IsTransient() && !other.IsTransient() && ID.Equals(other.ID) && CultureCode.Equals(other.CultureCode))
return true;

return IsTransient() && other.IsTransient();
}

public override bool Equals(object obj)
{
var compareTo = obj as EntityCulture;

return Equals(compareTo);
}

public override int GetHashCode()
{
if (_oldHashCode.HasValue)
return _oldHashCode.Value;

if (IsTransient())
{
_oldHashCode = base.GetHashCode();
return _oldHashCode.Value;
}

return ID.GetHashCode() + CultureCode.GetHashCode();
}

public override string ToString()
{
return GetType().FullName + "#" + ID + "-" + CultureCode;
}
#endregion
}
public interface IEntityCulture
{
string Label { get; set; }
object Clone();
}



5. Finally, the entity ProductType should inherit the following class :



public class EntityMultiLanguage<T, TCulture> : Entity<T>, IEntityMultiLanguage<TCulture> where T : class where TCulture : class, IEntityCulture
{
private IDictionary<string, TCulture> _resources;

#region IEntityMultiLanguage<TCulture> Members
public virtual string Label
{
get
{
TCulture res = GetResource();
return res != null ? res.Label : null;
}
set
{
GetOrCreateResource().Label = value;
}
}

public virtual IDictionary<string, TCulture> Resources
{
get { return _resources ?? new Dictionary<string, TCulture>(); }
set { _resources = value; }
}
#endregion

protected virtual TCulture GetDefaultResource()
{
return Resources.ContainsKey(CultureFilter.DefaultCulture.TwoLetterISOLanguageName)
? Resources[CultureFilter.DefaultCulture.TwoLetterISOLanguageName]
: null;
}

protected virtual TCulture GetOrCreateResource()
{
if (Resources.ContainsKey(CultureFilter.CultureCode))
return Resources[CultureFilter.CultureCode];

var newResource = GetResource().Clone() as TCulture;
Resources.Add(CultureFilter.CultureCode, newResource);
return newResource;
}
protected virtual TCulture GetResource()
{
return Resources.ContainsKey(CultureFilter.CultureCode)
? Resources[CultureFilter.CultureCode]
: GetDefaultResource();
}
}

Generic Entity and Value Object in DDD

In the Domain Layer of DDD architecture, it's necessary to create generic entity and value object.

Generic Entity :


public interface IEntity<t> where T : class
{
long ID { get; set; }
bool IsTransient();
bool Equals(object obj);
bool Equals(Entity<t> other);
int GetHashCode();
string ToString();
}
[Serializable]
public abstract class Entity : IEntity where T : class
{
private int? _oldHashCode;
public virtual long ID { get; set; }
public virtual bool IsTransient()
{
return ID.Equals(0);
}
public virtual bool Equals(Entity other)
{
if (ReferenceEquals(this, other))
return true;
if (other == null || !(other is T))
return false;
if (!IsTransient() && !other.IsTransient() && ID.Equals(other.ID))
return true;
return IsTransient() && other.IsTransient();
}

public override bool Equals(object obj)
{
var compareTo = obj as Entity;
return Equals(compareTo);
}
public override int GetHashCode()
{
unchecked
{
if (_oldHashCode.HasValue)
return _oldHashCode.Value;
if (IsTransient())
{
_oldHashCode = base.GetHashCode();
return _oldHashCode.Value;
}
return ID.GetHashCode();
}
}
public override string ToString()
{
return GetType().FullName + "#" + ID;
}
public static bool operator ==(Entity left, Entity right)
{
return Equals(left, right);
}

public static bool operator !=(Entity left, Entity right)
{
return !Equals(left, right);
}
}




Generic ValueObject

public interface IValueObject<t> where T : class
{
bool IsTransient();
bool Equals(ValueObject<t> other);
bool Equals(object obj);
int GetHashCode();
string ToString();
}

[Serializable]
public abstract class ValueObject<t> : IEquatable<t>, IValueObject<t> where T : class
{
private int? _oldHashCode;
public abstract bool IsTransient();
public virtual bool Equals(T other)
{
var compareTo = other as ValueObject<t>;

return Equals(compareTo);
}
public virtual bool Equals(ValueObject<t> other)
{
if (ReferenceEquals(this, other))
return true;

if (ReferenceEquals(null, other) || !GetType().Equals(other.GetType()))
return false;

if (!IsTransient() &amp;&amp; !other.IsTransient() &amp;&amp; PropertiesEquals(other))
return true;

return IsTransient() &amp;&amp; other.IsTransient();
}
public override bool Equals(object obj)
{
var compareTo = obj as ValueObject<t>;

return Equals(compareTo);
}

public override int GetHashCode()
{
unchecked
{
if (_oldHashCode.HasValue)
return _oldHashCode.Value;

if (IsTransient())
{
_oldHashCode = base.GetHashCode();
return _oldHashCode.Value;
}

return PropertiesGetHashCode();
}
}

public override string ToString()
{
return GetType().FullName;
}

protected abstract bool PropertiesEquals(ValueObject<t> obj);
protected abstract int PropertiesGetHashCode();

public static bool operator ==(ValueObject<t> left, ValueObject<t> right)
{
return Equals(left, right);
}

public static bool operator !=(ValueObject<t> left, ValueObject<t> right)
{
return !Equals(left, right);
}

public static bool IsTransient<tentity>(IEntity<tentity> entity) where TEntity : class
{
return entity == null || entity.IsTransient();
}
}

Example of Value Object :


public class Address : ValueObject<address>
{
...
public override bool IsTransient()
{
return StreetAddress == null &amp;&amp; City == null &amp;&amp; ZipCode == null;
}

protected override bool PropertiesEquals(ValueObject<address> obj)
{
Address adr = obj as Address;
if (adr != null)
{
return StreetAddress == adr.StreetAddress &amp;&amp; City == adr.City
&amp;&amp; ZipCode == adr.ZipCode;
}
return false;
}

protected override int PropertiesGetHashCode()
{
return (StreetAddress ?? string.Empty).GetHashCode() ^ (City ?? string.Empty).GetHashCode()
^ (ZipCode ?? string.Empty).GetHashCode() ;
}
}