views:

161

answers:

5

I have a scenario that i want to add some standard properties to my entities. Meaning that i will have e.g. 1 int and 2 string properties applied to all relevant entities. I have over 100 mapping files and most but not all will be hosts to these new properties. In the classes its easy to define this; in the mappings however i've found no reference other than creating a utility or xslt and applying that (http://stackoverflow.com/questions/1529961/how-to-define-reusable-generator-elements-in-hibernate-mapping).

However i want to be able to add/modify/remove properties from this "standard" mapping.

thx for any replies

Edit1: an example of the mapping i want to add

<property name="TimeOfEdit" column="TimeOfEdit" type="DateTime" not-null="true"/>
<many-to-one name="EditedBy" column="FK_EditedBy" cascade="save-update" not-null="true" />

Edit2: I removed the accepted solution because with NH 2.1.1 XML Entities are not working (NH-1236) and NH will throw a "DTD is prohibited in this XML document"

A: 

Creating a special code generator for your specific case is your only option.

Aaron Digulla
do you mean a one-off script/utility that will manipulate the mappings i want and inject the elements?
Jaguar
I mean a utility that will take some kind of source for the information and creates the mapping files which hibernate expects. That can mean to read the existing mapping files and add/remove elements from them but I prefer a process where I have one source (for example, special comments in the source files) and which generates the whole output file. Otherwise, you'll have spurious errors if someone manipulates an output file in a way that confuses the code generator. He'll have the bug and you won't, things like that.
Aaron Digulla
+1  A: 

It depends on how these properties are implemented in your classes.

If they are all defined in a base class or interface, you could map them once in the base class or interface, and derive using union-subclass. There are some limitations. Read this chapter in the NHibernate documentation about it.

If you decide to put them together into a class, you could map them as a user type. This will be similar to a component, but you could specify some things like type names, lengths and others in the user type. You still need to specify each column name.

There is another option: you could use XML entities. This is a rather primitive feature from XML which is supported by NHibernate. Read this chapter in the NH reference documentation where it is mentioned.

Stefan Steinegger
XML Entities seems the best solution but i don't understand this statement "The disadvantage of this approach is that NHibernate does not generate SQL UNIONs when performing polymorphic queries. "Isn't the appropriate xml combined with the mapping before NH consumes the mapping?Besides that, i'm having trouble creating it, i can't seem to find a working example of XML Entities usage.
Jaguar
Finally i did make it work with xml entities, however it is quite impossible to define <property>-ies with that. The defining xml may only have a single root node and as such only <component>-s are really viable. <union-subclass>-ing wasn't feasable, an <id> element is required for the class
Jaguar
A: 

Option 1:
-Define these 3 properties in a base class

-have your entities inherit from this base

-set up 'table per class hierarchy'

Option 2:

-Define these 3 properties as a component.

-You can have the mapping for these 3 properties in one file that is reused.

UpTheCreek
unfortunately the component solution requires an extra class which is not exactly what i want. The first option is viable however i want to avoid because the subclasses of the abstract class are be defined in the abstract class's mapping file, whereas i would prefer a solution where i go to A's class mapping file, and there define (in some way) that i want inherited/injected the abstract class's properties
Jaguar
A: 

You might take a look at fluentNHibernate, It will simplify the mapping work for you. With With auto mapping you may only need an abstract base class to define these properties.

Aaron Fischer
unfortunately the standard xml mappings have already been laid out.
Jaguar
A: 

It seems that the only to do this, is to use Dynamic Mapping (http://ayende.com/Blog/archive/2008/05/01/Dynamic-Mapping-with-NHibernate.aspx)

as such since i've already defined an interface that my entities will use for the new properties (lets say IAuditable) its just a matter of running the appropriate code at the NH-session initialization

Configuration cfg = new Configuration() Mappings mappings = cfg.CreateMappings(); 
foreach (var persistentClass in mappings.Classes) 
{ 
   if (persistentClass.MappedClass is IAuditable)
   {
     ...
   }
}

and then

cfg.BuildSessionFactory();

to have it wired up and ready to be used for about 85 classes the performance impact is negligible

Jaguar