Failed to UPDATE or INSERT using NHibernate - nhibernate

I'm using NHibernate on a legacy database with Oracle 8i client. I can perform Get and Delete on the database table, but can't save or update entries. The exception is as follow, the sqlString consists of question marks and I don't know why.
Nhibernate.Exceptions.GenericADOException:
{"could not update: [MIAP.Domain.Entities.MITFORG#3][SQL: UPDATE MITFORG SET TREELEVEL = ?, PARTENTID = ?, FORGNAME = ?, FORGINFO = ?, ACTIVE = ?, MUTATOR = ?, INPDATETIME = ?, UPDDATETIME = ? WHERE FORGID = ?]"}
Here are my entity class and mapping:
public class MITFORG {
private long fORGID;
private long? tREELEVEL;
private long? pARTENTID;
private string fORGNAME;
private string fORGINFO;
private string aCTIVE;
private long? mUTATOR;
private DateTime? iNPDATETIME;
private DateTime? uPDDATETIME;
public MITFORG() { }
public virtual long FORGID {
get {
return this.fORGID;
}
set {
this.fORGID = value;
}
}
public virtual long? TREELEVEL
{
get {
return this.tREELEVEL;
}
set {
this.tREELEVEL = value;
}
}
public virtual long? PARTENTID
{
get {
return this.pARTENTID;
}
set {
this.pARTENTID = value;
}
}
public virtual string FORGNAME {
get {
return this.fORGNAME;
}
set {
this.fORGNAME = value;
}
}
public virtual string FORGINFO {
get {
return this.fORGINFO;
}
set {
this.fORGINFO = value;
}
}
public virtual string ACTIVE {
get {
return this.aCTIVE;
}
set {
this.aCTIVE = value;
}
}
public virtual long? MUTATOR
{
get {
return this.mUTATOR;
}
set {
this.mUTATOR = value;
}
}
public virtual DateTime? INPDATETIME
{
get {
return this.iNPDATETIME;
}
set {
this.iNPDATETIME = value;
}
}
public virtual DateTime? UPDDATETIME
{
get {
return this.uPDDATETIME;
}
set {
this.uPDDATETIME = value;
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping assembly="MIAP.Domain" namespace="MIAP.Domain.Entities" xmlns="urn:nhibernate-mapping-2.2">
<class name="MITFORG" table="MITFORG" lazy="true" >
<id name="FORGID">
<generator class="assigned" />
</id>
<property name="TREELEVEL"></property>
<property name="PARTENTID"></property>
<property name="FORGNAME"></property>
<property name="FORGINFO"></property>
<property name="ACTIVE"></property>
<property name="MUTATOR"></property>
<property name="INPDATETIME"></property>
<property name="UPDDATETIME"></property>
</class>
</hibernate-mapping>
I've checked property names and table column names. Since the FORGID is assigned by the application, I changed the generator class to "assigned". It doesn't work with "identity" either. Could someone please point me the direction to debug this?
Edited: Code to save entries
Dim mitforgRepository As New MITFORGRepository
Dim mitforg As MITFORG = mitforgRepository.GetById(3)
mitforg.FORGINFO = "T"
mitforg.ACTIVE = "Y"
mitforg.FORGINFO = "T"
mitforg.INPDATETIME = Now
mitforg.MUTATOR = 324
mitforg.PARTENTID = 335
mitforg.TREELEVEL = 1
mitforg.UPDDATETIME = Now
mitforgRepository .Save(mitforg)
And here is the Repository class:
using System;
using System.Collections.Generic;
using System.Text;
using NHibernate;
using MIAP.Domain.Entities;
namespace MIAP.Domain.Repositories
{
public class MITFORGRepository : IRepository<MITFORG, Int64?>
{
private static ISession GetSession()
{
return SessionProvider.SessionFactory.OpenSession();
}
public MITFORG GetById(Int64? id)
{
using (ISession session = GetSession())
{
return session.Get<MITFORG>(id);
}
}
public void Save(MITFORG saveObj)
{
using (ISession session = GetSession())
{
using (ITransaction trans = session.BeginTransaction())
{
session.SaveOrUpdate(saveObj);
trans.Commit();
}
}
}
public void Delete(MITFORG delObj)
{
using (ISession session = GetSession())
{
using (ITransaction trans = session.BeginTransaction())
{
session.Delete(delObj);
trans.Commit();
}
}
}
}
}
The InnerException is System.Data.OracleClient.OracleException, ORA-12571
And here's the stack trace:
於 System.Data.OracleClient.OracleConnection.CheckError(OciErrorHandle errorHandle, Int32 rc)
於 System.Data.OracleClient.OracleCommand.Execute(OciStatementHandle statementHandle, CommandBehavior behavior, Boolean needRowid, OciRowidDescriptor& rowidDescriptor, ArrayList& resultParameterOrdinals)
於 System.Data.OracleClient.OracleCommand.ExecuteNonQueryInternal(Boolean needRowid, OciRowidDescriptor& rowidDescriptor)
於 System.Data.OracleClient.OracleCommand.ExecuteNonQuery()
於 NHibernate.AdoNet.AbstractBatcher.ExecuteNonQuery(IDbCommand cmd) 於 c:\Users\oskar.berggren\Documents\Projects\nhibernate-core-3\src\NHibernate\AdoNet\AbstractBatcher.cs: 行 203
於 NHibernate.AdoNet.NonBatchingBatcher.AddToBatch(IExpectation expectation) 於 c:\Users\oskar.berggren\Documents\Projects\nhibernate-core-3\src\NHibernate\AdoNet\NonBatchingBatcher.cs: 行 40
於 NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Object[] oldFields, Object rowId, Boolean[] includeProperty, Int32 j, Object oldVersion, Object obj, SqlCommandInfo sql, ISessionImplementor session) 於 c:\Users\oskar.berggren\Documents\Projects\nhibernate-core-3\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs: 行 2799

If you're using assigned id's you can't use SaveOrUpdate as NHibernate won't know whether it's a new instance (ie. to Save/do an insert) or an existing instance(ie. to Update).
You need to then be explicit about whether you're inserting a new entity (session.Save) or updating an existing entity (session.Update).

From the looks of it, you want to create a new object and save it into the database but what you are doing is loading the object using the Nhibernate Session and then updating the properties of it.. what this tells the Nhibernate session is that you have an object associated in the db with the given id and now you want to update certain properties when infact you want an insert statement to run.
Thus the right way is to create a new MitForg object and then call Session.SaveOrUpdate() on it and Nhibernate should take care of the insertion thereafter.
You could also try using Session.Merge().
Let me know if this works out for you..

Turns out it's a Unicode to ASCII conversion problem. I followed the solution in the links below. What's needed is adding a type attribute to all string type properties in the mapping file like this:
<property name="FORGNAME" type="AnsiString" ></property>
Recently my colleague also encountered some kind of Unicode/ASCII conversion problem but I never thought it would have been the answer. The exception message is just misleading...
Thank Martin for the inspiring suggestion!
NHibernate and The Case of the Crappy Oracle
NHibernate and ORA-12571 Errors

Related

NHibernate ID Generator with custom UserType

I have an NHibernate implementation working with a legacy database (DB2) that I have been asked to modify and I'm running into an issue with getting an id generator to work on an id property that is defined as a customer user type.
The data in a table is mapped to a class similar to the following:
// CLASS FILE
public class Request {
public virtual int Id { get; set; }
... other data properties ...
}
//MAPPING FILE
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="LibraryName" namespace="LibraryName.Domain" default-cascade="none">
<class name="Request" schema="..." table="..." where="...">
<id name="Id" column="..." type="LibraryName.Domain.DB2UserTypes.NullableIntegerType, LibraryName" />
... other data property mappings ...
The legacy database has tables with columns that are foreign keys into the Request's table. The columns containing these foreign keys are NOT nullable so the custom NullableIntegerType is used to write a zero into the foreign key column when a Request object property is null in a referencing object.
// NullableIntegerType Definition
public class NullableIntegerType : IEnhancedUserType
{
private static readonly SqlType[] SQL_TYPES = { NHibernate.NHibernateUtil.Int32.SqlType };
public SqlType[] SqlTypes { get { return SQL_TYPES; } }
public new bool Equals(object x, object y)
{
if (object.ReferenceEquals(x, y))
return true;
else if ((x == null) && (y == null))
return true;
else if ((x == null) || (y == null))
return false;
else
return x.Equals(y);
}
public object DeepCopy(object value) { return value; }
public bool IsMutable { get { return false; } }
public object Assemble(object cached, object owner) { return cached; }
public object Disassemble(object value) { return value; }
public object Replace(object original, object target, object owner) { return original; }
public int GetHashCode(object obj) { return obj.GetHashCode(); }
public Type ReturnedType { get { return typeof(int); } }
public object NullSafeGet(IDataReader dr, string[] names, object owner)
{
object obj = NHibernate.NHibernateUtil.Int32.NullSafeGet(dr, names[0]);
if (obj == null)
return null;
else
{
int result = (int)obj;
if ((result == 0) || (result == 9999999))
return null;
else
{
return int.Parse(result.ToString());
}
}
}
public void NullSafeSet(IDbCommand cmd, object obj, int index)
{
if (obj == null)
NHibernateUtil.Int32.NullSafeSet(cmd, 0, index);
else
NHibernateUtil.Int32.NullSafeSet(cmd, obj, index);
}
public object FromXMLString(string xml)
{
return int.Parse(xml);
}
public string ToXMLString(object obj)
{
return ((int)obj).ToString();
}
public string ObjectToSQLString(object obj)
{
return ((int)obj).ToString();
}
}
I have been asked to modify the mapping so that we can create new Request objects and have the ID be generated using a generator. I created the generator class and modified the Request object mapping to use the generator for the Id.
// GENERATOR CLASS
public class RequestGenerator : TableGenerator
{
public override object Generate(NHibernate.Engine.ISessionImplementor session, object obj)
{
using (IDbCommand command = session.Connection.CreateCommand())
{
command.CommandText = #"...";
command.CommandType = CommandType.StoredProcedure;
var parameter = command.CreateParameter();
parameter.DbType = DbType.Int32;
parameter.ParameterName = "#generatedId";
parameter.Value = 0;
parameter.Direction = ParameterDirection.InputOutput;
command.Parameters.Add(parameter);
command.ExecuteNonQuery();
return Convert.ToInt32(parameter.Value);
}
}
}
//MODIFIED MAPPING FILE
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="LibraryName" namespace="LibraryName.Domain" default-cascade="none">
<class name="Request" schema="..." table="..." where="...">
<id name="Id" column="..." type="LibraryName.Domain.DB2UserTypes.NullableIntegerType, LibraryName" >
<generator class="LibraryName.Domain.DB2Generators.RequestGenerator, LibraryName" />
</id>
... other data property mappings ...
When I attempt to test the modified mapping I get an error before my code even runs that NHibernate is unable to instantiate the ID generator.
// Sample Code
Request request = new Request() { Id = 0, ... other properties }
session.Save(request);
session.Flush();
// Exception Details and Stack Trace
NHibernate.MappingException was unhandled by user code
Message=could not instantiate id generator: LibraryName.Domain.DB2Generators.RequestGenerator, LibraryName
Source=NHibernate
StackTrace:
at NHibernate.Id.IdentifierGeneratorFactory.Create(String strategy, IType type, IDictionary`2 parms, Dialect dialect)
at NHibernate.Mapping.SimpleValue.CreateIdentifierGenerator(Dialect dialect, String defaultCatalog, String defaultSchema, RootClass rootClass)
at NHibernate.Impl.SessionFactoryImpl..ctor(Configuration cfg, IMapping mapping, Settings settings, EventListeners listeners)
at NHibernate.Cfg.Configuration.BuildSessionFactory()
at LibraryName.Infrastructure.NH.NHibernateSessionFactory.createSessionFactory() in C:\...\NHibernate\NHibernateSessionFactory.cs:line 23
at LibraryName.Infrastructure.NH.NHibernateSessionFactory.get_SessionFactory() in C:\...\NHibernate\NHibernateSessionFactory.cs:line 15
at LibraryName.Infrastructure.NH.NHibernateSessionFactoryProvider.CreateInstance(IContext context) in C:\...\NHibernate\NHibernateSessionFactoryProvider.cs:line 13
at Ninject.Activation.Provider`1.Create(IContext context)
at Ninject.Activation.Context.Resolve()
at Ninject.KernelBase.<>c__DisplayClass10.<Resolve>b__c(IBinding binding)
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.<CastIterator>d__b1`1.MoveNext()
at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
at Ninject.ResolutionExtensions.Get[T](IResolutionRoot root, IParameter[] parameters)
at LibraryName.Infrastructure.InternalMvcModule.<Load>b__0(IContext c) in C:\...\Ninject\InternalMvcModule.cs:line 16
at Ninject.Activation.Providers.CallbackProvider`1.CreateInstance(IContext context)
at Ninject.Activation.Provider`1.Create(IContext context)
at Ninject.Activation.Context.Resolve()
at Ninject.KernelBase.<>c__DisplayClass10.<Resolve>b__c(IBinding binding)
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
at Ninject.Planning.Targets.Target`1.GetValue(Type service, IContext parent)
at Ninject.Planning.Targets.Target`1.ResolveWithin(IContext parent)
at Ninject.Activation.Providers.StandardProvider.GetValue(IContext context, ITarget target)
at Ninject.Activation.Providers.StandardProvider.<>c__DisplayClass4.<Create>b__2(ITarget target)
at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at Ninject.Activation.Providers.StandardProvider.Create(IContext context)
at Ninject.Activation.Context.Resolve()
at Ninject.KernelBase.<>c__DisplayClass10.<Resolve>b__c(IBinding binding)
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
at Ninject.Web.Mvc.NinjectDependencyResolver.GetService(Type serviceType)
at System.Web.Mvc.DefaultControllerFactory.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType)
InnerException: System.ArgumentException
Message=type is not a ValueTypeType
Parameter name: type
Source=NHibernate
ParamName=type
StackTrace:
at NHibernate.Id.TableGenerator.Configure(IType type, IDictionary`2 parms, Dialect dialect)
at NHibernate.Id.IdentifierGeneratorFactory.Create(String strategy, IType type, IDictionary`2 parms, Dialect dialect)
InnerException:
If I remove the custom type (type="LibraryName.Domain.DB2UserTypes.NullableIntegerType, LibraryName") from the id mapping then the generator works correctly and my object saves to the database. How can I make the generator and the user defined type on the Id work together?
The NHibernate sources of the TableGenerator class show that its Configure method expects the column type to be a subclass of PrimitiveType. In your case this seems not to be the case, because you simply implement IEnhancedUserType (which probably get's wrapped internally, but by something which is not a PrimitiveType).
I cannot explain the reason for this, but in one of my projects I face similar requirements, i.e. implementing 0/null magic in a custom NHibernate type and using a custom id generator. In my project the custom "id" type directly implements IUserType and the id generator directly implements IIdentifierGenerator and IConfigurable, i.e. it does not extend NHibernate's TableGenerator. Maybe you should do the same with your id generator in order to work around the column type restriction of NHibernate's TableGenerator.

NHibernate - Sqlite in memory DB - Can't test the mapping files

I wanted to test whether my entities can be persisted to the database or not, so I came across this article:
http://www.codethinked.com/nhibernate-20-sqlite-and-in-memory-databases
My code to initialize the session factory is the same the one in the article:
public class NHibernateInMemoryTestFixtureBase
{
protected static ISessionFactory sessionFactory;
protected static Configuration configuration;
public static void InitalizeSessionFactory(params Assembly[] assemblies)
{
if (sessionFactory != null)
return;
var properties = new Dictionary<string, string>();
properties.Add("connection.driver_class", "NHibernate.Driver.SQLite20Driver");
properties.Add("dialect", "NHibernate.Dialect.SQLiteDialect");
properties.Add("connection.provider", "NHibernate.Connection.DriverConnectionProvider");
properties.Add("connection.connection_string", "Data Source=:memory:;Version=3;New=True;");
properties.Add("connection.release_mode", "on_close");
configuration = new Configuration();
configuration.Properties = properties;
foreach (Assembly assembly in assemblies)
{
configuration = configuration.AddAssembly(assembly);
}
sessionFactory = configuration.BuildSessionFactory();
}
public ISession CreateSession()
{
ISession openSession = sessionFactory.OpenSession();
IDbConnection connection = openSession.Connection;
new SchemaExport(configuration).Execute(false, true, false, true, connection, null);
return openSession;
}
}
And here's my test:
[Test]
public void IWillChangeThisNameLater()
{
InitalizeSessionFactory(typeof(LogRepository).Assembly);
var session = this.CreateSession();
Log log = Log.New("a", "b", "I");
session.Save(log);
session.Flush();
Assert.Greater(log.IDColumn, 0);
}
And the problem is, I removed the "a" property of Log from the log.hbm.xml and session.Save(log) is not throwing an exception or anything, it just works...
This must be obvious and on porpose, but I fail to find out why that is, how can it save it if is not mapped, is that how the in memory database work? how can I test my mapping then?
I mainly did this in-memory test so that I can know right away if a valid entity is failing to persist, of course that would include missing properties on the mapping file.
Any thoughts will be appreciated.
EDIT:
As requested,
the Log entity definition:
public class Log : DomainBase<Log, ILogRepository<Log>>
{
private int logId;
private string tableName;
private string field;
private string userLogin;
protected Log()
{
}
protected Log(string tableName, string field, string userLogin)
{
TableName = tableName;
Field = field;
UserLogin = userLogin;
}
public virtual int LogId { get; set; }
public virtual string TableName { get; set; }
public virtual string Field { get; set; }
public virtual string UserLogin { get; set; }
}
the Log Mapping:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="DomainProject" table="Log" lazy="true">
<id name="logId" column="ID" type="int">
<generator class="native" />
</id>
<property name="TableName" column="TableName" type="string" />
<property name="Field" column="Field" type="string" />
<property name="UserLogin" column="UserLogin" type="string" />
</class>
</hibernate-mapping>
If a class contains a property that is not mentioned in the mappings, NHibernate will ignore the property.

Fluent NHibernate automapping

I was just wandering if it would be possible to use the Fluent NHibernate to auto map a .Net TcpClient object?
I have a class that has a TcpClient property which I would like to map.
I tried creating a custom class inheriting from TcpClient called tTcpClient and adding an Id Property with a getter/setter; however, it was still looking for the Id field for the base class.
Anyone have any ideas if it is possible, or will I need to create my own xml mapping for the TcpClient?
I was sort of hoping to be able to save the object to easily recreate it on reloading the application and to bind the properties of the TcpClient object to the PropertiesGrid and allowing configuration through that rather easy.
Thanks.
NHibernate does not know how to deal with complex types like TcpClient out of the box. But it lets you provide your own loading and storing code. You can use IUserType:
public class TcpClientMapper : IUserType {
public SqlType[] SqlTypes {
get {
return new[] {
new SqlType(DbType.String),
new SqlType(DbType.Int32)
};
}
}
public Object NullSafeGet(IDataReader rs, String[] names, ...) {
String address = NHibernateUtil.String.NullSafeGet(rs, names[0]);
Int32 port = NHibernateUtil.Int32.NullSafeGet(rs, names[1]);
return new TcpClient(address, port);
}
public void NullSafeSet(IDbCommand cmd, Object value, Int32 index) {
TcpClient tcpClient = value as TcpClient;
if(tcpClient == null) {
NHibernateUtil.String.NullSafeSet(cmd, null, index);
NHibernateUtil.Int32.NullSafeSet(cmd, null, index + 1);
} else {
EndPoint red = tcpClient.Client.RemoteEndPoint;
IPEndPoint endpoint = ((IPEndPoint)red);
NHibernateUtil.String.Set(cmd, endpoint.Address.ToString(), index);
NHibernateUtil.Int32.Set(cmd, endpoint.Port, index + 1);
}
}
public Type ReturnedType {
get { return typeof(TcpClient); }
}
// TODO: implement other methods
}
And map it like this in hbm:
<property name="_tcpClient" type="MyNamespace.TcpClientMapper, MyAssembly">
<column name="Address" /> <!-- NullSafeGet/Set index == 0 -->
<column name="Port" /> <!-- NullSafeGet/Set index == 1 -->
</property>
Or use fluent UserTypeConvention:
public class TcpClientUserTypeConvention : UserTypeConvention<TcpClientMapper> {
}
Nathan,
Have you had a look at this project?
http://automapper.org/
Cheers

NHibernate - code example for update

I've been trying all day to get one of my object to be saved with versions but to no avail. Please point out what I'm doing wrong, as I've tried SaveOrUpdate, Merge() and Update() after a Clear() call.
The business object:
public class MappedTest
{
public virtual Guid TestID { get; set; }
public virtual int VersionID { get; set; }
public virtual byte[] Content { get; set;}
public virtual DateTime DateSaved { get; set; }
}
The mapping:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping ...>
<class name="TestImp.Definition.MappedTest, PythonTest" table="Tests">
<id name="TestID" unsaved-value="00000000-0000-0000-0000-000000000000">
<generator class="guid"/>
</id>
<version name="VersionID" column="VersionID" />
<property name="Content" column="TestObject" type="BinaryBlob"/>
<property name="DateSaved" column="Date"/>
`
The actual code:
using (var session = new Configuration().Configure().BuildSessionFactory().OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
if(session.Get<MappedTest>(mappedTest.TestID) == null)
{
session.Save(mappedTest);
}
else
{
session.Clear();
session.Update(mappedTest);
}
transaction.Commit();
}
}`
Thanks.
For insert try just with:
using (var session = new Configuration().Configure().BuildSessionFactory().OpenSession())
{
MappedTest mappedTest =new MappedTest();
using (ITransaction transaction = session.BeginTransaction())
{
session.SaveOrUpdate(mappedTest);
transaction.Commit();
}
}
for update:
using (var session = new Configuration().Configure().BuildSessionFactory().OpenSession())
{
MappedTest mappedTest =session.Get<MappedTest>(..an Id..);
mappedTest.YourProperty="newValue";
using (ITransaction transaction = session.BeginTransaction())
{
session.SaveOrUpdate(mappedTest);
transaction.Commit();
}
}
If you need it try use a session.Flush() to force database operations.
Another possibility that took me some time to realize and is not covered yet on this thread: In such case, check if your mapper is set on ReadOnly. NHibernate does not tell anything when asked to save or update with a ReadOnly mapper.

How do I create/use a Fluent NHibernate convention to automap UInt32 properties to an SQL Server 2008 database?

I'm trying to use a convention to map UInt32 properties to a SQL Server 2008 database. I don't seem to be able to create a solution based on existing web sources, due to updates in the way Fluent NHibernate works - i.e. examples are out of date.
I'm trying to have NHibernate generate the schema (via ExposeConfiguration). I'm happy to have NHibernate map it to anything sensible (e.g. bigint).
Here's my code as it currently stands (which, when I try to expose the schema, fails due to SQL Server not supporting UInt32). Apologies for the code being a little long, but I'm not 100% sure what is relevant to the problem, so I'm erring on the side of caution. Most of it is based on this post.
The error reported is:
System.ArgumentException : Dialect does not support DbType.UInt32
I think I'll need a relatively comprehensive example, as I don't seem to be able to pull the pieces together into a working solution, at present.
FluentConfiguration configuration =
Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008
.ConnectionString(connectionString))
.Mappings(mapping =>
mapping.AutoMappings.Add(
AutoMap.AssemblyOf<Product>()
.Conventions.Add<UInt32UserTypeConvention>()));
configuration.ExposeConfiguration(x => new SchemaExport(x).Create(false, true));
namespace NHibernateTest
{
public class UInt32UserTypeConvention : UserTypeConvention<UInt32UserType>
{
// Empty.
}
}
namespace NHibernateTest
{
public class UInt32UserType : IUserType
{
// Public properties.
public bool IsMutable
{
get
{
return false;
}
}
public Type ReturnedType
{
get
{
return typeof(UInt32);
}
}
public SqlType[] SqlTypes
{
get
{
return
new SqlType[]
{
SqlTypeFactory.Int32
};
}
}
// Public methods.
public object Assemble(object cached, object owner)
{
return cached;
}
public object DeepCopy(object value)
{
return value;
}
public object Disassemble(object value)
{
return value;
}
public new bool Equals(object x, object y)
{
return (x != null && x.Equals(y));
}
public int GetHashCode(object x)
{
return x.GetHashCode();
}
public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
int? i = (int?)NHibernateUtil.Int32.NullSafeGet(rs, names[0]);
return (UInt32?)i;
}
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
UInt32? u = (UInt32?)value;
int? i = (Int32?)u;
NHibernateUtil.Int32.NullSafeSet(cmd, i, index);
}
public object Replace(object original, object target, object owner)
{
return original;
}
}
}
You'd need to map to an existing SQL Server datatype, of course.
Based on this question, "Best way to store UInt32 in Sql Server", your choices:
CLR datatype
bigint
decimal
a workaround using int.MinValue to map to int