Try fast search NHibernate

07 February 2010

NHibernate issues: The quality is not achieved by chance

BugReports

I’m not the only one, I’m feeling a little bit better.

Would be better if many of our users understands that if we asking tests is not to annoying you, but because

The quality is not achieved by chance!

06 February 2010

Sharp Tests Ex RC

Sharp Tests Ex 1.0.0 was released today. You can download it from here.

There are few issues fixed:

* Executing two times the Expression cause unexpected not failing Assertion
* Add EqualTo to boolean constraint
* intValue.Should().BE(5) as short-cut instead EqualTo

The SharpTestsEx’s API is now considered stable, how much ? we will use SharpTestsEx for NHibernate-Core tests as we are using it in NHibernate.Validator.

Happy testing!!

04 February 2010

ConfORM: NHibernate un-Mapping

The “Map NHibernate using your API” post was matter a little discussion in the NHibernate’s development-list. The feedback was not so big but enough to begin the work in NHibernate trunk. Before start the implementation inside NHibernate I wanted to understand how should look some classes with the responsibility to create the mapping. The API proposed in the previous post is pretty good but the underlining implementation is too much strongly typed to be reused in a non-strongly-typed task.

I was thinking in begin a new proof-of-concept but two weeks ago somebody have asked me to write ~400 mappings of a domain created from various XSD… perhaps to join business requirement and Open-Source pleasure is not so hard.

Few months ago, after a discussion in NHibernate’s dev-list, I have reserved a project name in Google-Code… and… with “Nessun Dorma” here we go.

The ORM (“Nessun dorma! Tu pure, o, Principessa, nella tua fredda stanza”)

A domain, and even less a single class, can’t self explain its persistent representation. To be short, and avoid the discussion over a dream (ORuM), I need a way to define :

  • which is the strategy to represent a class hierarchy
  • which is the relation between classes
  • how manage cascade-actions (read it as: which are aggregate-root)

The result are these methods:

void TablePerClassHierarchy<TBaseEntity>();
void TablePerClass<TBaseEntity>();
void TablePerConcreteClass<TBaseEntity>();

void ManyToOne<TLeftEntity, TRigthEntity>();
void OneToOne<TLeftEntity, TRigthEntity>();
void ManyToMany<TLeftEntity, TRigthEntity>();

void Cascade<TFromEntity, TToEntity>(Cascade cascadeOptions);

Perhaps, some relations can be self discovered watching the domain but it isn’t so clear always.

The mapping to NHibernate (“ma il mio mistero √© chiuso in me”)

The exigency of a mapping is, may be, more complicated… bah?!? “may be”… it is more complicated especially if you want use some ORM feature. Between the way I’m using to describe my domain-persistent-representation and the mapping needs I’m needing a contract.

public interface IDomainInspector
{
bool IsRootEntity(Type type);
bool IsComponent(Type type);
bool IsComplex(Type type);
bool IsEntity(Type type);

bool IsTablePerClass(Type type);
bool IsTablePerClassHierarchy(Type type);
bool IsTablePerConcreteClass(Type type);

bool IsOneToOne(Type from, Type to);
bool IsManyToOne(Type from, Type to);
bool IsManyToMany(Type role1, Type role2);
bool IsOneToMany(Type from, Type to);
bool IsHeterogeneousAssociations(MemberInfo member);
Cascade ApplyCascade(Type from, Type to);

bool IsPersistentId(MemberInfo member);
IPersistentIdStrategy GetPersistentIdStrategy(MemberInfo member);

bool IsPersistentProperty(MemberInfo role);
IDbColumnSpecification[] GetPersistentSpecification(MemberInfo role);

What happen if any mapping task will be based on this contract ? Which can be the way you can use to describe your domain ?

If I can write all mappings to NHibernate discovering anything needed basing in this contract your domain-descriptor can be API, DSL, Attributes, classes generated for EntityFramework (Ups!!! I should not say).

The Example (“Tramontate stelle! All’alba vincer√≥!”)

The domain is the same of the previous post where I have used an API to map each element:


DomainDiagram

The difference is that with ConfORM the mapping is this:

var orm = new ObjectRelationalMapper();

orm.TablePerClass<Animal>();
orm.TablePerClass<User>();
orm.TablePerClass<StateProvince>();
orm.TablePerClassHierarchy<Zoo>();

orm.ManyToMany<Human, Human>();
orm.OneToOne<User, Human>();

orm.PoidStrategies.Add(new NativePoidPattern());

Who wrote the mapping ?

ConfOrm does not generate XML mappings but you can easy create XMLs to check how ConfOrm work.

The code to see the XML is available in this example.

For the above mapping the XML is:

<hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
namespace="ConfOrmExample.Domain"
assembly="ConfOrmExample"
xmlns="urn:nhibernate-mapping-2.2">
<
class name="User">
<
id name="Id" type="Int64">
<
generator class="native" />
</
id>
<
property name="UserName" />
<
one-to-one name="Human" />
<
list name="Permissions">
<
key column="user_key" />
<
list-index />
<
element type="String" />
</
list>
</
class>
<
class name="Animal">
<
id name="Id" type="Int64">
<
generator class="native" />
</
id>
<
property name="BodyWeight" />
<
set name="Offspring" inverse="true" cascade="all,delete-orphan">
<
key column="Mother" />
<
one-to-many class="Animal" />
</
set>
<
many-to-one name="Mother" cascade="all" />
<
many-to-one name="Father" cascade="all" />
<
property name="Description" />
<
many-to-one name="Zoo" />
<
property name="SerialNumber" />
</
class>
<
class name="StateProvince">
<
id name="Id" type="Int64">
<
generator class="native" />
</
id>
<
property name="Name" />
<
property name="IsoCode" />
</
class>
<
class name="Zoo">
<
id name="Id" type="Int64">
<
generator class="native" />
</
id>
<
discriminator />
<
property name="Name" />
<
property name="Classification" />
<
map name="Animals" inverse="true">
<
key column="Zoo" />
<
map-key type="String" />
<
one-to-many class="Animal" />
</
map>
<
map name="Mammals" inverse="true">
<
key column="Zoo" />
<
map-key type="String" />
<
one-to-many class="Mammal" />
</
map>
<
component class="Address" name="Address">
<
property name="Street" />
<
property name="City" />
<
property name="PostalCode" />
<
property name="Country" />
<
many-to-one name="StateProvince" />
</
component>
</
class>
<
joined-subclass name="Mammal" extends="Animal">
<
key column="animal_key" />
<
property name="Pregnant" />
<
property name="Birthdate" />
</
joined-subclass>
<
joined-subclass name="DomesticAnimal" extends="Mammal">
<
key column="mammal_key" />
<
many-to-one name="Owner" cascade="all" />
</
joined-subclass>
<
joined-subclass name="Cat" extends="DomesticAnimal">
<
key column="domesticanimal_key" />
</
joined-subclass>
<
joined-subclass name="Dog" extends="DomesticAnimal">
<
key column="domesticanimal_key" />
</
joined-subclass>
<
joined-subclass name="Reptile" extends="Animal">
<
key column="animal_key" />
<
property name="BodyTemperature" />
</
joined-subclass>
<
joined-subclass name="Lizard" extends="Reptile">
<
key column="reptile_key" />
</
joined-subclass>
<
subclass name="PettingZoo" extends="Zoo" />
<
joined-subclass name="Human" extends="Mammal">
<
key column="mammal_key" />
<
component class="Name" name="Name">
<
property name="First" />
<
property name="Initial" />
<
property name="Last" />
</
component>
<
property name="NickName" />
<
bag name="Friends" cascade="all,delete-orphan">
<
key column="human_key" />
<
many-to-many class="Human" />
</
bag>
<
bag name="Pets" inverse="true" cascade="all,delete-orphan">
<
key column="Owner" />
<
one-to-many class="DomesticAnimal" />
</
bag>
<
map name="Family" cascade="all,delete-orphan">
<
key column="human_key" />
<
map-key type="String" />
<
many-to-many class="Human" />
</
map>
<
property name="Height" />
<
property name="BigIntegerValue" />
<
property name="BigDecimalValue" />
<
property name="IntValue" />
<
property name="FloatValue" />
<
set name="NickNames">
<
key column="human_key" />
<
element type="String" />
</
set>
<
map name="Addresses">
<
key column="human_key" />
<
map-key type="String" />
<
composite-element class="Address">
<
property name="Street" />
<
property name="City" />
<
property name="PostalCode" />
<
property name="Country" />
<
many-to-one name="StateProvince" />
</
composite-element>
</
map>
</
joined-subclass>
</
hibernate-mapping>

Who wrote the mapping ?

Where is the code

ConfOrm is open source under LGPL and is hosted in Google-Code (check http://code.google.com/p/codeconform/).