Try to create a failing NUnit test and create a new issue (improvement) in our JIRA.Thanks.
2009/3/9 Germán Schuager <[email protected]> > Fabio, I've made up the Cat class only to show my point: session.Merge is > accessing properties of instances in invalid state when it is not needed. > > I do have the real use-case and I assure you that it makes a lot more sense > than the cat ;) only that it is very complex to present it here... > > The solution was simple. I just added this to the Num getter: > > if (state != null) return 0; > > but this was only to please session.Merge, and I think that NH could be > improved by not requiring me to do that. > > If I came up with something more "real" than the Cat I will follow up. > > Thanks for your time. > > > > > On Mon, Mar 9, 2009 at 6:39 PM, Fabio Maulo <[email protected]> wrote: > >> Ah... German... try to recreate the situation out-side the code of the >> application; I'm sure you will find the solution or at least you can send us >> a real use-case with a real class and a real mapping. >> >> 2009/3/9 Fabio Maulo <[email protected]> >> >> so.. in a property getter you are accessing to a Relationship loaded using >>> lazy-loading, inside the same class... and all to have a unnormalized >>> property.interesting and discouraged approach. >>> >>> Inside the getter you should check if "state" is a proxy and in that case >>> you should initialize it (the dyn-proxy don't work inside the instance) >>> >>> Another possibility is fetch="join" to load "state" immediately. >>> >>> Your existing code are working only under some very specific condition: >>> it work only if you access to the property "State" before access to the >>> property "Num" from some place outside the class instance. >>> To be clear, try this in a fresh session: >>> var c = session.Get<Cat>(id); >>> Assert.That(c.Num, Is.Not.EqualTo(0)); >>> >>> >>> >>> 2009/3/9 Germán Schuager <[email protected]> >>> >>>> My actual model is somewhat more complex than this: >>>> >>>> public interface INum >>>> { >>>> int Num { get; } >>>> } >>>> >>>> public class Cat : Entity, INum >>>> { >>>> private State state; >>>> >>>> protected Cat() { } >>>> >>>> public Cat(State state) >>>> { >>>> this.state = state; >>>> } >>>> >>>> public virtual State State { get { return state; } } >>>> >>>> public virtual int Num { get { return state.Num; } } >>>> } >>>> >>>> <?xml version="1.0" encoding="utf-8"?> >>>> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" >>>> assembly="MyAssembly" namespace="MyNamespace"> >>>> <class name="Cat" table="Cats"> >>>> <id name="ID" column="CatID" type="Int32"> >>>> <generator class="hilo" /> >>>> </id> >>>> <many-to-one name="State" access="field.camelcase" /> >>>> <property name="Num" access="readonly" /> >>>> </class> >>>> </hibernate-mapping> >>>> >>>> >>>> On Mon, Mar 9, 2009 at 6:05 PM, Fabio Maulo <[email protected]>wrote: >>>> >>>>> Mapping please. >>>>> >>>>> >>>>> 2009/3/9 Germán Schuager <[email protected]> >>>>> >>>>>> inline >>>>>> >>>>>> On Mon, Mar 9, 2009 at 5:11 PM, Fabio Maulo <[email protected]>wrote: >>>>>> >>>>>>> The fact is that the Merge need to read the state from DB but with >>>>>>> its result in the persistent class (not from DataReader). >>>>>> >>>>>> >>>>>> I think that I understand. That is the case of merging a detached >>>>>> entity, but when merging a new transient entity that it is not in the DB >>>>>> then NH does not need to do this, does it? >>>>>> >>>>>> >>>>>>> BTW I don't understand how you can work with that entity... NH use >>>>>>> the parameterless ctor not only for Merge but even when you use >>>>>>> session.Get<T>(id). >>>>>>> >>>>>> >>>>>> Yes, but when using session.Get, it creates the new entity and WRITE >>>>>> its properties (*), on the other hand when using session.Merge it creates >>>>>> the entity and READ its properties. >>>>>> >>>>>> >>>>>>> In case of Get/Load who are injecting the State instance ? >>>>>>> >>>>>> >>>>>> NH is assigning the state field. I don't understand what you mean. >>>>>> >>>>>> >>>>>> >>>>>> (*) here the problem could be that NH tries to set Num before State, >>>>>> but this is due to me trying to simplify my domain; just suppose that Num >>>>>> doesn't have a setter and is mapped using access="readonly" >>>>>> >>>>>> >>>>>> >>>>>>> >>>>>>> >>>>>>> 2009/3/9 Germán Schuager <[email protected]> >>>>>>> >>>>>>>> Thanks Fabio, I will take a look at what a tuplizer is :), but I >>>>>>>> don't see why NH needs to access the properties of a newly created >>>>>>>> object >>>>>>>> just to overwrite them with the transient instance properties' values. >>>>>>>> >>>>>>>> I'm browsing the NH source to trying to find out but it is complex >>>>>>>> beast... >>>>>>>> >>>>>>>> It seems that this drags from the fact that both EntityIsTransient >>>>>>>> and EntityIsDetached are using the same method (CopyValues) to update >>>>>>>> the >>>>>>>> properties of the resulting persistent entity. Do you see room for >>>>>>>> improvement here or I should just move on? >>>>>>>> >>>>>>>> Thanks again. >>>>>>>> >>>>>>>> >>>>>>>> On Mon, Mar 9, 2009 at 4:27 PM, Fabio Maulo >>>>>>>> <[email protected]>wrote: >>>>>>>> >>>>>>>>> Ah.. sorry.. in Merge sure it access to the getter... sorryIf you >>>>>>>>> need a certain ctor you should implement your own tuplizer (I don't >>>>>>>>> know >>>>>>>>> where you will find the State instance but it is another matter). >>>>>>>>> >>>>>>>>> >>>>>>>>> 2009/3/9 Germán Schuager <[email protected]> >>>>>>>>> >>>>>>>>>> I've tried it. It does access the getters when merging an entity >>>>>>>>>> in the method CopyValues of DefaultMergeEventListener.cs >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> https://nhibernate.svn.sourceforge.net/svnroot/nhibernate/trunk/nhibernate/src/NHibernate/Event/Default/DefaultMergeEventListener.cs >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> On Mon, Mar 9, 2009 at 3:14 PM, Fabio Maulo <[email protected] >>>>>>>>>> > wrote: >>>>>>>>>> >>>>>>>>>>> NH don't access to the getter during object creation. Try it. >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> 2009/3/9 Germán Schuager <[email protected]> >>>>>>>>>>> >>>>>>>>>>>> Hi Fabio, >>>>>>>>>>>> >>>>>>>>>>>> Num is a persistent property, and I have several entities that >>>>>>>>>>>> implement INum; in this case Cat is delegating its actual >>>>>>>>>>>> implementation to >>>>>>>>>>>> its private field "state". >>>>>>>>>>>> >>>>>>>>>>>> I don't think that a nosetter access for Num would solve the >>>>>>>>>>>> problem because the exception would be generated anyway (when >>>>>>>>>>>> accessing the >>>>>>>>>>>> getter of Num for the newly instantiated Cat, the persistent one, >>>>>>>>>>>> which has >>>>>>>>>>>> state == null yet). >>>>>>>>>>>> >>>>>>>>>>>> And with the readonly accesor it would also be the same. >>>>>>>>>>>> >>>>>>>>>>>> The problem here is that NH is trying to read Num from an entity >>>>>>>>>>>> that is in an invalid state in order to compare this value with the >>>>>>>>>>>> transient one that I'm trying to merge, to determine if it should >>>>>>>>>>>> be copied >>>>>>>>>>>> or not. (At least I think this is the problem) >>>>>>>>>>>> >>>>>>>>>>>> Does this make sense? >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> On Mon, Mar 9, 2009 at 1:51 PM, Fabio Maulo < >>>>>>>>>>>> [email protected]> wrote: >>>>>>>>>>>> >>>>>>>>>>>>> If Num is a persistent property you should use- a field only >>>>>>>>>>>>> to make NH happy (you don't need to use it) >>>>>>>>>>>>> - Num access="nosetter.camelcase"... if I well remember we have >>>>>>>>>>>>> another accessor in NH2.1 access="read-only" >>>>>>>>>>>>> >>>>>>>>>>>>> 2009/3/9 Germán Schuager <[email protected]> >>>>>>>>>>>>> >>>>>>>>>>>>> Hi, >>>>>>>>>>>>>> >>>>>>>>>>>>>> I want to do a merge of a transient object which some of its >>>>>>>>>>>>>> properties are assigned with detached objects, in order to get a >>>>>>>>>>>>>> persistent >>>>>>>>>>>>>> object with all its properties assigned with persistent >>>>>>>>>>>>>> instances (using >>>>>>>>>>>>>> cascade="merge"). Is this the correct usage scenario for merge? >>>>>>>>>>>>>> >>>>>>>>>>>>>> Here is a sample entity: >>>>>>>>>>>>>> >>>>>>>>>>>>>> public interface INum >>>>>>>>>>>>>> { >>>>>>>>>>>>>> int Num { get; } >>>>>>>>>>>>>> } >>>>>>>>>>>>>> >>>>>>>>>>>>>> public class Cat : Entity, INum >>>>>>>>>>>>>> { >>>>>>>>>>>>>> private State state; >>>>>>>>>>>>>> >>>>>>>>>>>>>> protected Cat() { } >>>>>>>>>>>>>> >>>>>>>>>>>>>> public Cat(State state) >>>>>>>>>>>>>> { >>>>>>>>>>>>>> this.state = state; >>>>>>>>>>>>>> } >>>>>>>>>>>>>> >>>>>>>>>>>>>> public State State { get { return state; } } <--- mapped >>>>>>>>>>>>>> using access="field.camelcase" >>>>>>>>>>>>>> >>>>>>>>>>>>>> public int Num { >>>>>>>>>>>>>> get { return state.Num; } >>>>>>>>>>>>>> set { state.Num = value; } >>>>>>>>>>>>>> } >>>>>>>>>>>>>> >>>>>>>>>>>>>> } >>>>>>>>>>>>>> >>>>>>>>>>>>>> The problem that I'm facing is that Merge is trying to read >>>>>>>>>>>>>> the Num property from a Cat created using the protected >>>>>>>>>>>>>> constructor (the >>>>>>>>>>>>>> persistent instance?) before assigning its "state" field, thus >>>>>>>>>>>>>> throwing a >>>>>>>>>>>>>> NullReferenceException in the getter. >>>>>>>>>>>>>> >>>>>>>>>>>>>> A simple solution would be to add a check to verify that state >>>>>>>>>>>>>> != null in the getter, but that would be only to support NH >>>>>>>>>>>>>> functionality >>>>>>>>>>>>>> and it would have nothing to do with my domain. >>>>>>>>>>>>>> >>>>>>>>>>>>>> Do I need to add the check for state != null? >>>>>>>>>>>>>> Can NH be improve to handle this situation? >>>>>>>>>>>>>> >>>>>>>>>>>>>> Regards. >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>>> -- >>>>>>>>>>>>> Fabio Maulo >>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> -- >>>>>>>>>>> Fabio Maulo >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> -- >>>>>>>>> Fabio Maulo >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>> >>>>>>> >>>>>>> -- >>>>>>> Fabio Maulo >>>>>>> >>>>>>> >>>>>>> >>>>>> >>>>>> >>>>>> >>>>> >>>>> >>>>> -- >>>>> Fabio Maulo >>>>> >>>>> >>>>> >>>> >>>> >>>> >>> >>> >>> -- >>> Fabio Maulo >>> >> >> >> >> -- >> 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 -~----------~----~----~----~------~----~------~--~---
