Mapping enum with NH
Mapping enum with NH
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?
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?
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}:
The run-time works OK. Could you please point out the problem?
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>
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:
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?
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>
Did you write/configure such a type elsewhere?
Or how come this works for you?
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:
This works for me.
Or specify the fully qualified type-name of the enum:
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.
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>
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>
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.
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.
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.
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...
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...
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.
If this doesn't help, please send us a small test project so that we can reproduce the issue in our environment.
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:As we understood, you are using external enums (not from your model), aren't you?
I'm not sure what you mean by intermediate? As far as I know, it's not possible to extend enums.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 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.
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 .
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 .
Re: Mapping enum with NH
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.
As far as I can see the fluent mapping is created correctly, but the xml mapping is missing the assembly.
Re: Mapping enum with NH
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?
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?
Re: Mapping enum with NH
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?!).
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?!).