Reputation: 578
I have a class defined like this:
public class StateMachineMetadata<T> where T: struct
{
public virtual int ID { get; protected set; }
public virtual T State { get; set; }
public virtual DateTime DateChanged { get; set; }
}
Where the State
property is an enum:
public enum CarState
{
Stopped = 1,
Moving = 2
}
public enum OrderState
{
Ordered = 1,
Delivered = 2
}
Can I have two types:
StateMachineMetadata<CarState>, StateMachineMetadata<OrderState>
to be persisted in one table StateMachineMetadata
using NHibernate?
=== update ===
As workaround generic part can be moved to interface:
public interface IStateMachineMetadata<T> where T: struct
{
int ID { get; }
T State { get; set; }
DateTime DateChanged { get; set; }
}
public class StateMachineMetadataBase
{
public virtual int ID { get; protected set; }
public virtual DateTime DateChanged { get; set; }
}
public class CarStateMachineMetadata
: StateMachineMetadataBase, IStateMachineMetadata<CarState>
{
public virtual CarState State { get; set; }
}
Upvotes: 3
Views: 956
Reputation: 59923
No, and here's why.
Let's assume we have two rows in the StateMachineMetadata
table:
ID | State | DateChanged
1 | 1 | 2012-02-13
2 | 1 | 2012-02-14
If the State
column is mapped both to CarState
and OrderState
, how would NHibernate determine which enum to deserialize to? One solution would be to add a discriminator column to the StateMachineMetadata
table, which tells NHibernate which type it should map a specific row to.
For example the Type
discriminator column:
ID | State | DateChanged | Type
1 | 1 | 2012-02-13 1
2 | 1 | 2012-02-14 2
tells NHibernate that the first row represents a StateMachineMetadata<CarState>
while the second is a StateMachineMetadata<OrderState>
. This is called a Table per class hierarchy mapping in NHibernate. It requires both classes to inherit from a common base class, which in your case would naturally be StateMachineMetadata<T>
.
But here's the catch: NHibernate doesn't have a way to map a class with an open generic type. The reason is that it's simply not possible.
However, NHibernate does allow you to map classes with closed generics. You just can't map them to the same table. Here's how such configuration would look like:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="MyAssembly"
namespace="MyNamespace">
<class name="StateMachineMetadata`1[MyNamespace.CarState]"
table="StateMachineMetadata_CarState">
<!-- property to column mappings -->
</class>
<class name="StateMachineMetadata`1[MyNamespace.OrderState]"
table="StateMachineMetadata_OrderState">
<!-- property to column mappings -->
</class>
</hibernate-mapping>
Upvotes: 3