-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 13 posts ] 
Author Message
 Post subject: Prevent loading of one-to-many class, how? With proxy?
PostPosted: Wed Dec 03, 2003 12:16 pm 
Newbie

Joined: Wed Dec 03, 2003 11:15 am
Posts: 13
Location: Stuttgart, Germany
Hi @ all

hope it is ok to ask somewhat stupid questions, but I spent quite a lot
of time into this already and really need some progress.

So here comes my question:
I create an instance of class "com.iag.ProductOrder" and access some attributes
of it via the getter methods, but I do not touch the getter method for the "com.iag.Customer" class.
What do I have to change in the following mapping files, so that an instance of class
"com.iag.Customer" is only created when the corresponding getter method in the class
"com.iag.ProductOrder" is called?
Right now, an instance of "com.iag.Customer" is already created when the instance of the
"ProductOrder" is created.
I tried a lot with proxies, but had no success with this.

Here the mapping file of "com.iag.Customer":
###
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>
<class name="com.iag.Customer" proxy="com.iag.Customer"
table="customer" lazy="true">

<id name="ID"
type="integer"
column="id"
unsaved-value="-1">
<generator class="assigned"/>
</id>

<version name="modified"
unsaved-value="undefined"/>

<property name="Name"
column="name"
type="string"
not-null="true"
unique="true"/>

<set name="ProductOrder" inverse="true" lazy="true">
<key column="customer_id"/>
<one-to-many class="com.iag.ProductOrder"/>
</set>

</class>
</hibernate-mapping>
###

And here the mapping file for "com.iag.ProductOrder":
###
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>
<class name="com.iag.ProductOrder"
table="product_order" lazy="true">

<id name="No"
type="integer"
column="no"
unsaved-value="-1">
<generator class="assigned"/>
</id>

<version name="modified"
unsaved-value="undefined"/>

<property name="ProductCategory"
column="product_category"
type="integer"
not-null="true"/>

<property name="ProductID"
column="product_id"
type="integer"
not-null="true"/>

<property name="Text"
column="text"
type="string"
not-null="false"/>

<many-to-one name="Customer" column="customer_id" not-null="false"/>

</class>
</hibernate-mapping>
###

Thx for any answers.

Regards,
noips


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 03, 2003 2:07 pm 
Senior
Senior

Joined: Sun Aug 31, 2003 3:14 pm
Posts: 151
Location: Earth (at the moment)
I could be wrong but I believe that lazy loading is only supported for relationships going from parent to children.
So when you mapped the set of ProductOrders on Customer as lazy and loaded a Customer it wouldn't load all of the orders until you accessed that getter. But as for trying to not load the parent Customer of a ProductOrder I don't think you can do that (at least not in a straightforward manner that I am aware of).


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 03, 2003 2:37 pm 
Expert
Expert

Joined: Tue Sep 16, 2003 4:06 pm
Posts: 318
Location: St. Petersburg, Russia
For me it looks like proxy should work fine and no Customer instance should be loaded until you explicitly call getCustomer on ProductOrder.

Why are you sure Customer is initialized before? If you added some logging to constructor - it will not show real initialization. Since proxy is subclass of Customer, when proxy is constructed, Customer's constructor will be invoked too. But this does not mean Customer was loaded from the database.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 03, 2003 2:51 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
Proxies may not be used on final class or class having final method.

The proxied class must implement a default constructor with at least package visibility.

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 03, 2003 2:58 pm 
Newbie

Joined: Wed Dec 03, 2003 11:15 am
Posts: 13
Location: Stuttgart, Germany
dimas wrote:
For me it looks like proxy should work fine and no Customer instance should be loaded until you explicitly call getCustomer on ProductOrder.

Why are you sure Customer is initialized before? If you added some logging to constructor - it will not show real initialization. Since proxy is subclass of Customer, when proxy is constructed, Customer's constructor will be invoked too. But this does not mean Customer was loaded from the database.


Yes, I got some logging in the constructor. And in every setter and getter method as well. So I can See when a method is called. I can see that the default constructor is called. This is fine so far, because hibernate has to create a "strut" object (is this the correct word for that?) with at least the "id" value set, is this right?
This "strut" object overwrites every method in the father-class to be able to detect any access to it. And in case of an access, the actual data is fetched from the db. I hope I understood the basic idea behind that. If not, please correct me and explain me how this works, thx.

Back to the Customer-object initialization:
After calling the default constructor, the setter methods are called as well to initialize the object completely. Thats why I know that the data is fetched from the db.
I thougth this should not happen when using a proxy class or interface for a class, in my case "com.iag.Customer", right?

Thx for your replies.

Regards,
noips


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 03, 2003 3:00 pm 
Newbie

Joined: Wed Dec 03, 2003 11:15 am
Posts: 13
Location: Stuttgart, Germany
epbernard wrote:
Proxies may not be used on final class or class having final method.

Yes, I read that and considered it.

The proxied class must implement a default constructor with at least package visibility.


Yes, this is what I did as well.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 03, 2003 3:11 pm 
Expert
Expert

Joined: Tue Sep 16, 2003 4:06 pm
Posts: 318
Location: St. Petersburg, Russia
According to what you see, yes, Customer gets loaded. And according to what I know this should not happen.

Could you please paste here code which you have between factory.openSession() and close() ?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 03, 2003 4:00 pm 
Newbie

Joined: Wed Dec 03, 2003 11:15 am
Posts: 13
Location: Stuttgart, Germany
dimas wrote:
According to what you see, yes, Customer gets loaded. And according to what I know this should not happen.

Could you please paste here code which you have between factory.openSession() and close() ?


Yes, I will do in about 12 hours. I can not do that right now because I am at home, and the
code is at my working place :)

Regards,
noips


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 04, 2003 3:21 am 
Newbie

Joined: Wed Dec 03, 2003 11:15 am
Posts: 13
Location: Stuttgart, Germany
dimas wrote:
According to what you see, yes, Customer gets loaded. And according to what I know this should not happen.

Could you please paste here code which you have between factory.openSession() and close() ?


Ok, here comes some code:


Code:
        Configuration cfg = new Configuration();
        //cfg.addClass(com.iag.Product.class);
        cfg.addClass(com.iag.ProductOrder.class);
        cfg.addClass(com.iag.Customer.class);

        SessionFactory sessions = cfg.buildSessionFactory();
        Session session = sessions.openSession();

        Transaction tx = session.beginTransaction();
        ProductOrder o = null;

        Query query = session.createQuery("select ProductOrder from com.iag.ProductOrder " +
                                          "as ProductOrder");
        System.out.println("\nFollowing ProductOrders found:");
        for (Iterator it = query.iterate(); it.hasNext();)
        {
           o = (ProductOrder)it.next();

           String msg = String.valueOf(o.getNo());

           boolean flag = true;

           if (flag)
           {
              // "getText()" has nothing to do with the "Customer".
              msg = msg + ", Text: " + o.getText();
           }
           else
           {
              msg = msg + ", Customer: " +
                 ((o.getCustomer() == null) ? "Not set" : o.getCustomer().getName());
           }

          System.out.println(msg);
        }

        session.close();



What do I have to set in the mapping file, that if flag==true only the abributes of class
ProductOrders are fetched from db? Right now the Customer is fetched as well in
any case.

If I comment out the hole if-else part, then only the ProductOrder Constructor is called,
noting else. So this is as expected.

Btw: Im using hibernate 2.1 rc1


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 04, 2003 4:20 am 
Expert
Expert

Joined: Tue Sep 16, 2003 4:06 pm
Posts: 318
Location: St. Petersburg, Russia
Very strange. I just checked similar code with my classes - everything work as expected.

Quote:
If I comment out the hole if-else part, then only the ProductOrder Constructor is called, noting else.


What happens if you replace if-else part with just

Code:
   o.getText();


? Does Customer get initialized? If yes, could you please paste getText() here? I do not believe it is just plain getter :)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 04, 2003 4:30 am 
Newbie

Joined: Wed Dec 03, 2003 11:15 am
Posts: 13
Location: Stuttgart, Germany
dimas wrote:
Very strange. I just checked similar code with my classes - everything work as expected.

Quote:
If I comment out the hole if-else part, then only the ProductOrder Constructor is called, noting else.


What happens if you replace if-else part with just

Code:
   o.getText();


? Does Customer get initialized? If yes, could you please paste getText() here? I do not believe it is just plain getter :)


Just doing
Code:
o.getText();
leads to the unwanted behaviour that the Customer
object is created as well.

Here the complete ProductOrder code:
Code:
   
public class ProductOrder
{
   private static final boolean DEBUG = true;
   private static final boolean DEBUG2 = true;
   private int clNo;
   private int clProduct_Category;
   private int clProduct_ID;
   private Customer clCustomer; // instead of "customer_id"
   private String clText;
   private int clModified;

public ProductOrder(int no, int category, int product_id, String text)
   {
      clNo = no;
      clProduct_Category = category;
      clProduct_ID = product_id;
      clCustomer = null;
      clText = text;
      clModified = 0;
      if (DEBUG)
         System.out.println("Constructor ProductOrder: " + clNo + ", " +
                            clProduct_Category + ", " + clProduct_Category + ", " +
                            clText + ", " + clModified);
   }

   public ProductOrder()
   {
      this(-1, -1, -1, null);
   }

   protected void finalize()
   {
      if (DEBUG)
         System.out.println("Destructor ProductOrder: " + clNo + ", " + clProduct_Category +
                            ", '" + clProduct_ID + "'");
   }

   public void setNo(int no)
   {
      clNo = no;
      if (DEBUG2)
         System.out.println("ProductOrder::setNo: " + clNo);
   }

   public int getNo()
   {
      if (DEBUG2)
         System.out.println("ProductOrder::getNo: " + clNo);
      return clNo;
   }

   public void setProductCategory(int category)
   {
      clProduct_Category = category;
      if (DEBUG2)
         System.out.println("ProductOrder::setCategory: " + clProduct_Category);
   }

   public int getProductCategory()
   {
      if (DEBUG2)
         System.out.println("ProductOrder::getProductCategory: " + clProduct_Category);
      return clProduct_Category;
   }
   public void setProductID(int id)
   {
      clProduct_ID = id;
      if (DEBUG2)
         System.out.println("ProductOrder::setID: " + clProduct_ID);
   }

   public int getProductID()
   {
      if (DEBUG2)
         System.out.println("ProductOrder::getID: " + clProduct_ID);
      return clProduct_ID;
   }

   public void setCustomer(Customer c)
   {
      clCustomer = c;
      if (DEBUG2)
      {
         if (clCustomer == null)
            System.out.println("ProductOrder::setCustomer: null");
         else
            System.out.println("ProductOrder::setCustomer: " + clCustomer.getName());
      }
   }

   public Customer getCustomer()
   {
      if (DEBUG2)
      {
         if (clCustomer == null)
            System.out.println("ProductOrder::getCustomer: null");
         else
            System.out.println("ProductOrder::getCustomer: " + clCustomer.getName());
      }
      return clCustomer;
   }

   public void setText(String text)
   {
      clText = text;
      if (DEBUG2)
         System.out.println("ProductOrder::setText: " + clText);
   }

   public String getText()
   {
      if (DEBUG2)
         System.out.println("ProductOrder::getText: " + clText);
      return clText;
   }

   public void setModified(int mod)
   {
      clModified = mod;
   }

   public int getModified()
   {
      return clModified;
   }
}


I would guess that the reason for this behaviour is because of some missing/wrong
statements in one of my mapping files (see my first posting to this topic).


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 04, 2003 6:46 am 
Expert
Expert

Joined: Tue Sep 16, 2003 4:06 pm
Posts: 318
Location: St. Petersburg, Russia
Code:
    public void setCustomer(Customer c)
    {
...
                System.out.println("ProductOrder::setCustomer: " + [b]clCustomer.getName()[/b]);

...
    }


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 04, 2003 7:08 am 
Newbie

Joined: Wed Dec 03, 2003 11:15 am
Posts: 13
Location: Stuttgart, Germany
dimas wrote:
Code:
    public void setCustomer(Customer c)
    {
...
                System.out.println("ProductOrder::setCustomer: " + [b]clCustomer.getName()[/b]);

...
    }


Ok, my fault. If ProductOrder is initialized because of calling
Code:
getName()
or whatever,
then an proxy-Customer class is given as parameter for the
Code:
setCustomer()
method.

I can call
Code:
clCustomer.getID()
in this method without to initiate the retrieval of the complete customer-data from db, like it should be.

Thx and regards,
noips


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 13 posts ] 

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.