Discriminator and composite identifiers

461 views
Skip to first unread message

enurija

unread,
Jul 6, 2008, 8:22:07 AM7/6/08
to nhusers
Hello,

I am having the following problems with the design of a couple of
classes mapped to a single table in a legacy database. We have a base
class with 2 derived classes. The table's primary key includes a
discriminator column and an integer id. Here's how we mapped it:

<composite-id>
<key-property name="Kind"> <column name="kind"/> </key-
property>
<key-property name="Id"> <column name="id"/> </key-property>
</composite-id>

Acording to the NHibernate Reference docs, I should set the insert
attribute of the discriminator element to "false", so:

<discriminator column="kind" insert="false"/>


This works well, but it forces to me to have a property for the
discriminator in the base class. Since I have a class derived for each
one of the possible values of the discriminator, how I can avoid the
declaration of the property? Is something like the following possible?

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" ..>

<class name="Shape" table="shape">
<composite-id>
<column name="kind"/> <------- I don't need
the property
<key-property name="Id"> <column name="id"/> </key-
property>
</composite-id>

<discriminator column="kind"/> <-------- there is no
property mapped to this column in the composite-id so no need for
insert="false"

...

<subclass name="Rectangle" discriminator-value="R" />
<subclass name="Circle" discriminator-value="C"/>
</class>

</hibernate-mapping>

Thanks

Wolfgang Trog

unread,
Jul 6, 2008, 10:16:18 AM7/6/08
to nhu...@googlegroups.com
There's no need for a "discriminator property". Specifying the discriminator
in the mapping of the base class is enough:

<discriminator column="kind" type="...." />

--
Wolfgang


enurija

unread,
Jul 6, 2008, 11:12:34 AM7/6/08
to nhusers
Actually I need it because the discriminator column is part of the
table's primary key! If don't create a property or field for my class
and don't specify it in the mapping, I get an NonUniqueObjectException
when trying to add an instance of both of the derived classes with the
same Id.


Example 1

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" ...>
<class name="Shape" table="shape">
<composite-id>
<key-property name="Kind"> <column name="kind"/> </key-
property>
<key-property name="Id"> <column name="id"/> </key-
property>
</composite-id>

<discriminator column="kind" insert="false" />

<subclass name="Rectangle" discriminator-value="R" />
<subclass name="Circle" discriminator-value="C"/>
</class>
</hibernate-mapping>

class Shape
{
private char kind;
private int id;
public virtual char Kind { get { return kind; } set { kind =
value; } }
public virtual int Id { get { return id; } set { id = value; } }
...
}

class Rectangle : Shape { ... }
class Circle : Shape { ... }


Example 2

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" ...>
<class name="Shape" table="shape">
<composite-id>
<key-property name="Id"> <column name="id"/> </key-
property>
</composite-id>

<discriminator column="kind"/>

<subclass name="Rectangle" discriminator-value="R" />
<subclass name="Circle" discriminator-value="C"/>
</class>
</hibernate-mapping>

abstract class Shape
{
private int id;
public virtual int Id { get { return id; } set { id = value; } }
...
}

class Rectangle : Shape { ... }
class Circle : Shape { ... }


The first example works fine but the Kind property is quite useless
and really weird. It is clear that the Kind property will be "R" for
rectangles and "C" for circles!

The second example doen't work. When I try the following

var rect = new Rectangle() { Id = 10 };
session.Save(rect);
var circ = new Rectangle() { Id = 10 };
session.Save(circ);

I get the NonUniqueObjectException. In my database, both (rectangles
and circles) are diferent entities that share a common ancestor and
are mapped to the same database table and even though they have the
same Id, the rectangle 10 is not the same as the circle 10 because a
discriminator column is in the primary key.

(Actually, what we have in our legacy database is a table shared for
customers and suppliers.)


Any ideas?


Thanks for your interest!

Wolfgang Trog

unread,
Jul 7, 2008, 3:03:40 AM7/7/08
to nhu...@googlegroups.com
In example 2, I suppose hibernate can't distinguish both objects because the
identity only consists of the id. That's the reason, why you get the
exception. I think example 1 is the way to go, at least I don't know of a
way around it. As you don't like the "kind" property, you can still set it
to private, so it's not visible.

--
Wolfgang

typhos

unread,
Jul 7, 2008, 2:50:13 AM7/7/08
to nhusers
Example 1 is the only way it works, I think. You need to define the
Kind property as part of the key and so you have to set it manually
(or you can implement your own pk generator which sets the Kind
property automatically). You can make the Kind property private so
nobody will take care about it.
Reply all
Reply to author
Forward
0 new messages