52

Is there a way to persist an enum to the DB using NHibernate? That is have a table of both the code and the name of each value in the enum.

I want to keep the enum without an entity, but still have a foreign key (the int representation of the enum) from all other referencing entities to the enum's table.

Meidan Alon
  • 3,074
  • 7
  • 45
  • 63

5 Answers5

107

Why are you guys over complicating this? It is really simple.

The mapping looks like this:

<property name="OrganizationType"></property>

The model property looks like this:

public virtual OrganizationTypes OrganizationType { get; set; }

The Enum looks like this:

public enum OrganizationTypes
{
    NonProfit = 1,
    ForProfit = 2
}

NHibernate will automatically figure it all out. Why type more than you need????

Emad
  • 4,110
  • 5
  • 30
  • 35
  • I'm not that familiar with Hibernate so I can't understand you post. Can you explain what the "model property" is. Where is this defined? – Alex Worden Mar 11 '10 at 03:05
  • 11
    I don't understand why your answer didn't get voted up tons more. You supply the answer in clear code that is easy to understand. – Kevin Albrecht Mar 11 '10 at 23:16
  • 5
    This does not work in nHibernate 2.1 as it causes ghosting: http://stackoverflow.com/questions/3247188/nhibernate-updates-unchaged-records – brainimus Jul 19 '10 at 17:56
  • 3
    I suspect it's not a wildly popular answer because the bigger problem is persisting enums as strings. As you point out storing enums as ints is kinda trivial, but storing them as strings is a challenge... – penderi Apr 01 '11 at 13:46
  • eibrahim's answer should NOT cause ghosting because the organisation type is not being mapped to an int. – Lisa Jun 01 '11 at 07:23
  • I don't think this is really the crux of the issue -- it's 100% the right way to map an enum property. But @Meidan wants to (in addition to this) have a reference table that correlates the integer and string values, so that there can be a foreign key constraint, as well as probably the additional visibility for data reporting and the like (essentially, "mapping" an enum). – Matt Enright Nov 03 '11 at 05:33
13

You can use the enum type directly: http://web.archive.org/web/20100225131716/http://graysmatter.codivation.com/post/Justice-Grays-NHibernate-War-Stories-Dont-Use-Int-If-You-Mean-Enum.aspx. If your underlying type is a string, it should use the string representation, if it is numeric, it will just use the numeric representation.

But your question wording sounds like you're looking for something different, not quite an enum. It seems that you want a lookup table without creating a separate entity class. I don't think this can be done without creating a separate entity class though.

Garo Yeriazarian
  • 2,533
  • 18
  • 29
  • 1
    That link doesn't seem to work. This one should: http://graysmatter.codivation.com/post/Justice-Grays-NHibernate-War-Stories-Dont-Use-Int-If-You-Mean-Enum.aspx – UpTheCreek Nov 16 '09 at 17:32
6

An easy but not so beautiful solution:

Create an integer field with and set the mapping in the mapping file to the field. Create a public property that uses the integer field.

private int myField;
public virtual MyEnum MyProperty
{
   get { return (MyEnum)myField; }
   set { myField = value; }
}
Paco
  • 8,335
  • 3
  • 30
  • 41
4

I am using NHibernate 3.2, and this works great:

type="NHibernate.Type.EnumStringType`1[[enum_full_type_name, enum_assembly]], NHibernate"

Not sure when the generic EnumStringType got added, though.

Jamie
  • 141
  • 2
2

Try using a stategy pattern. Uou can then put logic into your inner classes. I use this quite alot espically when there is logic that should be contained in the "enum". For example the code below has the abstract IsReadyForSubmission() which is then implemented in each of the nested subclasses (only one shown). HTH

[Serializable]
public abstract partial class TimesheetStatus : IHasIdentity<int>
{
        public static readonly TimesheetStatus NotEntered = new NotEnteredTimesheetStatus();
        public static readonly TimesheetStatus Draft = new DraftTimesheetStatus();
        public static readonly TimesheetStatus Submitted = new SubmittedTimesheetStatus();
        //etc

        public abstract int Id { get; protected set; }
        public abstract string Description { get; protected set; }
        public abstract bool IsReadyForSubmission();

        protected class NotEnteredTimesheetStatus: TimesheetStatus
        {
            private const string DESCRIPTION = "NotEntered";
            private const int ID = 0;
            public override int Id
            {
                get { return ID; }
                protected set { if (value != ID)throw new InvalidOperationException("ID for NotEnteredTimesheetStatus must be " + ID); }
            }

             public override string Description
            {
                get { return DESCRIPTION; }
                protected set { if (value != DESCRIPTION)throw new InvalidOperationException("The description for NotEnteredTimesheetStatus must be " + DESCRIPTION); }
            }
            public override bool IsReadyForSubmission()
            {
                return false;
            }

        }
        //etc
}
RhysC
  • 1,644
  • 1
  • 15
  • 23