Enum fields cannot be mapped to database on DB2

Description

I explained the problem in forums also.

http://forum.hibernate.org/viewtopic.php?t=986593

The problem is that enum fields cannot be mapped to the database with DB2 dialect . Enum fields wants to be saved as integer(not as string) on database. So that in the mapper file the enum field's type property is set to nothing. (Also tried with type="int" and type="MyNameSpace.MyEnum, MyNameSpace" and type="String" the result is same)

The table is created by NHibernate with "new SchemaExport(cfg).Create(false, true)"

When insert command is run by NHibernate, NotSupportedException is thrown as below.

System.NotSupportedException: Invalid data type.

I tried the same method with MySQL dialect and it worked well. I think the problem is on DB2 dialect or something.

ADO.NET Provider: IBM DB2 .NET Data Provider (Comes with i5 V5R3M0 server. I patched the provider with the latest updates)
.NET Framework: 2.0

Environment

None

Attachments

2

Activity

Show:

Fabio Maulo 
June 19, 2008 at 2:47 PM

Fixed with refactoring of PersistentEnumType (r3568).

TolgaO 
June 16, 2008 at 9:51 AM

This patch solves the enumeration mapping problem on DB2 databases using IBM DB2 Data Provider.

TolgaO 
June 16, 2008 at 9:49 AM

Today I had free time to try to find the bug. I started debugging with a small application that maps a student class with properties id, name, number and "GENDER" to the database. While debugging i compared the property values of inner NHibernate classes for MySQL and DB2 databases. All the values are same for both databases. And i wrote another application using plain OLE DB as below

------------------------------------------------------------------------------------------------------------------------
Student s = new Student();
s.ID = 2;
s.Name = "Tolga Onbay";
s.Number = 23456;
s.Gender = Gender.Female;

iDB2Connection connection = new iDB2Connection("DataSource=XXXXXXX;UserID=YYYYYYYY;Password=ZZZZZZZZZ;Database=WWWWWW");
connection.Open();

iDB2Command command = new iDB2Command("INSERT INTO S65A2F1D.EMOTDB.OGRENCI (ID, NUMBER, NAME, GENDER) VALUES (?, ?, ?, ?)", connection);

iDB2Parameter paramID = new iDB2Parameter("p1", iDB2DbType.iDB2Integer);
iDB2Parameter paramNumber = new iDB2Parameter("p2", iDB2DbType.iDB2Integer);
iDB2Parameter paramName = new iDB2Parameter("p3", iDB2DbType.iDB2VarChar, 50);
iDB2Parameter paramGender = new iDB2Parameter("p4", iDB2DbType.iDB2Integer);

paramID.Value = s.ID;
paramNumber.Value = s.Number;
paramName.Value = s.Name;
paramGender.Value = s.Gender;

command.Parameters.Add(paramID);
command.Parameters.Add(paramNumber);
command.Parameters.Add(paramName);
command.Parameters.Add(paramGender);

command.ExecuteNonQuery();
connection.Close();

------------------------------------------------------------------------------------------------------------------------
The code above is throwing an exception as below

------------------------------------------------------------------------------------------------------------------------
System.NotSupportedException was unhandled
Message="Invalid data type."
Source="IBM.Data.DB2.iSeries"
StackTrace:
at IBM.Data.DB2.iSeries.MPParamConverter.normalizeData(Object& data)
at IBM.Data.DB2.iSeries.iDB2Command.setRowOfParameterData(MpDcData[]& dcDataRow)
at IBM.Data.DB2.iSeries.iDB2Command.execute()
at IBM.Data.DB2.iSeries.iDB2Command.ExecuteNonQuery()
at SampleApp.Program.Main(String[] args) in C:\NHibernate-1.2.1.GA-src\src\SampleApp\Program.cs:line 63
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

------------------------------------------------------------------------------------------------------------------------
I realized that the problem is on IBM DB2 Provider. The db2 parameter is not accepting enum values directly. If i change the line

paramGender.Value = s.Gender;

with this

paramGender.Value = (int) s.Gender;

the problem has gone away.

Then i searched NHibernate code for assigning values to enum properties. In Set method of PersistentEnumType class the value of a enum type is assigning as below

par.Value = value;

Of course the value cannot be directly casted to integer value. So i found GetValue method in same class which i think it is made for just Oracle. Then i change the above line with this and the problem is solved

par.Value = GetValue(value);

I tested this with MySQL and DB2. Also i changed the Genders enum type to long and there is no problem. I think there will be no problem with other databases and enum types.

I attached the patch which is generated for revision 3563 in 1.2.x branch. This solution is OK?

OrenE 
May 31, 2008 at 3:24 AM

I don't have a DB2 to test this, so I have no idea what the problem is.
The best scenario is that you can create a patch that solve this issue.
I believe that this may be an issue with parameter types set in the ADO parameter set.
But again, can't test that.

TolgaO 
May 31, 2008 at 12:59 AM

I can't understand what you mean with create the ADO.NET code. Could you explain it?

Fixed

Details

Assignee

Reporter

Components

Fix versions

Affects versions

Priority

Who's Looking?

Open Who's Looking?
Created May 14, 2008 at 9:01 AM
Updated June 19, 2008 at 2:47 PM
Resolved June 19, 2008 at 2:47 PM
Who's Looking?