Mapping enum with NH

Discussion of open issues, suggestions and bugs regarding Entity Developer - ORM modeling and code generation tool
mindplay
Posts: 148
Joined: Tue 13 Dec 2011 22:58
Location: Ithaca, NY

Mapping enum with NH

Post by mindplay » Tue 13 Dec 2011 23:09

I added an Enum type, added a property and chose the enum type from the type drop-down.

I get the following exception:

NHibernate.MappingException: Could not determine type for: Ongweoweh.Entities.TaskType, Ongweoweh, for columns: NHibernate.Mapping.Column(Type)

It doesn't work, and I don't understand how this was intended to work.

Looking at the generated HBM, it simply has the type-name in the generated attribute, which seems wrong - the type-name in the attribute is supposed to be the name of an NH type "handler", a type that can convert back/forth between a .NET enum type and a column type (typically int, but string is also supported with the EnumStringType class:

http://elliottjorgensen.com/nhibernate- ... gType.html

Simply putting the name of an enum in the attribute does not work - and should not, as far as my understanding of NH goes...

What gives?

Shalex
Site Admin
Posts: 9543
Joined: Thu 14 Aug 2008 12:44

Post by Shalex » Thu 15 Dec 2011 14:13

The following DataModel1.Class1.hbm.xml was generated after adding to the model (in design time) enum Enum1:int{Member1, Member2} and class Class1{int Property1; Enum1 Property2}:

Code: Select all

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping assembly="ConsoleApplication492" namespace="ConsoleApplication492" xmlns="urn:nhibernate-mapping-2.2">
  <class name="Class1" table="Class1s" schema="dbo">
    <id name="Property1" type="Int32">
      <column name="Property1" not-null="true" precision="10" scale="0" sql-type="int" />
      <generator class="assigned" />
    </id>
    <property name="Property2" type="Enum1">
      <column name="Property2" precision="10" scale="0" sql-type="int" />
    </property>
  </class>
</hibernate-mapping>
The run-time works OK. Could you please point out the problem?

mindplay
Posts: 148
Joined: Tue 13 Dec 2011 22:58
Location: Ithaca, NY

Post by mindplay » Thu 15 Dec 2011 15:16

I get the same exception every time, even with a simple example like yours - in this case, I added a class Foo { public Id; public BarType Bar } and an enum BarType { A=1, B=2, C=3 } both via the visual designer - I still get a similar exception:

NHibernate.MappingException: Could not determine type for: MyApp.Entities.BarType, MyApp, for columns: NHibernate.Mapping.Column(Bar)

Can you explain why this should work? Looking at the generated XML, I don't see why or how this is expected to work:

Code: Select all

<property name="Bar" type="BarType">
      <column name="Bar" />
    </property> 
type="BarType" implies that there's an NH type called "BarType", but that's just the name of the enum type I defined - what NH needs, is the name of a type that convert between BarType and the "int" SQL-type.

Did you write/configure such a type elsewhere?

Or how come this works for you?

mindplay
Posts: 148
Joined: Tue 13 Dec 2011 22:58
Location: Ithaca, NY

Post by mindplay » Thu 15 Dec 2011 16:05

Okay, a bit more info.

According to the documentation you have two options for enums.

Leave out the type entirely, and let NH guess the type by using reflection:

Code: Select all

<property name="Bar">
      <column name="Bar" />
    </property>     
This works for me.

Or specify the fully qualified type-name of the enum:

Code: Select all

<property name="Bar" type="MyApp.Lib.BarType, Ongweoweh">
      <column name="Bar" />
    </property>   
This also works for me.

Simply putting an unqualified type-name in the type-attribute, from what I could read, causes NH to look for an NH type of that name - it will not "guess" that you're referring to a .NET type.

But either way, it seems like there should be an option to specify the NH type for a property in ED? So that you can choose what NH-type you want to use. So that, for example, you could use either the TrueFalse or YesNo NH-types for a Boolean property, or a custom type when you need to map an enum-type to a string-column.

mindplay
Posts: 148
Joined: Tue 13 Dec 2011 22:58
Location: Ithaca, NY

Post by mindplay » Thu 15 Dec 2011 19:51

Is there any way to override the output type-attribute by editing the template? This would enable me to implement a custom property with an NH type override.

mindplay
Posts: 148
Joined: Tue 13 Dec 2011 22:58
Location: Ithaca, NY

Post by mindplay » Mon 19 Dec 2011 15:22

To anybody else experiencing this problem, here's a work-around:

When specifying the property-type on the diagram, type in the fully qualified name of the enum-type.

If you pick it from the drop-down, it will not be qualified, neither in the generated code or in the mapping.

Entering the fully qualified name results in some verbosity in the generated code - since the fully qualified name will show up both the code and mapping files, but it works.

mindplay
Posts: 148
Joined: Tue 13 Dec 2011 22:58
Location: Ithaca, NY

Post by mindplay » Mon 19 Dec 2011 20:10

Yikes, this work-around is only good if your enum-types are in a different namespace - unfortunately, after saving/loading the model, ED "optimizes" the fully qualified name away, probably because it's technically redundant.

For now, I'm going to put my enum-types in a different namespace, and define them by hand, rather than defining enums in the model...

Shalex
Site Admin
Posts: 9543
Joined: Thu 14 Aug 2008 12:44

Post by Shalex » Tue 20 Dec 2011 11:06

As we understood, you are using external enums (not from your model), aren't you? But, for some reason, you are creating enum in your model which is intermediate between external enum and the data type of your property in a class. In this case, remove your intermediate enum from the model and assign the type of your property directly to the external enum: double click on the property in the designer and set the full name of your external enum.

If this doesn't help, please send us a small test project so that we can reproduce the issue in our environment.

mindplay
Posts: 148
Joined: Tue 13 Dec 2011 22:58
Location: Ithaca, NY

Post by mindplay » Tue 20 Dec 2011 13:51

Shalex wrote:As we understood, you are using external enums (not from your model), aren't you?
No. I have tried both using purely an enum defined in ED, and an enum defined in my own codebase. Neither works, unless I put the fully qualified type-name into ED - in which case, both works equally well; my own type, or one generated by ED. (the enum types I wrote by hand are identical to the ones generated by ED anyhow...)
Shalex wrote:But, for some reason, you are creating enum in your model which is intermediate between external enum and the data type of your property in a class. In this case, remove your intermediate enum from the model and assign the type of your property directly to the external enum: double click on the property in the designer and set the full name of your external enum.
I'm not sure what you mean by intermediate? As far as I know, it's not possible to extend enums.

I'm not doing anything weird here, as far as I know - if I create an empty project with a Foo class, BarType enum and a Foo.Bar property of that type, the generated mapping will read type="BarType" on the property mapping - and it doesn't work.

If I correct the type-name in ED to "MyApp.Entities.BarType", thus forcing ED to write this fully qualified name into the type-attribute, it works.

If it happens to work in your NH setup without qualifying the type, I don't know how it would - according to NH documentation, it's not correct, neither is it very performant, as NH has to search for the type.

I would recommend you write out the full type-name in the mapping files - according to documentation, that is the safest and most performant approach.

Shalex
Site Admin
Posts: 9543
Joined: Thu 14 Aug 2008 12:44

Post by Shalex » Fri 23 Dec 2011 09:04

We will investigate the issue with setting full type-name of enums and post here about the results.

Shalex
Site Admin
Posts: 9543
Joined: Thu 14 Aug 2008 12:44

Post by Shalex » Fri 23 Dec 2011 09:52

The bug with setting full enum name in property type is fixed. We will post here when the corresponding build of Entity Developer is available for download.

Shalex
Site Admin
Posts: 9543
Joined: Thu 14 Aug 2008 12:44

Post by Shalex » Thu 12 Jan 2012 16:36

New build of Entity Developer 4.2.110 is available for download now!
It can be downloaded from http://www.devart.com/entitydeveloper/download.html (trial version) or from Registered Users' Area (for users with valid subscription only).
For more information, please refer to http://www.devart.com/forums/viewtopic.php?t=23135 .

PeterM
Posts: 14
Joined: Tue 16 Jul 2013 12:53

Re: Mapping enum with NH

Post by PeterM » Fri 09 Aug 2013 09:34

Hi, sorry to dig up this old issue. However I think this problem was reintroduced in a newer version of Entity Developer as I'm running into the same problem described here and when using the custom type where I define the full name (including the assembly) it works correctly.
As far as I can see the fluent mapping is created correctly, but the xml mapping is missing the assembly.

Shalex
Site Admin
Posts: 9543
Joined: Thu 14 Aug 2008 12:44

Re: Mapping enum with NH

Post by Shalex » Wed 14 Aug 2013 16:28

We cannot reproduce the problem with the latest (5.5.164) build of Entity Developer.

The names of assembly and namespace can be set in the following ways:
1) using the "MyNamespace.MyEnum, MyAssembly" format in the Type field of the class property
2) via Assembly and Namespace properties of the enum
3) via Default Assembly and Default Namespace properties of the model

Please specify the exact (x.xx.xxx) build of your Entity Developer and send us a small test project to reproduce incorrect generation of XML mapping. Are you using a predefined NHibernate template?

PeterM
Posts: 14
Joined: Tue 16 Jul 2013 12:53

Re: Mapping enum with NH

Post by PeterM » Fri 16 Aug 2013 10:21

When setting the Assembly property of the Enum itself it indeed works as expected, when leaving it empty it doesn't use the Default Assembly of the model.
I'm using that exact last build. I've send a model which includes two enums, one with the Assembly defined and one without (where I am assuming the default should be used?!).

Post Reply