Jekas
Jekas

Reputation: 578

NHibernate: Mapping class with generic enum property

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

Answers (1)

Enrico Campidoglio
Enrico Campidoglio

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

Related Questions