Hi Fabio,
Thanks for the response. A custom type seemed like overkill here
since all I really want is a nullable Int32. I ended up doing three
things to work around this problem:
- Made the version property in my POCO nullable (int?) to solve the
problem where NHibernate found a "dirty" (but not really dirty) object
in the database, since its version property was mistakenly set to null
- Made the version property in my mapping XML just an "int" (not sure
if it necessary to call out that it's nullable in the mapping XML, but
I got the exception noted below when I did -- it works when I leave
out the type as well, of course.)
- Made the following code change (to fix the NullReferenceException
when NHibernate tries to increment the null value in the database):
--- Versioning.cs
+++ Versioning.cs (working copy)
@@ -28,6 +28,11 @@
/// <returns>Returns the next value for the version.</returns>
public static object Increment(object version,
IVersionType versionType, ISessionImplementor session)
{
+ if(version == null)
+ {
+ version = versionType.Seed(session);
+ }
+
object next = versionType.Next(version, session);
if (log.IsDebugEnabled)
{
By the way, I also tested to verify that the 3rd change was really
necessary. (Since I saw Seed() being used elsewhere, I wasn't sure if
it would try again to increment a null value after I fixed my
mappings.)
Also, in case anyone else is seeing this problem, the following
exception is thrown when I try to specify the type of the version
property in the XML as "int?":
NHibernate.MappingException : Could not compile the mapping document:
Example.hbm.xml
----> NHibernate.MappingException : Could not determine type for:
MyCompany.Model.int?, PROLIN.DAO, for columns:
NHibernate.Mapping.Column(VERSION)
at NHibernate.Cfg.Configuration.LogAndThrow(Exception exception) in
Configuration.cs: line 340
at NHibernate.Cfg.Configuration.AddDeserializedMapping(HbmMapping
mappingDocument, String documentFileName) in Configuration.cs: line
528
at NHibernate.Cfg.Configuration.AddValidatedDocument(NamedXmlDocument
doc) in Configuration.cs: line 497
at NHibernate.Cfg.Configuration.ProcessMappingsQueue() in
Configuration.cs: line 1830
at NHibernate.Cfg.Configuration.AddDocumentThroughQueue(NamedXmlDocument
document) in Configuration.cs: line 1821
at NHibernate.Cfg.Configuration.AddXmlReader(XmlReader hbmReader,
String name) in Configuration.cs: line 1814
at NHibernate.Cfg.Configuration.AddInputStream(Stream xmlInputStream,
String name) in Configuration.cs: line 644
at NHibernate.Cfg.Configuration.AddResource(String path, Assembly
assembly) in Configuration.cs: line 682
at NHibernate.Cfg.Configuration.AddAssembly(Assembly assembly) in
Configuration.cs: line 761
--MappingException
at NHibernate.Mapping.SimpleValue.get_Type() in SimpleValue.cs: line 241
at NHibernate.Cfg.XmlHbmBinding.RootClassBinder.BindProperty(HbmVersion
versionSchema, Property property, IDictionary`2 inheritedMetas) in
RootClassBinder.cs: line 227
at NHibernate.Cfg.XmlHbmBinding.RootClassBinder.BindVersion(HbmVersion
versionSchema, PersistentClass rootClass, Table table, IDictionary`2
inheritedMetas) in RootClassBinder.cs: line 209
at NHibernate.Cfg.XmlHbmBinding.RootClassBinder.Bind(HbmClass
classSchema, IDictionary`2 inheritedMetas) in RootClassBinder.cs: line
55
at NHibernate.Cfg.XmlHbmBinding.MappingRootBinder.AddRootClasses(HbmClass
rootClass, IDictionary`2 inheritedMetas) in MappingRootBinder.cs: line
83
at NHibernate.Cfg.XmlHbmBinding.MappingRootBinder.AddEntitiesMappings(HbmMapping
mappingSchema, IDictionary`2 inheritedMetas) in MappingRootBinder.cs:
line 42
at NHibernate.Cfg.XmlHbmBinding.MappingRootBinder.Bind(HbmMapping
mappingSchema) in MappingRootBinder.cs: line 29
at NHibernate.Cfg.Configuration.AddDeserializedMapping(HbmMapping
mappingDocument, String documentFileName) in Configuration.cs: line
520
This exception may be an error on my part rather than a bug, since
I am not explicitly calling out nullable properties anywhere else in
my mapping XML. (I imagine I was trying to do something unsupported,
but I don't explicitly state types anywhere else in my mapping XML.)
The quirk here is that for a version property (according to the
reference manual I found at
http://www.nhforge.org/doc/nh/en/index.html, section 5.1.7), the
"type" parameter is "(optional - defaults to Int32)". I'm not sure why
this wouldn't default to the type defined in the POCO for the version
property. Also, the manual states "Version numbers may be of type
Int64, Int32, Int16, Ticks, Timestamp, or TimeSpan (or their nullable
counterparts in .NET 2.0)", so I assumed I could write "int?".
Regards,
Mike
On Thu, Nov 11, 2010 at 6:12 AM, Fabio Maulo <[email protected]> wrote:
> May be you have to know that you can implements your own type for the
> version property following the rules of your legacy DB.
>
> --
> Fabio Maulo
>
>
> El 10/11/2010, a las 20:04, Mike Pontillo <[email protected]> escribió:
>
>> In case anyone was wondering,
>>
>> I figured out the problem. I am trying to map a legacy database
>> that uses version columns that are nullable. NHibernate threw
>> exceptions when I defined the nullable types in my POCOs and the
>> NHibernate XML (even though the manual stated that they were supported
>> -- so likely a bug) so I defined them as "int". However, I didn't
>> notice that some rows (very few - likely mistakes, or cases where
>> someone hand-edited the data) in the database indeed have NULL values
>> for the version column. If a query ever cached one of these NULL
>> values, and NHibernate subsequently performed a dirty check, it will
>> throw this exception.
>>
>> If I have time, I'll write up a test case and try patching the code
>> so NHibernate supports nullable version columns better. I think if
>> NHibernate treated NULL version columns as if they had the value 0,
>> this would fix the problem.
>>
>> Regards,
>> Mike
>>
>> On Tue, Nov 9, 2010 at 5:30 PM, Mike Pontillo <[email protected]> wrote:
>>> Greetings,
>>>
>>> I am using NHibernate 3.0.0 beta 2, and am trying to evolve some
>>> prototype code that was using the "session per call" anti-pattern to
>>> use a "session per request" approach. I soon noticed that after
>>> implementing the session sharing, my unit tests started failing with
>>> the following exception:
>>>
>>> System.NullReferenceException : Object reference not set to an
>>> instance of an object.
>>> at NHibernate.Type.Int32Type.Next(Object current, ISessionImplementor
>>> session) in d:\CSharp\NH\nhibernate\src\NHibernate\Type\Int32Type.cs:
>>> line 77
>>> at NHibernate.Engine.Versioning.Increment(Object version, IVersionType
>>> versionType, ISessionImplementor session) in d:\CSharp\NH\nhibernate
>>> \src\NHibernate\Engine\Versioning.cs: line 31
>>> at
>>> NHibernate.Event.Default.DefaultFlushEntityEventListener.GetNextVersion(FlushEntityEvent
>>> event) in d:\CSharp\NH\nhibernate\src\NHibernate\Event\Default
>>> \DefaultFlushEntityEventListener.cs: line 331
>>> at
>>> NHibernate.Event.Default.DefaultFlushEntityEventListener.ScheduleUpdate(FlushEntityEvent
>>> event) in d:\CSharp\NH\nhibernate\src\NHibernate\Event\Default
>>> \DefaultFlushEntityEventListener.cs: line 242
>>> at
>>> NHibernate.Event.Default.DefaultFlushEntityEventListener.OnFlushEntity(FlushEntityEvent
>>> event) in d:\CSharp\NH\nhibernate\src\NHibernate\Event\Default
>>> \DefaultFlushEntityEventListener.cs: line 45
>>> at
>>> NHibernate.Event.Default.AbstractFlushingEventListener.FlushEntities(FlushEvent
>>> event) in d:\CSharp\NH\nhibernate\src\NHibernate\Event\Default
>>> \AbstractFlushingEventListener.cs: line 161
>>> at
>>> NHibernate.Event.Default.AbstractFlushingEventListener.FlushEverythingToExecutions(FlushEvent
>>> event) in d:\CSharp\NH\nhibernate\src\NHibernate\Event\Default
>>> \AbstractFlushingEventListener.cs: line 60
>>> at
>>> NHibernate.Event.Default.DefaultDirtyCheckEventListener.OnDirtyCheck(DirtyCheckEvent
>>> event) in d:\CSharp\NH\nhibernate\src\NHibernate\Event\Default
>>> \DefaultDirtyCheckEventListener.cs: line 21
>>> at NHibernate.Impl.SessionImpl.IsDirty() in d:\CSharp\NH\nhibernate\src
>>> \NHibernate\Impl\SessionImpl.cs: line 1510
>>>
>>> The failures happened at "random" times, such as when I was about
>>> to execute a query and NHibernate would do a dirty check. So I added
>>> asserts for session.IsDirty() to try to catch the problem earlier, but
>>> I still don't see an obvious cause. The odd thing is, the version
>>> property should not be incrementing, since I am only doing read-only
>>> work within the session so far. For example, the following code fails:
>>>
>>>
>>> Assert.IsFalse(session.IsDirty());
>>> var query = session.CreateQuery("from " + typeof(T).Name);
>>> var list = query.List<T>();
>>> Console.WriteLine(" HQL query: {0} " + typeof(T).Name + "
>>> objects found", list.Count());
>>> Assert.AreEqual(_rowCount, list.Count()); // value cached
>>> in test setup
>>> Assert.IsFalse(session.IsDirty());
>>>
>>> I have been looking at this all afternoon, and tried to recreate
>>> the problem by pasting similar unit test code into the
>>> NHibernate.Test.VersionTest unit tests. (No luck yet.) Also, I tried
>>> doing a "session.Clear()" before running this code, (which I thought
>>> might solve the problem if there was stale data in the session) but it
>>> had no effect.
>>>
>>> I'm running out of ideas... does anyone have any thoughts on what
>>> to look at next?
>>>
>>> Thanks,
>>> Mike
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "nhusers" group.
>> To post to this group, send email to [email protected].
>> To unsubscribe from this group, send email to
>> [email protected].
>> For more options, visit this group at
>> http://groups.google.com/group/nhusers?hl=en.
>>
>
> --
> You received this message because you are subscribed to the Google Groups
> "nhusers" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to
> [email protected].
> For more options, visit this group at
> http://groups.google.com/group/nhusers?hl=en.
>
>
--
You received this message because you are subscribed to the Google Groups
"nhusers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/nhusers?hl=en.