ah... The Versioning is not the place of the modification, instead, the right place is the implementation of IVersionType inside Int32Type. btw... a IUserVersionType would be perfect for your case.
On Wed, Nov 17, 2010 at 3:44 PM, Fabio Maulo <[email protected]> wrote: > 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 > > -- 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.
