Mark Allison
Mark Allison

Reputation: 7228

How to work with Enums with NHibernate?

In AccountType.cs I have:

namespace MooDB.Domain
{
    public enum AccountType {Real, Demo, Fictional};
}

In Account.cs I have:

public class Account : Entity
{        
    public virtual int Id { get; set; }
    public virtual Broker Broker { get; set; }
    public virtual string Name { get; set; }
    public virtual string NickName { get; set; }
    public virtual string AccountNumber { get; set; }
    public virtual Currency Currency { get; set; }
    public virtual AccountType AccountType { get; set; }
    public virtual bool IsActive { get; set; }
    public virtual bool IsDefault { get; set; }
}

In my Account.hbm.xml I have

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="MooDB"
                   namespace="MooDB.Domain">

  <class name="MooDB.Domain.Account,MooDB" table="accounts">
    <id name="Id" column="accountId" type="Int32" unsaved-value="0">
      <generator class="native" />
    </id>
    <version name="Version" column="version" type="integer" unsaved-value="0" />
    <many-to-one name ="Broker" column="brokerId" not-null="true" class="MooDB.Domain.Broker,MooDB" />
    <property name="Name" column="`name`" type="String" length="50" not-null="true" />
    <property name="NickName" column="nickName" type="String" length="50" not-null="true" />
    <property name="AccountNumber" column="accountNumber" type="String" length="50" not-null="true" />
    <many-to-one name ="Currency" column="currency" not-null="true" class="MooDB.Domain.Currency,MooDB" />
    <property name="AccountType" column="accountType" />
    <property name="IsActive" column="isActive" type="bool" not-null="true" />
    <property name="IsDefault" column="isDefault" type="bool" not-null="true" />
  </class>
</hibernate-mapping>

My database table looks like:

CREATE TABLE [dbo].[accounts](
    [accountId] [int] IDENTITY(1,1) NOT NULL,
    [brokerId] [int] NOT NULL,
    [name] [nvarchar](50) NOT NULL,
    [nickName] [nvarchar](50) NOT NULL,
    [accountNumber] [nvarchar](50) NOT NULL,
    [currency] [char](3) NOT NULL,
    [accountType] [varchar](10) NOT NULL,
    [isActive] [bit] NOT NULL,
    [isDefault] [bit] NOT NULL,
    [version] [int] NOT NULL,
 CONSTRAINT [PK_accounts] PRIMARY KEY CLUSTERED 
(
    [accountId] ASC
)

When I try and test a retrieval of an account, I get this error from NHibernate:

Test 'Test.RepoTest.CanGetAccountById' failed: NHibernate.Exceptions.GenericADOException : could not load an entity: [MooDB.Domain.Account#1][SQL: SELECT account0_.accountId as accountId3_0_, account0_.version as version3_0_, account0_.brokerId as brokerId3_0_, account0_.[name] as name4_3_0_, account0_.nickName as nickName3_0_, account0_.accountNumber as accountN6_3_0_, account0_.currency as currency3_0_, account0_.accountType as accountT8_3_0_, account0_.isActive as isActive3_0_, account0_.isDefault as isDefault3_0_ FROM accounts account0_ WHERE account0_.accountId=?]
  ----> System.FormatException : Input string was not in a correct format.

All I want to do is have a list of Account Types in my application for validation purposes. I don't want to have a lookup table in my DB. Any ideas what I'm doing wrong?

Upvotes: 2

Views: 8385

Answers (2)

Paul
Paul

Reputation: 36349

I think NHibernate would default to persisting an enum as an integer (since in .net enums are basically syntactic sugar over ints), unless you tell it otherwise. If you really need it to be the string then you'll need to implement an IUserType. A similar example is mapping strings to booleans and is covered here.

With enums you'd just have to change the logic in NullSafeGet and NullSafeSet to map to your enums, possibly using the Enum.Parse or TryParse methods.

Upvotes: 1

Tomasz Jaskuλa
Tomasz Jaskuλa

Reputation: 16033

On the AccountType mapping add the type attribute with the following value

NHibernate.Type.EnumStringType`1[[MooDB.Domain.AccountType, MooDB]], NHibernate

By specifying a type attribute for AccountType, we tell NHibernate to use a custom class for conversion between .NET types and the database. NHibernate includes EnumStringType<T> to override the conversion of enumeration values to database values so that the string name is stored, not the numeric value.

Upvotes: 6

Related Questions