7
votes

I have a class that has an enum type indicating whether the message type is Email or Sms. The enum type is defined:

public enum ReminderType
{
    Email = 1,
    Sms = 2
}

The class that utilizes this type looks like:

public class Reminder : EntityBase
{
    public virtual string Origin { get; set; }
    public virtual string Recipient { get; set; }
    public virtual ReminderType Type { get; set; }
    public virtual Business Business { get; set; }
    public virtual DateTime Created { get; set; }

    public Reminder()
    {
        Created = DateTime.UtcNow;
    }
}

When I try to persist an entity of type Reminder to the database however, I get the following error:

System.Data.SqlClient.SqlException (0x80131904): Conversion failed when converting the nvarchar value 'Email' to data type int.

The backing field is of type int, so I'm not sure why NHibernate is trying to map the string representation by default. I'm using Fluent NHibernate, and the relevant mapping code is:

mappings.Override<Reminder>(map =>
{
     map.Map(x => x.Type).Column("Type")
});

I'm pretty sure the default behavior of NHibernate is to map enums as ints, so why is it not doing so in this case? I'm using SQL Server 2005, if that matters.

3
Email is the string value of the Type property. Nhibernate should be trying to store it as the integer value 1, but it's trying to store the string 'Email' instead, hence the error. I'm not sure why it's doing that though...Chris

3 Answers

5
votes

I am doing the same thing and got it working like so...

In my case EmployeeType is the enum class

 Map(x => x.EmployeeType, "EmployeeType_Id").CustomType(typeof (EmployeeType));
3
votes

I don't know why this person keeps posting and then deleting their comment or answer, but the link they provided () does answer my question. I opted not to go with a full blow class definition for the convention, but rather, an inline convention in the mappings code, like so:

var mappings = AutoMap.AssemblyOf<Business>()
    .Where(x => x.IsSubclassOf(typeof(EntityBase)))
    .IgnoreBase(typeof(EntityBase))
    .Conventions.Add
    (
        ConventionBuilder.Id.Always(x => x.GeneratedBy.Identity()),
        ConventionBuilder.HasMany.Always(x => x.Cascade.All()),
        ConventionBuilder.Property.Always(x => x.Column(x.Property.Name)),
        Table.Is(o => Inflector.Pluralize(o.EntityType.Name)),
        PrimaryKey.Name.Is(o => "Id"),
        ForeignKey.EndsWith("Id"),
        DefaultLazy.Always(),
        DefaultCascade.All(),

        ConventionBuilder.Property.When(
            c => c.Expect(x => x.Property.PropertyType.IsEnum),
            x => x.CustomType(x.Property.PropertyType))
    );

The last convention builder statement did the trick. I'm curious as to why Fluent NHibernate's default is to map enums as strings now. That doesn't seem to make much sense.

0
votes

You should never map Enum as int in NHibernate. It becomes a reason of having a ghost updates.

The best way to it is just not setting a type property in XML mappings. To achieve that in Fluent NHibernate you can use .CustomType(string.Empty).

Some additional info you can find here.