Try fast search NHibernate

26 October 2008

entity-name in action: Entity Abstraction

Another time I start from :

“Program to an interface and not to an implementation”

I want have the same approach, I’m using for DAOs, Models, Presenters, Validation, and so on, for my domain.

The domain:

public interface IEntity<TIdentity>: IEquatable<IEntity<TIdentity>>
{
TIdentity Id { get; }
}

public interface IAnimal : IEntity<int>
{
string Description { get; set; }
}

public interface IReptile : IAnimal
{
float BodyTemperature { get; set; }
}

public interface IHuman : IAnimal
{
string Name { get; set; }
string NickName { get; set; }
DateTime Birthdate { get; set; }
}

public interface IFamily<T> : IEntity<int> where T : IAnimal
{
T Father { get; set; }
T Mother { get; set; }
ISet<T> Childs { get; set; }
}

Because I’m going to work with interfaces I will need a sort of factory to have transient-instances of my entities. For this example I’m going to use something simple and more “general purpose”; a class resolver:

public interface IClassResolver : IDisposable
{
T Resolve<T>() where T : class;
T Resolve<T>(string service) where T : class;
}

The responsibility of the IClassResolver implementor is return an instance for a given Type where the Type is an interface (well… in general is an interface). The concrete implementation of a IClassResolver will be injected using some IoC framework but for this post I will use a simple static exposer:

public class DI
{
private static IClassResolver resolver;
private DI() {}

public static IClassResolver Resolver
{
get
{
if (resolver == null)
{
throw new InvalidOperationException("Resolver was not initialized. Use StackResolver.");
}

return resolver;
}
}

public static void StackResolver(IClassResolver dependencyResolver)
{
resolver = dependencyResolver;
}
}

As you can see nothing so complicated.

Now I have all needed to write a test for my domain:

[Test]
public void DomainAbstraction()
{
using (ISession s = sessions.OpenSession())
using (ITransaction tx = s.BeginTransaction())
{
var rf = DI.Resolver.Resolve<IReptile>();
rf.Description = "Crocodile";

var rm = DI.Resolver.Resolve<IReptile>();
rm.Description = "Crocodile";

var rc1 = DI.Resolver.Resolve<IReptile>();
rc1.Description = "Crocodile";

var rc2 = DI.Resolver.Resolve<IReptile>();
rc2.Description = "Crocodile";

var rfamily = DI.Resolver.Resolve<IFamily<IReptile>>();
rfamily.Father = rf;
rfamily.Mother = rm;
rfamily.Childs = new HashedSet<IReptile> { rc1, rc2 };

s.Save(rfamily);
tx.Commit();
}

using (ISession s = sessions.OpenSession())
using (ITransaction tx = s.BeginTransaction())
{
var hf = DI.Resolver.Resolve<IHuman>();
hf.Description = "Flinstone";
hf.Name = "Fred";

var hm = DI.Resolver.Resolve<IHuman>();
hm.Description = "Flinstone";
hm.Name = "Wilma";

var hc1 = DI.Resolver.Resolve<IHuman>();
hc1.Description = "Flinstone";
hc1.Name = "Pebbles";

var hfamily = DI.Resolver.Resolve<IFamily<IHuman>>();
hfamily.Father = hf;
hfamily.Mother = hm;
hfamily.Childs = new HashedSet<IHuman> { hc1 };

s.Save(hfamily);
tx.Commit();
}

using (ISession s = sessions.OpenSession())
using (ITransaction tx = s.BeginTransaction())
{
var hf = s.CreateQuery("from HumanFamily").List<IFamily<IHuman>>();

Assert.That(hf.Count, Is.EqualTo(1));
Assert.That(hf[0].Father.Name, Is.EqualTo("Fred"));
Assert.That(hf[0].Mother.Name, Is.EqualTo("Wilma"));
Assert.That(hf[0].Childs.Count, Is.EqualTo(1));

var rf = s.CreateQuery("from ReptilesFamily").List<IFamily<IReptile>>();

Assert.That(rf.Count, Is.EqualTo(1));
Assert.That(rf[0].Childs.Count, Is.EqualTo(2));

tx.Commit();
}

using (ISession s = sessions.OpenSession())
using (ITransaction tx = s.BeginTransaction())
{
s.Delete("from HumanFamily");
s.Delete("from ReptilesFamily");
tx.Commit();
}
}

Note: s.Save(hfamily) <<=== there isn’t a string for the entity-name; now NH are supporting it.

As you can see the users of my domain (the test in this case), are working only using interfaces; there isn’t a reference to a concrete implementation of my domain. The concrete implementation of the domain is trivial and you can see it downloading the code. The main thing you will notice, in the implementation, is the absence of the virtual modifier.

Wiring…

To wire the interface, with its concrete implementation, I want use NHibernate. The mapping is similar to the previous:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="EntityNameInAction.Abstraction.Entities.Impl"
namespace="EntityNameInAction.Abstraction.Entities.Impl.Naturalness"
default-access="backfield">

<
class name="MyAnimal" abstract="true"
proxy="EntityNameInAction.Abstraction.Entities.Naturalness.IAnimal, EntityNameInAction.Abstraction.Entities"
entity-name="Animal">
<
id name="id" access="field">
<
generator class="hilo"/>
</
id>
<
discriminator column="kind"/>
<
property name="Description"/>
</
class>

<
subclass name="MyHuman"
proxy="EntityNameInAction.Abstraction.Entities.Naturalness.IHuman, EntityNameInAction.Abstraction.Entities"
extends="Animal"
entity-name="Human">
<
property name="Name"/>
<
property name="NickName"/>
<
property name="Birthdate" type="Date"/>
</
subclass>

<
subclass name="MyReptile"
proxy="EntityNameInAction.Abstraction.Entities.Naturalness.IReptile, EntityNameInAction.Abstraction.Entities"
extends="Animal"
entity-name="Reptile">
<
property name="BodyTemperature"/>
</
subclass>

<
class name="MyFamily`1[[EntityNameInAction.Abstraction.Entities.Naturalness.IReptile, EntityNameInAction.Abstraction.Entities]]"
proxy="EntityNameInAction.Abstraction.Entities.Naturalness.IFamily`1[[EntityNameInAction.Abstraction.Entities.Naturalness.IReptile, EntityNameInAction.Abstraction.Entities]], EntityNameInAction.Abstraction.Entities"
table="Families" discriminator-value="Reptile" where="familyKind = 'Reptile'"
entity-name="ReptilesFamily">
<
id name="id" access="field">
<
generator class="hilo"/>
</
id>
<
discriminator column="familyKind"/>
<
many-to-one name="Father" cascade="all" entity-name="Reptile"/>
<
many-to-one name="Mother" cascade="all" entity-name="Reptile"/>
<
set name="Childs" generic="true" cascade="all">
<
key column="familyId" />
<
one-to-many entity-name="Reptile"/>
</
set>
</
class>

<
class name="MyFamily`1[[EntityNameInAction.Abstraction.Entities.Naturalness.IHuman, EntityNameInAction.Abstraction.Entities]]"
proxy="EntityNameInAction.Abstraction.Entities.Naturalness.IFamily`1[[EntityNameInAction.Abstraction.Entities.Naturalness.IHuman, EntityNameInAction.Abstraction.Entities]], EntityNameInAction.Abstraction.Entities"
table="Families" discriminator-value="Human" where="familyKind = 'Human'"
entity-name="HumanFamily">
<
id name="id" access="field">
<
generator class="hilo"/>
</
id>
<
discriminator column="familyKind"/>
<
many-to-one name="Father" cascade="all" entity-name="Human"/>
<
many-to-one name="Mother" cascade="all" entity-name="Human"/>
<
set name="Childs" generic="true" cascade="all">
<
key column="familyId" />
<
one-to-many entity-name="Human"/>
</
set>
</
class>
</
hibernate-mapping>

Mapping highlight


  • class/subclass name: are my concrete classes (implementors of domain)
  • proxy : is the interface (the domain); using it as proxy I can avoid virtual methods in the implementation because the underlining Dynamic-Proxy will inherit from the interface. Using interface I have many others vantages but is to long explain each (only one for example: I can cast a proxy-instance to an interface)
  • entity-name :  is the name I will use for persistence and represent another abstraction-level. For persistence stuff I can use a “conceptual-name” of the entity without take care about its representation in C#. As you can see the entity-name are playing on each association/aggregation/extends; not the concrete class nor the interface.
  • As in this post the domain is represented in two tables.

Class Resolver

In the implementation of IClassResolver I’m going to use the NHibernate’s mapping to wire the interface of the domain (ex: IHuman) to its concrete class (ex: MyHuman) trough the entity-name. Is it not clear ? ok perhaps the code will be more clear

public class NhEntityClassResolver : IClassResolver
{
private readonly Dictionary<Type, string> serviceToEntityName = new Dictionary<Type, string>();
public NhEntityClassResolver(ISessionFactoryImplementor factory)
{
if(factory == null)
{
throw new ArgumentNullException("factory");
}
Factory = factory;
InitializeTypedPersisters();
}

private void InitializeTypedPersisters()
{
foreach (var entityName in Factory.GetAllClassMetadata().Keys)
{
serviceToEntityName
.Add(Factory.GetEntityPersister(entityName)
.GetConcreteProxyClass(EntityMode.Poco), entityName);
}
}

public ISessionFactoryImplementor Factory { get; private set; }

#region Implementation of IDisposable

public void Dispose()
{
}

#endregion

#region
Implementation of IClassResolver

public T Resolve<T>() where T : class
{
string entityName;
if(serviceToEntityName.TryGetValue(typeof(T), out entityName))
{
return Resolve<T>(entityName);
}
return null;
}

public T Resolve<T>(string service) where T: class
{
return Factory.GetEntityPersister(service).Instantiate(null, EntityMode.Poco) as T;
}

#endregion
}

The ISessionFactoryImplementor is one of the interfaces implemented by the NH SessionFactory. The method Resolve<T>(string) are using the parameter service as the entity-name. The hard-work is done by the method InitializeTypedPersisters; what I’m doing there is map each interface with its entity-name… nothing more.

Conclusions

“Program to an interface and not to an implementation” is really wonderful.

Do you really have some doubt about how NHibernate implements “Persistence ignorance” ?

Code available here.

21 October 2008

The power of ORM

In the last two years we saw many developers becoming from “DataSet world” to “ORM world” (thanks to Microsoft and it’s EntityFramework).

One of the most important challenge of ORM is the abstraction of your domain (entity classes of your business) from its persistent representation (tables in the DB).

To understand how NHibernate solve the ORM challenge I want start from an existing domain. The domain of this post:

public abstract class Animal
{
public virtual int Id { get; private set; }
public virtual string Description { get; set; }
}

public class Reptile: Animal
{
public virtual float BodyTemperature { get; set; }
}

public class Human : Animal
{
public virtual string Name { get; set; }
public virtual string NickName { get; set; }
public virtual DateTime Birthdate { get; set; }
}

public class Family<T> where T: Animal
{
public virtual int Id { get; private set; }
public virtual T Father { get; set; }
public virtual T Mother { get; set; }
public virtual ISet<T> Childs { get; set; }
}

The mapping of the previous post represent the domain in five tables:


OldDomain
 

Without touch my previous domain, and my previous test, I want represent it in two tables:


NewDomain
The new mapping is:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="EntityNameInAction"
namespace="EntityNameInAction"
default-access="backfield">

<
class name="Animal" abstract="true">
<
id name="Id">
<
generator class="hilo"/>
</
id>
<
discriminator column="kind"/>
<
property name="Description"/>

<
subclass name="Reptile">
<
property name="BodyTemperature"/>
</
subclass>

<
subclass name="Human">
<
property name="Name"/>
<
property name="NickName"/>
<
property name="Birthdate" type="Date"/>
</
subclass>
</
class>

<
class name="Family`1[[Reptile]]" entity-name="ReptilesFamily"
table="Families" discriminator-value="Reptile" where="familyKind = 'Reptile'">
<
id name="Id">
<
generator class="hilo"/>
</
id>
<
discriminator column="familyKind"/>
<
many-to-one name="Father" class="Reptile" cascade="all"/>
<
many-to-one name="Mother" class="Reptile" cascade="all"/>
<
set name="Childs" generic="true" cascade="all">
<
key column="familyId"/>
<
one-to-many class="Reptile"/>
</
set>
</
class>

<
class name="Family`1[[Human]]" entity-name="HumanFamily"
table="Families" discriminator-value="Human" where="familyKind = 'Human'">
<
id name="Id">
<
generator class="hilo"/>
</
id>
<
discriminator column="familyKind"/>
<
many-to-one name="Father" class="Human" cascade="all"/>
<
many-to-one name="Mother" class="Human" cascade="all"/>
<
set name="Childs" generic="true" cascade="all">
<
key column="familyId"/>
<
one-to-many class="Human"/>
</
set>
</
class>
</
hibernate-mapping>
The difference in the Animal hierarchy mapping is trivial and well known by NH users. What is more interesting is the work to persist Family<T> classes. Because I’m using the same table (Families) I need something to discriminate the tow concrete types Family<Reptile> and Family<Human>. In this case I can’t say that Family<Reptile> is a subclass of something else (in my domain I don’t have a superclass for Family<T>) by the way I can use a simple trick. The use of <discriminator>, discriminator-value and where tags is the trick.
Goal achived by NH: same domain, same test, two different persistent representations.
Code available here.

18 October 2008

El placer de un Bug Fix

Después de tantas líneas de código escritas en NHibernate (según las estadísticas de ohloh van más de 130000 solo en el core de NH) aún encuentro placer en arreglar bugs.

El placer se incrementa cuando, rastreando un bug, me encuentro con comentarios bastante detallados en puntos críticos donde, por varios motivos, había tomado una determinada decisión sobre la implementación de una funcionalidad de Hibernate3.2. En el caso de NHibernate, que es un porting, estas cosas son las que denomino: licencias poéticas. La misma definición la uso cuando alguien toma un patrón y lo implementa como le parece.

En NH encontré y arreglé unas cuantas licencias poéticas y, despacito, despacito, me permití también tomarme mis licencias poéticas (hay veces que el TDD te lleva a eso).

Realmente es un placer cuando aparece un bug que me lleva a arreglar una licencia poĂ©tica y más aĂşn si tambiĂ©n me permite transformar un TODO en DONE… ni hablar si eso arregla dos bugs de un solo fix.

17 October 2008

How Test your mappings: the Ghostbuster

In NHibernate, when you have the FulshMode configured to AutoFlush, a session.Flush() is thrown when NH detect a dirty entity instance and you are querying an intersected QuerySpace (the QuerySpace is represented by all tables affected in a query).

Example:

    <class name="Animal">
<
id name="Id">
<
generator class="hilo"/>
</
id>
<
property name="Description"/>

<
joined-subclass name="Reptile">
<
key column="animalId"/>
<
property name="BodyTemperature"/>
</
joined-subclass>

</
class>

If you have the above domain, and you are going to query the Reptile class in a opened session with a dirty instance of Animal, a session.Flush() will be thrown.

After a session.Get<Animal>(anId) we can be pretty sure that there is no dirty entities in the session, sure ?

Don’t be so sure! The real answer is: It depend.

For example try this domain:

public enum Sex
{
Unspecified,
Male,
Female
}
public class Person
{
public virtual int Id { get; set; }
public virtual Sex Sex { get; set; }
}

with this mapping:

    <class name="Person">
<
id name="Id">
<
generator class="hilo"/>
</
id>
<
property name="Sex" type="int"/>
</
class>

In the mapping I define the property Sex of type int but in the class the type is Sex; even if you don’t receive an exception, because an int is convertible to Sex and viceversa, your persistence will have a unexpected  behavior. NH will detect a modification, of your entity, “immediately” after session.Get because it having an int in the entity snap-shot (retrieved from DB) and a Sex in the actual state. The example are showing a very simple case of “ghosts” in your application. In a big environment, with a complex domain, find “ghosts” it is not so easy.

The Ghostbusters

[TestFixtureSetUp]
public void TestFixtureSetUp()
{
XmlConfigurator.Configure();
cfg = new Configuration();
cfg.Configure();
new SchemaExport(cfg).Create(false, true);
sessions = (ISessionFactoryImplementor) cfg.BuildSessionFactory();
PopulateDb();
}

Few words about the TestFixtureSetUp:


  • if you are testing your domain persistence you can run the “ghostbuster” in each test.
  • if you are testing yours DAOs and you have an implementation of ObjectMother or TestDataBuilder you can use it in the implementation of PopulateDb() method.
  • If you don’t have tests you can leave the PopulateDb() method empty and configure NH to an existing copy of your DB.

[Test, Explicit]
public void UnexpectedUpdateDeleteOnFetch()
{
PersistingMappings(null);
}

[Test, Explicit]
public void UnexpectedUpdateDeleteOnFetchSpecific()
{
var entitiesFilter = new[]
{
"Person"
};
PersistingMappings(entitiesFilter);
}

In my experience the above two tests are needed. The first sound like “close your eyes and pray” the second allow you to analyze some specific entities.

To don’t break the test, on each unexpected DB-hit, I’ll use the power of log4net in the whole fixture.

To intercept unexpected Flush a possible, easy and quickly, way is an implementation of IInterceptor.

private class NoUpdateInterceptor : EmptyInterceptor
{
private readonly IList<string> invalidUpdates;

public NoUpdateInterceptor(IList<string> invalidUpdates)
{
this.invalidUpdates = invalidUpdates;
}

public override bool OnFlushDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, IType[] types)
{
string msg = " FlushDirty :" + entity.GetType().FullName;
log.Debug(msg);
invalidUpdates.Add(msg);
return false;
}

public override bool OnSave(object entity, object id, object[] state, string[] propertyNames, IType[] types)
{
string msg = " Save :" + entity.GetType().FullName;
log.Debug(msg);
invalidUpdates.Add(msg);
return false;
}

public override void OnDelete(object entity, object id, object[] state, string[] propertyNames, IType[] types)
{
string msg = " Delete :" + entity.GetType().FullName;
log.Debug(msg);
invalidUpdates.Add(msg);
}
}

As you can see I’m interested in : unexpected Flush of dirty instance, unexpected Saves and unexpected Deletes.

The PersistingMappings is my “driver” to test each entity. The responsibility of the method is iterate each persistent class known by the SessionFactory (or the selected in UnexpectedUpdateDeleteOnFetchSpecific methods), run the test of each entity and reports all issues found.

private void PersistingMappings(ICollection<string> entitiesFilter)
{
var invalidUpdates = new List<string>();
var nop = new NoUpdateInterceptor(invalidUpdates);

IEnumerable<string> entitiesToCheck;
if (entitiesFilter == null)
{
entitiesToCheck = cfg.ClassMappings.Select(x => x.EntityName);
}
else
{
entitiesToCheck = from persistentClass in cfg.ClassMappings
where entitiesFilter.Contains(persistentClass.EntityName)
select persistentClass.EntityName;
}

foreach (var entityName in entitiesToCheck)
{
EntityPersistenceTest(invalidUpdates, entityName, nop);
}

if (invalidUpdates.Count > 0)
{
if (logError.IsDebugEnabled)
{
logError.Debug(" ");
logError.Debug("------ INVALID UPDATES -------");
invalidUpdates.ForEach(x => logError.Debug(x));
logError.Debug("------------------------------");
}
}
Assert.AreEqual(0, invalidUpdates.Count, "Has unexpected updates.");
}

To check each persistent entity I’m using the Configuration.ClassMappings collection and extracting the EntityName from the PersistentClass. The use of EntityName don’t mean that I’m using the tag entity-name (as you can see in the mapping above).

The real “ghostbuster” is:

private void EntityPersistenceTest(ICollection<string> invalidUpdates,
string entityName, IInterceptor nop)
{
const string queryTemplate = "select e.{0} from {1} e";
string msg = "s--------" + entityName;
log.Debug(msg);

using (var s = sessions.OpenSession(nop))
using (var tx = s.BeginTransaction())
{
IList entityIds = null;
try
{
string queryString = string.Format(queryTemplate, DefaultIdName, entityName);
entityIds = s.CreateQuery(queryString).SetMaxResults(1).List();
}
catch (Exception e)
{
log.Debug("Possible METEORITE:" + e.Message);
}

if (entityIds != null)
{
if (entityIds.Count == 0 || entityIds[0] == null)
{
log.Debug("No instances");
}
else
{
if (entityIds.Count > 1)
{
msg = ">Has " + entityIds.Count + " subclasses";
log.Debug(msg);
}
object entityId = entityIds[0];
try
{
s.Get(entityName, entityId);
try
{
s.Flush();
}
catch (Exception ex)
{
string emsg = string.Format("EXCEPTION - Flushing entity [#{0}]: {1}", entityId, ex.Message);
log.Debug(emsg);
invalidUpdates.Add(emsg);
}
}
catch (Exception ex)
{
string emsg = string.Format("EXCEPTION - Getting [#{0}]: {1}", entityId, ex.Message);
invalidUpdates.Add(emsg);
log.Debug(emsg);
}
}
tx.Rollback();
}
}
msg = "e--------" + entityName;
log.Debug(msg);
}

The core of the test is:

s.Get(entityName, entityId);
s.Flush();

If I Get an entity, from a clear fresh session, without touch the state what I’m expect is that the follow Flush don’t  make absolutely nothing but… you know… perhaps there is an ugly “ghost”. Each try-catch are checking some special situation.

And now lets go to run the “ghostbuster” in your application. Code available here.


Technorati Tags: ,,

15 October 2008

entity-name in action: a strongly typed entity

The entity-name is another powerful feature of NH2.1.

Part of the implementation was introduced in NH2.0 but it was not fully implemented even if it are working under the wood (if you read the SVN-log you saw “one more step to entity-name” many and many times).

As usual I start from domain:

namespace EntityNameInAction
{
public abstract class Animal
{
public virtual int Id { get; private set; }
public virtual string Description { get; set; }
}

public class Reptile: Animal
{
public virtual float BodyTemperature { get; set; }
}

public class Human : Animal
{
public virtual string Name { get; set; }
public virtual string NickName { get; set; }
public virtual DateTime Birthdate { get; set; }
}

public class Family<T> where T: Animal
{
public virtual int Id { get; private set; }
public virtual T Father { get; set; }
public virtual T Mother { get; set; }
public virtual ISet<T> Childs { get; set; }
}
}

In the DB representation I want each Animal in a different table so I’m going to have tree different tables. At this point only one table for all “kinds” of Family is not enough basically because I can’t have a ForeignKey pointing to two tables. What I need is a table for each strongly typed Family. The way to do it, using NHibernate, is the new tag: entity-name

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="EntityNameInAction"
namespace="EntityNameInAction"
default-access="backfield">

<
class name="Animal">
<
id name="Id">
<
generator class="hilo"/>
</
id>
<
property name="Description"/>

<
joined-subclass name="Reptile">
<
key column="animalId"/>
<
property name="BodyTemperature"/>
</
joined-subclass>

<
joined-subclass name="Human">
<
key column="animalId"/>
<
property name="Name"/>
<
property name="NickName"/>
<
property name="Birthdate" type="Date"/>
</
joined-subclass>
</
class>

<
class name="Family`1[[Reptile]]" table="ReptilesFamilies"
entity-name="ReptilesFamily">
<
id name="Id">
<
generator class="hilo"/>
</
id>
<
many-to-one name="Father" class="Reptile" cascade="all"/>
<
many-to-one name="Mother" class="Reptile" cascade="all"/>
<
set name="Childs" generic="true" cascade="all">
<
key column="familyId" />
<
one-to-many class="Reptile"/>
</
set>
</
class>

<
class name="Family`1[[Human]]" table="HumanFamilies"
entity-name="HumanFamily">
<
id name="Id">
<
generator class="hilo"/>
</
id>
<
many-to-one name="Father" class="Human" cascade="all"/>
<
many-to-one name="Mother" class="Human" cascade="all"/>
<
set name="Childs" generic="true" cascade="all">
<
key column="familyId" />
<
one-to-many class="Human"/>
</
set>
</
class>

</
hibernate-mapping>

The new accessor "backfield" is another new feature but it don’t play some special role here.

As you can see I have a class implementation for all “kinds” of families but two different strongly typed persistence mappings.

Well… that’s all… ups… The test to demonstrate that it are working

[Test]
public void EntityNameDemo()
{
using (ISession s = sessions.OpenSession())
using (ITransaction tx = s.BeginTransaction())
{
var rf = new Reptile {Description = "Crocodile"};
var rm = new Reptile {Description = "Crocodile"};
var rc1 = new Reptile {Description = "Crocodile"};
var rc2 = new Reptile {Description = "Crocodile"};
var rfamily = new Family<Reptile>
{
Father = rf,
Mother = rm,
Childs = new HashedSet<Reptile> {rc1, rc2}
};
s.Save("ReptilesFamily", rfamily);
tx.Commit();
}

using (ISession s = sessions.OpenSession())
using (ITransaction tx = s.BeginTransaction())
{
var hf = new Human {Description = "Flinstone", Name = "Fred"};
var hm = new Human {Description = "Flinstone", Name = "Wilma"};
var hc1 = new Human {Description = "Flinstone", Name = "Pebbles"};
var hfamily = new Family<Human>
{
Father = hf,
Mother = hm,
Childs = new HashedSet<Human> {hc1}
};
s.Save("HumanFamily", hfamily);
tx.Commit();
}

using (ISession s = sessions.OpenSession())
using (ITransaction tx = s.BeginTransaction())
{
IList<Family<Human>> hf = s.CreateQuery("from HumanFamily").List<Family<Human>>();
Assert.That(hf.Count, Is.EqualTo(1));
Assert.That(hf[0].Father.Name, Is.EqualTo("Fred"));
Assert.That(hf[0].Mother.Name, Is.EqualTo("Wilma"));
Assert.That(hf[0].Childs.Count, Is.EqualTo(1));

IList<Family<Reptile>> rf = s.CreateQuery("from ReptilesFamily").List<Family<Reptile>>();
Assert.That(rf.Count, Is.EqualTo(1));
Assert.That(rf[0].Childs.Count, Is.EqualTo(2));

tx.Commit();
}

using (ISession s = sessions.OpenSession())
using (ITransaction tx = s.BeginTransaction())
{
s.Delete("from HumanFamily");
s.Delete("from ReptilesFamily");
tx.Commit();
}
}

As in “Less than GoF is hbm” I’m using the overload of session.Save(string, object) method; the first parameter is the entity-name I had used in the mapping, the second is the instance.

Now that’s all (code available here).

Less than GoF is hbm

In Less than “Few” is GoF I show how have a single implementation for the whole domain entities using Tuplizers.

In this post I will show another NH2.1 feature : EntityMode.Map

Suppose you want prototype the persistence of your application; you don’t want write any entity-interface nor any entity-implementation.

Suppose you want test the ORM, in the strictly meaning of the anachronism, to a legacy data base; you don’t want write any entity-interface nor any entity-implementation.

Suppose a company send you some NH-mappings-files, to optimize data access, but they don’t want send you their implementation; you don’t have the implementation.

To prototype a entirely system there are various tools; one of these is AjGenesis and it’s IDE AjGenesisStudio. AjGenesis is a CodeGenerator that use an XML source (at the end, who are using only the designer for WebForm or WPF ? ). In practices AjGenesis start from a conceptual model written in XML, and NOT from a DB model, to generate your system.

As I can do with AjGenesis (explain how it work is not a target of this post), I’m going to prototype, a little system, using an XML:

<class entity-name="ProductLine">
<
id name="Id" type="int">
<
generator class="hilo"/>
</
id>
<
property name="Description" not-null="true" length="200" type="string"/>

<
bag name="Models" cascade="all" inverse="true">
<
key column="productId"/>
<
one-to-many class="Model"/>
</
bag>

</
class>

<
class entity-name="Model">
<
id name="Id" type="int">
<
generator class="hilo"/>
</
id>

<
property name="Name" not-null="true" length="25" type="string"/>
<
property name="Description" not-null="true" length="200" type="string"/>
<
many-to-one name="ProductLine" column="productId" not-null="true" class="ProductLine"/>
</
class>

Do you are seeing something familiar ?

Yes! it is only a NHibernate2.1 mapping file.

How I can write a persistence-test without write a single class ? well… with my hands, VisualStudio, NUnit and… of course our dear NHibernate.

The configuration:

[TestFixtureSetUp]
public void TestFixtureSetUp()
{
cfg = new Configuration();
cfg.Configure();
cfg.AddResource("LessThanGoF.Prototype.ProductLine.hbm.xml", typeof (PrototypeSystemFixture).Assembly);
new SchemaExport(cfg).Create(false, true);

cfg.SetProperty("default_entity_mode", EntityModeHelper.ToString(EntityMode.Map));

sessions = (ISessionFactoryImplementor) cfg.BuildSessionFactory();
}
The line to pay attention is the set of "default_entity_mode". If you paid attention in the mappings of the previous post you sure noted entity-mode="poco". The EntityMode.Poco is the EntityMode you are using until today. The EntityMode.Map is not something new; if you are using dynamic-component, even in NH2.0, you are using part of the implementation of EntityMode.Map.

The EntityMode work together with Tuplizers. In practice the tuplizer defines the way on how transform a Property-Value to it’s persistent representation, and viceversa a Column-Value to it’s in-memory representation, and the EntityMode defines which tuplizer is in use (I have simplified the “definition” of tuplizer).

In NH2.1 each entity may have tree representations:
  • POCO
  • Dynamic-Map (aka Dictionary<PropertyName, PropertyValue>)
  • Xml (Not implemented yet)
And now the test
[Test]
public void DynamicClasses()
{
IDictionary cars;
IList models;
using (ISession s = sessions.OpenSession())
{
using (ITransaction t = s.BeginTransaction())
{
cars = new Hashtable();
cars["Description"] = "Cars";

IDictionary ferrari = new Hashtable();
ferrari["ProductLine"] = cars;
ferrari["Name"] = "Dino";
ferrari["Description"] = "Ferrari Dino.";

IDictionary lamborghini = new Hashtable();
lamborghini["ProductLine"] = cars;
lamborghini["Name"] = "Countach";
lamborghini["Description"] = "Lamborghini Countach";

models = new List<IDictionary> {ferrari, lamborghini};

cars["Models"] = models;

s.Save("ProductLine", cars);
t.Commit();
}
}

using (ISession s = sessions.OpenSession())
{
using (ITransaction t = s.BeginTransaction())
{
cars = (IDictionary) s.CreateQuery("from ProductLine pl order by pl.Description").UniqueResult();
models = (IList) cars["Models"];

Assert.That(models.Count == 2);

s.Clear();

IList list = s.CreateQuery("from Model m").List();
var model = (IDictionary) list[0];

Assert.That(((IList) ((IDictionary) model["ProductLine"])["Models"]).Contains(model));

s.Clear();
t.Commit();
}
}

using (ISession s = sessions.OpenSession())
{
using (ITransaction t = s.BeginTransaction())
{
cars = (IDictionary) s.CreateQuery("from ProductLine pl order by pl.Description").UniqueResult();
s.Delete(cars);
t.Commit();
}
}
}
Take a look to s.Save("ProductLine", cars); the first parameter is the entity-name I had used in the mapping, the second is the instance.

As you can see, I have wrote a complete persistence test without write a single entity-interface nor entity-implementation. All NH-session-API are working as expected, lazy-loading are working as expected and if you activate NHibernate.SQL logging you can see that all are working in the same way than when you have entities implemented.

End of the story!

…… wait… wait…

let me wire some thoughts…

  • The entity-name is a conceptual representation of an entity definition, I can use the entity-name to work with NH without take care if the entity is represented by an interface, a class or a class with some generic type definition…
  • With NHibernate an entity have three possible representations…
  • In this post I have a Dictionary<PropertyName, PropertyValue> to represent the state of an entity… but in the previous post I have the same representation in the DataProxy
  • Dictionary<K, V> is serializable and if I join it with a string, to hold the entityName, I may have a generic DataContract to send my entity state…

Material for some others posts.

To be continued…