Is there a way to define reusable properties to n-hibernate mappings? - nhibernate

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 (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"

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.

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

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.

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.

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

Related

Return only the Parent using nHibernate

Im pretty new to nhibernate so this may be quite straightforward but i havent found an answer on the web yet.
Lets say i have a Parent class and a Child class. The Parent Class can have many Child classes associated with it. Now when i try to load a specific Parent nhibernate also populates its Child collection for me. There are situations where I want to just return a Parent class without a Child collection.
I know i can turn on Lazy loading but that wont work as im serializing the Parent to XML. The XML serialiser cannot work with the nhibernate PersistanceBag that contains the Child collection.
So is there a way to define a Parent class, lets say ParentView which works on the same table but only contains the Parent properties and not all its children and grandchildren?
Define a class ParentView that contains the columns you need to retrieve. Make sure this class has one parameterless constructor.
ISession session = NHibernateHelper.Session;
ISQLQuery query = session.CreateSQLQuery("select Parent_ID, Name form Parent where Parent_ID = :parentID");
query.SetInt32("parentID", parentID);
IList<ParentView> parentView = query.SetResultTransformer(Transformers.AliasToBean<ParentView>()).List<ParentView>();
return parentView;
An alternative to creating a view class and associated query as suggested by sh_kamalh (which I would consider if I were you). If the problem is related to the bag mapping structure specifically then you might have a couple of easier solutions:
Option 1
Revisit the bag mapping - Maybe simple selecting a different strategy will fix the issue. I have answered a question on the different collection mappings before List vs Set vs Bag in NHibernate personally I find that I use the Set strategy a lot. To map a different strategy in Fluent NHibernate use the following as a guide in your override.
mapping.HasMany<Child>(x => x.Children).ToSet();
or
mapping.HasMany<Child>(x => x.Children).ToList();
Option 2
Not particularly related to NHibernate but if you are using the default xml serializer you might be able to tell the xml serializer to simply ignore that property and leave the bag mapping in place.
[System.Xml.Serialization.XmlIgnore]
public IEnumerable<Child> Children { get; internal set; }

NHibernate: lazy loaded properties?

NHibernate question:
Say I have a SQL table Person and it has a Picture column ( OLE Object ) . I have a class Person and it has : byte[] Picture attribute.
Is it possible to map like this ?
<property name = "Picture" column = "Picture" type = "System.Byte[]" lazy="true" />
Does the "lazy" keyword have any effect on properties or can it only be used when working with collections / bags etc?
It appears that this feature just landed in the NHibernate trunk:
http://ayende.com/Blog/archive/2010/01/27/nhibernate-new-feature-lazy-properties.aspx
I have not found any way to get this to work, but the following two ways may help you around the problem you imply:
You can map two classes for the same table, one including the byte array, the other not.
You can include a many-to-one property mapping to the same table, where the child class has the byte array included, and you then access the binary using Person.PersonPicture.Picture rather than just Person.Picture; the intermediate class can now be lazy loaded.
Neither is ideal, but they do work. Short answer - collections and many-to-one properties can be lazy loaded, straight properties not.

NHibernate: How to disable virtual for class properties?

how exactly I can use public methods (non-virtual) with NHibernate?
I have this code:
public string crewNumber
{
get
{
return this.crewNumberField;
}
set
{
this.crewNumberField = value;
}
}
Note all my classes, properties, methods and interfaces are auto-generated and I do not want to change them manually.
Above code is producing this error:
The following types may not be used as
proxies: ... method get_crewNumber
should be 'public/protected virtual'
I see that it shold be possible to use simple public only properties here:
In our example above, we've made the
properties and the constructor public
- but that's not a requirement for NHibernate - it can use public,
protected, internal, or even private
properties to persist your data.
How do I turn off this virtual by default?
It's driving me crazy. I am really tempted here to drag one data adapter in visual studio and to end this ridiculous situation once and for all ;-)
Thanks
Specify that dynamic proxies should not be used for that class, by specifying lazy=false on the class-mapping.
Like this:
<class name="MyClass" table="MyTable" lazy="false">
</class>
This means offcourse that you cannot use dynamic proxies with NHibernate.
To be more clear:
- when you retrieve an instance of your class, which is able to use dynamic proxies, you'll recieve an 'empty instance'. That is, NHibernate will not fetch the data from the DB yet. You'll get an object who'se Id will be populated, but the other properties are not. Only when you access a property, then NHibernate will load the data from the DB. That's the reason why the properties need to be virtual, because NHibernate will create a subclass of your class internally, and override the properties so that it can achieve this behaviour.
I always specify 'lazy=false' on my class-mapping, since I don't want to have virtual properties for a reason that is infrastructure-related, instead of 'domain-related'.
(Note that this has nothing to do with lazy loading of associations; it is still possible to have them lazy loaded when you do not use dynamic proxies).
Put lazy="false" at the class mapping:
<class name="MyClass" table="MY_TABLE" lazy="false">

nhibernate lazy load options

What is the difference between lazy="true" and lazy="proxy" in nhibernate?
I suspect another way of thinking about it would be this.
class Foo
{
public virtual Bar SingleBar { get; set; }
public virtual ICollection<Bar> MultiBar { get; set; }
}
lazy="proxy" applies to single objects (ie foo.SingleBar)
lazy="true" applies to collections of objects (ie foo.MultiBar)
(You can't set lazy="proxy" to a collection, nor can you set lazy="true" to a single reference. Either will cause NH to throw a XmlSchemaException which is a little cryptic to beginners.)
Operationally they do the same abstract thing: when and only when the property is accessed does NHibernate hit the database and populate the property.
There is however a slight difference in the implementation due what is needed to fetch the objects (in the single case, the reference's id (Bar) was loaded with the parent entity (Foo). In the collection case, the ids are unknown and must be found in another table)
lazy="proxy" means that NHibernate will lazily initialize instances of your class;
When NHibernate retrieves an instance of your class from the database, it will - in this case - not return a 'real' instance of your class, but it will rather give you a proxy. That is, it will return an object that is of another type, more specifically, an object that is a subclass of your class (generated by NHibernate through IL generation).
The object that you will be given, is a proxy, and the only populated property, is the Id property. As soon as you call another property on the instance, NHibernate will initialize the proxy, and retrieve all the other properties / collections (except those that are lazy loaded) from the database.
Lazy="true" is used on another level. Whereas lazy="proxy" is used on the class-level, lazy="true" is used on the collection level. It means that the collection should be lazy loaded.
The documentation reference says that the value of the proxy attribute is in:
lazy="proxy|no-proxy|false"
lazy (optional - defaults to proxy): By default, single point associations are proxied.
lazy="no-proxy" specifies that the property should be fetched lazily when the instance variable is first accessed (requires build-time bytecode instrumentation).
lazy="false" specifies that the association will always be eagerly fetched.
By default, Hibernate3 uses lazy select fetching for collections and lazy proxy fetching for single-valued associations. These defaults make sense for most associations in the majority of applications.
http://docs.jboss.org/hibernate/stable/core/reference/en/html_single/#performance-fetching-lazy

NHibernate - Changing sub-types

How do you go about changing the subtype of a row in NHibernate? For example if I have a Customer entity and a subclass of TierOneCustomer, I have a case where I need to change a Customer to a TierOneCustomer but the TierOneCustomer should have the same Id (PK) as the original Customer entity.
The mapping looks something like this:
<class name="Customer" table="SiteCustomer" discriminator-value="C">
<id name="Id" column="Id" type="Int64">
<generator class="identity" />
</id>
<discriminator column="CustomerType" />
... properties snipped ...
<subclass name="TierOneCustomer" discriminator-value="P">
... more properties ...
</subclass>
</class>
I'm using the one-table per class hierarchy model, so using plain-sql, it'd be just a matter of a sql update of the discriminator (CustomerType) and set the appropriate columns relevant for the type. I can't find the solution in NHibernate, so would appreciate any pointers.
I'm also thinking whether the model is correct considering this use-case, but before I go down that route, I want to make sure doing as described above is actually possible in the first place. If not, I'll almost certainly think about changing the model.
Short answer is yes, you can change the discriminator value for the particular row(s) using native SQL.
However, I don't think NHibernate is intended to work this way, since the discriminator is generally "invisible" to the Java layer, where its value is supposed to be set initially according to the class of the persisted object and never changed.
I recommend looking into a cleaner approach. From the standpoint of the object model, you're trying to convert a superclass object into one of its subclass types while not changing the identity of its persisted instance, and that's where the conflict is (the converted object isn't really supposed to be the same thing). Two alternative approaches are:
Create a new instance of TierOneCustomer based on the information in the original Customer object, then delete the original object. If you were relying on the Customer's Primary Key for retrieval, you'll need to take note of the new PK.
or
Change your approach so the object type (discriminator) doesn't need to change. Instead of relying on a subclass to distinguish TierOneCustomer from Customer, you can use a property that you can modify freely at any time, i.e. Customer.Tier = 1.
Here are some related discussions on the Hibernate Forums that may be of interest:
Can we update the discriminator column in Hibernate
Table-per-Class Problem: Discriminator and Property
Converting a persisted instance into a subclass
You're doing something wrong.
What you are trying to do is to change the type of an object. You can't do that in .NET or in Java. That simply doesn't make sense. An object is of exactly one concrete type, and its concrete type cannot be changed from the time the object is created until the time the object is destroyed (black magic notwithstanding). In order to accomplish what you are trying to do, but with the class hierarchy you laid out, you would have to destroy the customer object which you want to turn into a tier-one customer object, create a new tier-one customer object, and copy all the relevant properties from the customer object to the tier-one customer object. That is how you do it with objects, in object-oriented languages, with your class hierarchy.
Obviously, the class hierarchy you have isn't working for you. You don't destroy customers in real life when they become tier-one customers! So don't do it with objects either. Instead, come up with a class hierarchy that makes sense, given the scenarios you need to implement. Your use scenarios include:
A customer who previously is not tier-one status now becomes tier-one status.
That means you need a class hierarchy which can accurately capture this scenario. As a hint, you should favor composition over inheritance. That means, it may be a better idea to have a property named IsTierOne, or a property named DiscountStrategy, etc., depending on what works best.
The entire purpose of NHibernate (and Hibernate for Java) is to make the database invisible. To allow you to work with objects natively, with the database magically there behind the scenes to make your objects persistent. NHibernate will let you work with the database natively, but that's not the type of scenario which NHibernate is built for.
This is REALLY late, but may be of use to the next person looking to do something similar:
While the other answers are correct that you shouldn't change the discriminator in most cases, you can do it purely within the scope of NH (no native SQL), with some clever use of mapped properties. Here's the gist of it using FluentNH:
public enum CustomerType //not sure it's needed
{
Customer,
TierOneCustomer
}
public class Customer
{
//You should be able to use the Type name instead,
//but I know this enum-based approach works
public virtual CustomerType Type
{
get {return CustomerType.Customer;}
set {} //small code smell; setter exists, no error, but it doesn't do anything.
}
...
}
public class TierOneCustomer:Customer
{
public override CustomerType Type {get {return CustomerType.TierOneCustomer;} set{}}
...
}
public class CustomerMap:ClassMap<Customer>
{
public CustomerMap()
{
...
DiscriminateSubClassesOnColumn<string>("CustomerType");
DiscriminatorValue(CustomerType.Customer.ToString());
//here's the magic; make the discriminator updatable
//"Not.Insert()" is required to prevent the discriminator column
//showing up twice in an insert statement
Map(x => x.Type).Column("CustomerType").Update().Not.Insert();
}
}
public class TierOneCustomerMap:SubclassMap<TierOneCustomer>
{
public CustomerMap()
{
//same idea, different discriminator value
...
DiscriminatorValue(CustomerType.TierOneCustomer.ToString());
...
}
}
The end result is that the discriminator value is specified for inserts, and used to determine the instantiated type on retrieval, but then if a record of a different subtype with the same Id is saved (as if the record was cloned or un-bound from the UI to a new type), the discriminator value is updated on the existing record with that ID as an object property, so that future retrievals of that type are as the new object. The setter is required on the properties because AFAIK NHibernate can't be told that a property is read-only (and thus "write-only" to the DB); in NHibernate's world, if you write something to the DB, why wouldn't you want it back?
I used this pattern recently to allow users to change the basic type of a "tour", which is in reality a set of rules governing the scheduling of the actual "tour" (a single digital "visit" to a client's on-site equipment to ensure it all works properly). While they're all "tour schedules" and need to be collectable in lists/queues etc as such, the different types of schedules require very different data and very different processing, calling for a similar data structure as the OP has. I therefore completely understand the OP's desire to treat a TierOneCustomer in a substantially different way while minimizing the effect at the data layer, so, here ya go.
If you're doing it offline (e.g. in a DB upgrade script), just use SQL and ensure consistency yourself.
If this is something you plan will happen in while the app is running, I think your requirements are wrong, just like keeping the same pointer address for a different object is wrong.
If you save the ID and use it to access the customer again (e.g. in a URL) consider making a new field that contains a token for this that will be the business key. Since it's not the ID, it's easy to create a new entity instance and copy over the token (you'll probably need to remove the token from the old one).