The implementation of a custom type is not an overkill, instead it is just
the way NH gives you to define what is correct/intelligent for you.
For me Int32 is more than enough and its default "unsaved-value" as zero is
more than enough. You are looking for a version with two possible
unsaved-value ('null' and zero)On Tue, Nov 16, 2010 at 9:14 PM, Mike Pontillo <[email protected]> wrote: > 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]<nhusers%[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]<nhusers%[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]<nhusers%[email protected]> > . > For more options, visit this group at > http://groups.google.com/group/nhusers?hl=en. > > -- Fabio Maulo -- 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.
