Hibernate Books

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 22 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: NHibernate and Null object pattern
PostPosted: Wed Oct 24, 2007 2:39 pm 
Beginner
Beginner

Joined: Thu Apr 27, 2006 5:49 am
Posts: 31
Hi guys. Does anyone use null object pattern with nhibernate?

What I am interesting in is there a way to instruct nhibernate to use null object instead of null after loading data from db?

Imagine, you have a class Foo with a property of type class Bar. Bar property is not mandatory and it might be null. So after loading from db, if Bar property I want Hibernate to assign to it an instance of type NullBar which inherits Bar.

Is there is a way to do so?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Oct 26, 2007 2:49 am 
Senior
Senior

Joined: Mon Aug 21, 2006 9:18 am
Posts: 179
Why not
Code:

public Bar BarProp
{
    set{  bar = value??Bar.NULL; }
}



This is a static field in Bar holding a reference to NullBar. That way only one NullBar is permitted in the application...a good idea.

_________________
If this helped...please remember to rate it!


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 29, 2007 8:23 am 
Newbie

Joined: Sun Sep 23, 2007 9:51 am
Posts: 1
I had a similar problem and solved it as follows:
(suppose the member of type Bar in class Foo is called m_bar)

Code:
public Bar BarProp
{
    get{ m_bar == null ? return Bar.NullBar : return m_bar }

    set{ 
       if(value is NullBar) { m_bar = null; }
       else  { m_bar = value; }
   }



This gave me the benefit of not needing to map the NullBar class to the database with NHibernate while still being able to use the SpecialCase pattern in its classic form. If you do map it you cannot use the Bar.NullBar form but would require the less preferred method of loading a non-static instance of NullBar from the database, which is a real problem with you want to do something simple and natural like initializing your class member M_BAR to NullBAR.

Hope this helps.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 30, 2007 8:24 am 
Beginner
Beginner

Joined: Thu Apr 27, 2006 5:49 am
Posts: 31
Well, these methods work, but only if you have a hibernate mapping for null object classes. But what if I don't want to store "empty" classes into the database?

The way I think would solve the problem of saving "empty" classes is to use access="field" in hibernate mapping. Then a property will return Null object when a field contain null. But I am not sure how will it afffect on lazy loading. Will it still work if I set field access? I think it won't, because NHibernate wouldn't be able to create a proxy.

Another way to solve a problem with lazy load and Null objects is to have 2 sets of properties: one set for public usage and another for NHibernate only. NHibernate only properties will be mapped as usual properties and lazy would work fine on them. Also we could made them private, since NHibernate doesn't require them to be visible outside of the object. In this case the public property set would use Nhibernate ones to fetch the data. Consider this example:
Code:
public class Foo
{
    private Bar m_bar;

    public Bar Bar
    {
         get { return this.m_bar == null ? new NullBar() : this.BarInternal; }
         set { this.BarInternal = value; }
    }
    private Bar BarInternal
    {
         get { return this.m_bar; }
         set { this.m_bar = value; }
    }
 
}
public class Bar { }
public class NullBar : Bar { }

Obvious disadvantage of this method is doubling all properties.
What do you think?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 02, 2007 2:37 pm 
Expert
Expert

Joined: Fri Oct 28, 2005 5:38 pm
Posts: 390
Location: Cedarburg, WI
Using field access rather than property access doesn't interfere with lazy loading. I recommend always using field access, since it's more efficient and free of unwanted side effects should Nhibernate get/set properties. NHibernate is essentially a serialization mechanism, and standard .NET serialization works with fields, not properties.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 02, 2007 4:47 pm 
Beginner
Beginner

Joined: Thu Apr 27, 2006 5:49 am
Posts: 31
Nels_P_Olsen wrote:
Using field access rather than property access doesn't interfere with lazy loading. I recommend always using field access, since it's more efficient and free of unwanted side effects should Nhibernate get/set properties. NHibernate is essentially a serialization mechanism, and standard .NET serialization works with fields, not properties.


Well, can't say that I am 100% agree. Using field access is actually a hit to an OOP principle of encapsulation. If you want to write a simple or HQL query you against an object, then you must use properties of the hibernate mapping and if it points to private fields then it means that other classes will be aware of the object's implementation.

And actually I don't understand how lazy loading works if it doesn't require properties as a mapping point. What is the purpose of creating proxy object since it can't wrap calls to a field and how hibernate gets notified when you are trying to access to a lazy field, not property?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 02, 2007 5:15 pm 
Expert
Expert

Joined: Fri Oct 28, 2005 5:38 pm
Posts: 390
Location: Cedarburg, WI
With field access, the only thing that "cheats" and accesses the fields outside of the class is NHibernate when it is loading a queried entity from the database or saving changes to that entity back to the database. Your own code (outside of each entity class), including your HQL queries, still access only the properties. So, while it technically breaks encapsulation, in a practical sense (all access from your own code) encapsulation still holds.

Proxies aren't an issue when using field access. If the proxy is not initialized, then nothing has read any of your properties so it makes no difference if they're all empty. Uninitialized proxies are never saved back to the database since by definition nothing has changed on them. Once a proxy gets initialized, its properties just forward to your class's properties, and your fields get read and written to as expected. When you save the modified entity back to the database, even if its an initialized proxy, it still finds the field values in your class.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Nov 03, 2007 10:34 am 
Senior
Senior

Joined: Thu Feb 09, 2006 1:30 pm
Posts: 172
Nels_P_Olsen wrote:
Using field access rather than property access doesn't interfere with lazy loading. I recommend always using field access, since it's more efficient and free of unwanted side effects should Nhibernate get/set properties. NHibernate is essentially a serialization mechanism, and standard .NET serialization works with fields, not properties.


Ok, I'm not 100% sure I agree with everything here either. While I do agree with the statement that field level access is superior to property level access I believe there is actually a performance hit in doing so. That is assuming we are talking about private fields.

When you access private fields/properties through reflection additional Code Access Security checks must be made to ensure that the environment the application is operating in allows such actions. Therefore you will see a notable performance hit when reflecting on private members instead of public members. If this is no longer the case I would LOVE to hear about it.

That being said in no way does this break the OOP principles. the OOP principles are intended for you and your application so assist in developing consistent, reliable and maintainable code. That is all true. The issue here is that the database is just like your extended memory. It needs to save your object to the database and then load it from the database so that you wind up with exactly the same object.

Really this is exactly the same thing that .NET Serialization. It is trying to take your object move it to another persistence store besides memory and then allow you to retrieve exactly the same object. .NET Serialization will access your private fields, that's how you the same object back!


Top
 Profile  
 
 Post subject: NULL object pattern and queries
PostPosted: Sun Nov 04, 2007 8:35 am 
Newbie

Joined: Tue Jan 09, 2007 5:24 am
Posts: 15
Hi - Chris has a discussion about the NULL object pattern on his blog:

http://www.factored-software.com/iimple ... ttern.aspx

I personally used his trick with field access, and it works very well. However, as Chris points out, you need to change any HQL queries to use the field name instead.

Cheers,
Thomas


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 04, 2007 10:02 am 
Beginner
Beginner

Joined: Thu Apr 27, 2006 5:49 am
Posts: 31
Nels_P_Olsen wrote:
NHibernate is essentially a serialization mechanism, and standard .NET serialization works with fields, not properties.


Good point.

jchapman wrote:
Really this is exactly the same thing that .NET Serialization. It is trying to take your object move it to another persistence store besides memory and then allow you to retrieve exactly the same object. .NET Serialization will access your private fields, that's how you the same object back!


Not really a good comparison. Yes, while .NET uses fields for serialization the process of serialization is much easier to control.
Basically, in automatic serialization the system need to serialize all fields except these, which are specially marked out with [NonSerialized] attribute.
In case of a custom serialization the class which is to be serialized do all the work, so information about fields not exposed to anyone.

But consider this code (I know I can use Find in this case:) ):
Code:
    public class Foo
    {
         private int m_id;
    }
 
    public class FooService
    {
        public Foo LoadFooById(ISession session, int id)
        {
             ICriteria criteria = session.CreateCriteria(typeof(Foo));
             criteria.Add(Expression.Eq("id", id)); // here!
             return criteria.UniqueResult();
        }
    }


Now I have a bind to the name of a private field in an outer class. If I want to refactor the code and rename the field I would have to look through all the code that creates queries to the DB to find if it doesn't use old field name.
Of course this also will happen if I rename a public property, but the difference is that if I am renaming a public property it is I who responsible for fixing all such places in other code.


Top
 Profile  
 
 Post subject: Re: NULL object pattern and queries
PostPosted: Sun Nov 04, 2007 10:05 am 
Beginner
Beginner

Joined: Thu Apr 27, 2006 5:49 am
Posts: 31
thomask wrote:
http://www.factored-software.com/iimplement/2007/09/21/The+Null+Object+Pattern.aspx

Yes, a nice article. It shows how to use null pattern with NHibernate just like guys above said. Thoug, personally, I still have doubts about using NHibernate to map private fields directly to DB.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 04, 2007 10:16 am 
Beginner
Beginner

Joined: Thu Apr 27, 2006 5:49 am
Posts: 31
Nels_P_Olsen wrote:
Proxies aren't an issue when using field access. If the proxy is not initialized, then nothing has read any of your properties so it makes no difference if they're all empty. Uninitialized proxies are never saved back to the database since by definition nothing has changed on them. Once a proxy gets initialized, its properties just forward to your class's properties, and your fields get read and written to as expected. When you save the modified entity back to the database, even if its an initialized proxy, it still finds the field values in your class.


Please correct me if I am wrong. So, NHibernate proxies, that are created by default for classes that are marked as lazy="true" (or have no lazy property at all, since it is true by default), can be in two states: Initialized and Unitialized. When you first access to unitialized proxy it 1) initialize itself, loading all necessary data from DB and 2) Redirect the initial call to base "real" class.

In this case is it still required to make public properties/methods virtual, so the proxy could be initialized when outer code calls any of these properties/methods, right? In this case private fields will always be initialized before being accessed.

And if I am right, if you make a field public (yes, bad style, but...) then the lazy load must not work on the class since NHIbernate won't have a way to initialize the class if someone tries to access the field.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 05, 2007 8:32 am 
Senior
Senior

Joined: Thu Feb 09, 2006 1:30 pm
Posts: 172
Ishitori wrote:
Please correct me if I am wrong. So, NHibernate proxies, that are created by default for classes that are marked as lazy="true" (or have no lazy property at all, since it is true by default), can be in two states: Initialized and Unitialized. When you first access to unitialized proxy it 1) initialize itself, loading all necessary data from DB and 2) Redirect the initial call to base "real" class.

In this case is it still required to make public properties/methods virtual, so the proxy could be initialized when outer code calls any of these properties/methods, right? In this case private fields will always be initialized before being accessed.

And if I am right, if you make a field public (yes, bad style, but...) then the lazy load must not work on the class since NHIbernate won't have a way to initialize the class if someone tries to access the field.


Ishitori, yes you are correct. The thing to keep in mind is that even when you use field level access NHibernate is still mapping the properties. It is the properties that control the proxy. You can not override fields, hence there would be no way for the proxy to catch that access was made to a public field.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 05, 2007 8:37 am 
Senior
Senior

Joined: Thu Feb 09, 2006 1:30 pm
Posts: 172
Ishitori wrote:
Now I have a bind to the name of a private field in an outer class. If I want to refactor the code and rename the field I would have to look through all the code that creates queries to the DB to find if it doesn't use old field name.
Of course this also will happen if I rename a public property, but the difference is that if I am renaming a public property it is I who responsible for fixing all such places in other code.


I should have noticed this post earlier. This is not actually how it works. See the NHibernate documentation regarding property mappings here:

http://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html_single/#mapping-declaration-property

and pay special attention to the naming strategies. You could still put the name of the Property in your mapping file so that your HQL and criteria objects map the name of the property, you then provide the naming strategy that you have employed to convert the name of the property to the name of the field. So if you use a property name like "Id" and the camel case naming strategy NHibernate will look for the field "id" which it now knows corresponds to the "Id" property.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 06, 2007 5:36 am 
Beginner
Beginner

Joined: Thu Apr 27, 2006 5:49 am
Posts: 31
jchapman wrote:

Aha, this is a good point. I knew about access and naming strategies, but (I don't know why) always thought it is only about how to set a value to a field. But you are saying it is working in opposite direction as well.

In other words, if I have a property MyFoo and a field myFoo (camel case) of type Int32 then I can map it like that:
Code:
  ...
  <property name="Foo" access="field.camelcase" type="Int32" />
  ...


Then if I write an HQL query like: "FROM <ClassName> WHERE MyFoo=1" then NHibernate actually gets the value not through the property MyFoo, but directly from the field myFoo, right?

Well.. I thought a little and it seems my question doesn't make sense. When I use MyFoo in HQL the value still gets from the DB directly using column that is associated with a mapped property named "MyFoo" which is not related to properties and fields of the class and just a value in the table column...


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 22 posts ]  Go to page 1, 2  Next

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.