Enum Mapping

52 views
Skip to first unread message

Neo

unread,
Feb 20, 2009, 7:37:48 AM2/20/09
to S#arp Architecture
Did anybody have problems to map an enum to a int DB column?

I'm having a problem within my DB Tests where it says "Can't Parse 1
as EnumType".

this is the code snippet where I'm mapping my enum column:

mapping.HasMany<Contact>(person => person.Contacts)
.AsSet()
.WithTableName("Contact")
.WithKeyColumn("Id")
.Component(ct =>
{
ct.Map(c => c.Type, "ContactType").Not.Nullable
().CustomTypeIs(typeof(ContactType));
ct.Map(c => c.Description,
"Description").Not.Nullable();
});

Am I doing anything wrong?

Simone Busoli

unread,
Feb 20, 2009, 7:46:12 AM2/20/09
to sharp-arc...@googlegroups.com
Neo, there are a zillion blog posts about how to map enums with NHibernate, why don't you try that first?

Billy

unread,
Feb 20, 2009, 8:24:54 AM2/20/09
to S#arp Architecture
Neo,

If you're storing the enum values in the Contact table as ints with a
foreign key to a reference table, which I see as an ideal way to do so
in a normalized way, then you'd simply change your map as follows:

ct.Map(x => x.Type, "ContactType").Not.Nullable
().CustomTypeIs(typeof(int));

Note that it gets mapped as a type of int, not the enum type itself.

You can get some pretty powerful behavior for enum mappings. For
instance, the following example illustrates that the parent object has
a many to many relationship with an enum value stored within a many-to-
many table. Note that the many-to-many stores the id to the parent as
well as a normalized id to the enum value which is stored in a
reference table:

public void Override(AutoMap<Notification> mapping) {
mapping.HasMany<CoreEnums.ChannelType>(x => x.Channels)
.WithTableName("Notification_Channels")
.WithKeyColumn("NotificationFk")
.AsElement("ChannelTypeFk")
.AsBag();
}

As long as you properly normalize the database and store the enum
values as ints (with foreign keys to a reference table) instead of
strings, it's very easy to push/pull the info with NHibernate
mappings.

Let me know if this doesn't assist.

Thanks,
Billy


On Feb 20, 5:46 am, Simone Busoli <simone.bus...@gmail.com> wrote:
> Neo, there are a zillion blog posts about how to map enums with NHibernate,
> why don't you try that first?http://www.google.com/search?q=nhibernate+enum

Neo

unread,
Feb 20, 2009, 8:51:32 AM2/20/09
to S#arp Architecture
Billy, I've tried many solutions and none seens to work...

I think there's something wrong because the error is the same
even changing the mapping.

I changed to CustomTypeIs(typeof(int)) and the error says:
Can't Parse 1 as ContactType

Shouldn't it say Can't Parse 1 as int (just an example, I know the
error have no sense)? O_O
Looks like it's ignoring my mapping. Maybe it's related with the
AutoMapping. Anyway, I said
within the auto mapper that I don't want it to auto map my Contact
class.

Another thing about your suggestion. I read in a post that using enum
type as int is a
terrible performance issue and shouldn't be used. Is it right?

Take a look at this:

http://graysmatter.codivation.com/JusticeGraysNHibernateWarStoriesDontUseIntIfYouMeanEnum.aspx

RoyWagner

unread,
Feb 20, 2009, 9:14:17 AM2/20/09
to S#arp Architecture
Hey Neo,

I had the same problem, it was a bug in Fluent NHibernate that was fix
yesterday.
take the last version of Fluent NHibernate from the trunk and it will
work.

http://fluent-nhibernate.googlecode.com/svn/trunk

Billy

unread,
Feb 20, 2009, 9:23:51 AM2/20/09
to S#arp Architecture
As Roy suggested, the current Fluent NHibernate from the trunk will
not ignore enum values. You can grab the compiled version from
https://sharp-architecture.googlecode.com/svn/trunk/bin which includes
the won't-ignore-enums fix.

But exactly as you stated, to my amazement, NHibernate performs an
update to an object if you're binding an int value to an enum. That's
incredibly annoying to say the least (and to my chagrin that I hadn't
noticed that). I would agree then that storing the strings (as much
as it irks me to have to suggest) is the appropriate way to go.

Please let me know if the latest FluentNHibernate.dll doesn't resolve
your issue.

Billy

Neo

unread,
Feb 20, 2009, 9:37:51 AM2/20/09
to S#arp Architecture
@RoyWagner

You're right. Updated FluentNHibernate and all is working again.
Thanks Roy.

@Billy

Well, so I'll change the enum to string within my DB. No more int :P

Thank you Billy for your help also.

On Feb 20, 11:23 am, Billy <wmccaffe...@gmail.com> wrote:
> As Roy suggested, the current Fluent NHibernate from the trunk will
> not ignore enum values.  You can grab the compiled version fromhttps://sharp-architecture.googlecode.com/svn/trunk/binwhich includes

Luis Abreu

unread,
Feb 21, 2009, 9:29:12 AM2/21/09
to sharp-arc...@googlegroups.com
I've used this in the past:

ct.Map(c => c.Kind, "TipoContacto")
.CustomTypeIs(typeof (ContactKind))
.CustomSqlTypeIs("integer");

Where Contactkind is an enum.

Luis

Billy

unread,
Feb 24, 2009, 3:07:31 PM2/24/09
to S#arp Architecture
Luis,

I couldn't get your suggestion working. Here's what I ended up doing
to have ints in the DB to represent the enum values and avoiding a
flush of the object after it's loaded from the DB.

1) Create the enum type; e.g.,

public class CoreEnums
{
public enum NotificationPriorityType
{
Null = 0,
High = 1,
Medium = 2,
Low = 3
}
}

2) Add a foreign key called e.g., NotificationPriorityTypeFk, to the
table you're mapping to the notification priority types table. The
types table would have one row for each enum value; e.g. 1/High, 2/
Medium, 3/Low

3) Create an NHibernate type which inherits from PersistentEnumType
for the enum type that we want to map; e.g.:

public class NotificationLevelType : PersistentEnumType
{
public NotificationLevelType()
: base(typeof(CoreEnums.NotificationLevelType)) { }
}

4) Override the respective mapping; e.g.:

mapping.Map(notification => notification.MessageLevel,
"NotificationPriorityTypeFk")
.SetAttribute("type", typeof
(NotificationLevelType).AssemblyQualifiedName);

Let me know if you're able to provide a simpler approach to mapping an
enum to an int column without having the loaded object get updated
during flush.

Thanks!
Billy
> > > If you're storing theenumvalues in the Contact table as ints with a
> > > foreign key to a reference table, which I see as an ideal way to do
> > so
> > > in a normalized way, then you'd simply change your map as follows:
>
> > >             ct.Map(x => x.Type, "ContactType").Not.Nullable
> > > ().CustomTypeIs(typeof(int));
>
> > > Note that it gets mapped as a type of int, not theenumtype itself.
>
> > > You can get some pretty powerful behavior forenummappings.  For
> > > instance, the following example illustrates that the parent object
> > has
> > > a many to many relationship with anenumvalue stored within a many-
> > to-
> > > many table.  Note that the many-to-many stores the id to the parent
> > as
> > > well as a normalized id to theenumvalue which is stored in a
> > > reference table:
>
> > >         public void Override(AutoMap<Notification> mapping) {
> > >             mapping.HasMany<CoreEnums.ChannelType>(x => x.Channels)
> > >                 .WithTableName("Notification_Channels")
> > >                 .WithKeyColumn("NotificationFk")
> > >                 .AsElement("ChannelTypeFk")
> > >                 .AsBag();
> > >         }
>
> > > As long as you properly normalize the database and store theenum
> > > values as ints (with foreign keys to a reference table) instead of
> > > strings, it's very easy to push/pull the info with NHibernate
> > > mappings.
>
> > > Let me know if this doesn't assist.
>
> > > Thanks,
> > > Billy
>
> > > On Feb 20, 5:46 am, Simone Busoli <simone.bus...@gmail.com> wrote:
>
> > > > Neo, there are a zillion blog posts about how to map enums with
> > NHibernate,
> > > > why don't you try that
> > first?http://www.google.com/search?q=nhibernate+enum
>
> > > > On Fri, Feb 20, 2009 at 1:37 PM, Neo <digaomat...@gmail.com> wrote:
>
> > > > > Did anybody have problems to map anenumto a int DB column?

Billy

unread,
Feb 24, 2009, 3:09:00 PM2/24/09
to S#arp Architecture
Oops, Step 3 should reflect the following code:

public class NotificationPriorityType : PersistentEnumType
{
public NotificationPriorityType()
: base(typeof(CoreEnums.NotificationPriorityType)) { }
}

Billy

On Feb 24, 1:07 pm, Billy <wmccaffe...@gmail.com> wrote:
> Luis,
>
> I couldn't get your suggestion working.  Here's what I ended up doing
> to have ints in the DB to represent theenumvalues and avoiding a
> flush of the object after it's loaded from the DB.
>
> 1) Create theenumtype; e.g.,
>
> public class CoreEnums
> {
>     publicenumNotificationPriorityType
>     {
>         Null = 0,
>         High = 1,
>         Medium = 2,
>         Low = 3
>     }
>
> }
>
> 2) Add a foreign key called e.g., NotificationPriorityTypeFk, to the
> table you're mapping to the notification priority types table.  The
> types table would have one row for eachenumvalue; e.g. 1/High, 2/
> Medium, 3/Low
>
> 3) Create an NHibernate type which inherits from PersistentEnumType
> for theenumtype that we want to map; e.g.:
>
> public class NotificationLevelType : PersistentEnumType
> {
>     public NotificationLevelType()
>         : base(typeof(CoreEnums.NotificationLevelType)) { }
>
> }
>
> 4) Override the respective mapping; e.g.:
>
> mapping.Map(notification => notification.MessageLevel,
> "NotificationPriorityTypeFk")
>     .SetAttribute("type", typeof
> (NotificationLevelType).AssemblyQualifiedName);
>
> Let me know if you're able to provide a simpler approach to mapping anenumto an int column without having the loaded object get updated
> during flush.
>
> Thanks!
> Billy
Message has been deleted

Luis Abreu

unread,
Feb 26, 2009, 5:48:34 AM2/26/09
to sharp-arc...@googlegroups.com
I think it will always load the object...
Reply all
Reply to author
Forward
Message has been deleted
0 new messages