-->
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.  [ 10 posts ] 
Author Message
 Post subject: Problem with CreateQuery and question with .NET REMOTING
PostPosted: Sun Apr 23, 2006 11:28 am 
Newbie

Joined: Thu Mar 16, 2006 12:35 pm
Posts: 17
Need help with Hibernate? Read this first:
http://www.hibernate.org/ForumMailingli ... AskForHelp

Hibernate version:
1.0.5000.0
Mapping documents:
<hibernate-mapping xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:nhibernate-mapping-2.0">

<class name="mapping.Country, mapping" table="country">
<id name="id" column="id_country" unsaved-value="0">
<generator class="sequence" />
</id>
<property name="name" column="name"/>
<set lazy="true" name="regions" inverse="true" access="NHibernate.Generics.GenericAccessor, NHibernate.Generics">
<key column="region_id"/>
<one-to-many class="mapping.Region,mapping"/>
</set>
</class>
</hibernate-mapping>

<hibernate-mapping xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:nhibernate-mapping-2.0">
<class name="mapping.Region, mapping" table="region">
<id name="id" column="id_region" unsaved-value="0">
<generator class="sequence" />
</id>
<property name="name" column="name"/>
<many-to-one name="country"
access="NHibernate.Generics.GenericAccessor, NHibernate.Generics"
class="mapping.Country, mapping"
column="region_id"
not-null="true"/>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():

Full stack trace of any exception that occurs:

Exception non gérée : NHibernate.QueryException: unexpected token: as [select c from count
ry as c]
à NHibernate.Hql.FromParser.Token(String token, QueryTranslator q)
à NHibernate.Hql.ClauseParser.Token(String token, QueryTranslator q)
à NHibernate.Hql.PreprocessingParser.Token(String token, QueryTranslator q)
à NHibernate.Hql.ParserHelper.Parse(IParser p, String text, String seperators, QueryTra
nslator q)
à NHibernate.Hql.QueryTranslator.Compile()
à NHibernate.Hql.QueryTranslator.Compile(ISessionFactoryImplementor factory, IDictionar
y replacements, Boolean scalar)
à NHibernate.Impl.SessionFactoryImpl.GetQuery(String queryString, Boolean shallow)
à NHibernate.Impl.SessionImpl.GetQueries(String query, Boolean scalar)
à NHibernate.Impl.SessionImpl.Enumerable(String query, QueryParameters parameters)
à NHibernate.Impl.QueryImpl.Enumerable()
à mapping.NHDBMgr.getAllCountry() dans C:\Documents and Settings\a.UNICORNI-24064D\Mes
documents\Visual Studio 2005\Projects\mapping\mapping\NHDBMgr.cs:ligne 195
à mapping.Program.Main(String[] args) dans C:\Documents and Settings\a.UNICORNI-24064D\
Mes documents\Visual Studio 2005\Projects\mapping\mapping\Program.cs:ligne 25
Name and version of the database you are using:
Oracle version 10g
The generated SQL (show_sql=true):

Debug level Hibernate log excerpt:
DEBUG

Hello

I have a problem with this code :
Code:
        public ArrayList getAllCountry()
        {
            ArrayList a = null;

            _session = _factory.OpenSession();   
            _transaction = _session.BeginTransaction();

            IQuery query = _session.CreateQuery("select c from country as c");
            foreach (Country c in query.Enumerable())
            {
                a.Add(c);
            }
            _transaction.Commit();
              _session.Close();

              return a;

        }


I just want to select and retrieve all country in the table country. What is wrong ? How can I do that ?

Another question :

I use NHibernate in a distributed environnement with a .NET REMOTING server that use NHibernate and expose methods to .NET REMOTING clients that return business object.

Sometimes I need to return an instance of Country to clients without loading Regions and Peoples collections that are in the Country class. How to load only when needed each collection ?

I am obliged to create methods like getCountry(idCountry, boolLoadRegions, boolLoadPeople) where boolLoadRegions when is set to true init the Region collection in Country and where boolLoadPeople when is set to true init the People collection in Country or can I do that in another way ?

The problem is that I can't keep the session open and so when a client get a Country he can't access the Region collection for example because the session is close !

Thanks in advance for helping me to correct the first problems and saying me if my approch is good.
[/code]


Top
 Profile  
 
 Post subject:
PostPosted: Sun Apr 23, 2006 12:20 pm 
Expert
Expert

Joined: Tue Aug 23, 2005 5:52 am
Posts: 335
Beware that class names and member names are case sensitive, so your query should read:

Code:
select c from Country c


Note the capital 'C' on 'Country'.

Or better yet, this can be simplified to...

Code:
from Country


...since your query doesn't actually need to refer to the alias. If you were going to retrieve something more specific you'd still need it - for example:

Code:
select c.name from Country c


but if you're just after the whole object and don't have any criteria then a simple 'from [classname]' is sufficient.

As for your approach with getting the regions, it's the recommended approach that collections be lazy if not always required and that you explicitly initialize them if they're needed and you have to close the session. In other words, I think your solution is essentially correct. You can change your query to use the "join fetch" or initialize the actual properties by touching them or using the static NHibernate.Initialize method.

Hope that helps!

Symon.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Apr 23, 2006 12:26 pm 
Newbie

Joined: Thu Mar 16, 2006 12:35 pm
Posts: 17
thanks for your help ! It solve my problem !


Top
 Profile  
 
 Post subject:
PostPosted: Sun Apr 23, 2006 4:59 pm 
Newbie

Joined: Thu Mar 16, 2006 12:35 pm
Posts: 17
I re explain my precedent question :

If I have a Country class that contain a collection of Regions and People because in a country are many Region and many People and in the People class I have a collection of Bird because each people has some bird (for example).

In my distributed architecture I will need to make a method like getCountry(idCountry, boolLoadRegions, boolLoadPeople) to retrieve a Country with his ID and know if I must load lazy collection (Region and People). But after the client has the Country that load the collection of People (for example) the client will need (for example) the bird collection for each People in the Region. So I will be obliged to create a method getPeople(idPeople, boolLoadBird) that will enable me to get for each People the Bird collection.


Can I make that easier ?

How to load lazy collections only when the clients access a collection without creating method for loading Collections by specifying a parameter like boolLoadRegions and without keeping the Session always open ?

Thanks in advance ...


Top
 Profile  
 
 Post subject:
PostPosted: Sun Apr 23, 2006 5:07 pm 
Expert
Expert

Joined: Tue Aug 23, 2005 5:52 am
Posts: 335
When the session that loaded the entity, (Country, Person, Bird, whatever) has closed the entity becomes transient. Once it's transient it's not possible to access lazy associations, so if you need to access them then you need to make the object persistent again.

You can re-attach the entity (making it persistent) using the Update or SaveOrUpdate method on a new session. This will associate the entity with the new session and will update any changes made in the entity to the database, but will also allow you to access it's lazy associations.

Cheers,

Symon.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Apr 23, 2006 5:19 pm 
Newbie

Joined: Thu Mar 16, 2006 12:35 pm
Posts: 17
ok but with my code

Code:
        public ArrayList getAllCountry()
        {
            ArrayList a = null;

            _session = _factory.OpenSession();   
            _transaction = _session.BeginTransaction();

            IQuery query = _session.CreateQuery("select c from country as c");
            foreach (Country c in query.Enumerable())
            {
                a.Add(c);
            }
            _transaction.Commit();
              _session.Close();

              return a;

        }


here I close the session after the work is done but after if the client want to access to the Region colletion in Country, how to enable that without creation a new method like getCountry(idCountry, boolLoadRegions) ?

I have understand what you said but I don't know how to code that .

You say that I need to re-attache the entite by using Update or SaveOrUpdate on a new session ok but if I get a loop through the collection of Country return by the method getAllCountry().

How to open a new session in the client in order to get the collection of Region in each Country without creating a new method or without adding code in the client ?

For example if I do that in the server :

Code:
ArrayList allCountry = getAllCountry();

foreach( Country c in allCountry ){
  int nbRegions = c.regions.Count;
}


It will throw an error because I try to access to the number of a Region in the Country without having a session open for the current Country in the loop. So how to open the session automaticelly when the client access to a collection in order to load lazy collection ?

Thanks for explications ...


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 24, 2006 3:18 am 
Expert
Expert

Joined: Tue Aug 23, 2005 5:52 am
Posts: 335
Actually, I don't have any great answers for you on that one. This is a very common question - many people want automatic reconnection for lazy loading - but it isn't there I personally haven't implemented anything myself.

One suggestion is to do your mappings to private fields and have logic in your property getters to check whether the associated entity is lazy. If it is then to associate the entity temporarily to a session (an existing one on the thread or by creating a new one explicitly for this purpose) and re-attach the object there so that lazy loading is possible.

The posultated reason for not doing this automatically in NH is that it introduces ad-hoc transaction semantics, but if that's not a problem for you then why not do it anyway? You'll just have to do the coding by hand.

There have been several threads on this over time - do a search on the forums and you'll see better arguments than mine!

Cheers,

Symon.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 25, 2006 1:31 pm 
Newbie

Joined: Thu Mar 16, 2006 12:35 pm
Posts: 17
ok ...

Now I have another question :

I have a class Country and Region. A Region belong to a Country and a Country has a collection of Region (relation many to one).

The problem is that when I add my new Region in the collection of Region in the Country object without loading the lazy collection of Region in the Country object the new Region is not saved in the database but no error are throw.

I don't want to load all Region in Country object just for adding an object in his collection. It make no cense.

So how to add an object into a collection without loading the lazy collection ?

Thanks in advance


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 25, 2006 7:45 pm 
Beginner
Beginner

Joined: Wed Oct 05, 2005 5:35 am
Posts: 47
Location: France
Well, since it's mapped as a Set I'd say, without much thinking, that you'd have to load your collection before you can add an item to it, since set can't have duplicates...

... a Bag would be even "worse", mind. Since it would require the whole collection to be re-created (if I remember properly - stopped using Bags a while ago).


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 26, 2006 3:04 am 
Expert
Expert

Joined: Tue Aug 23, 2005 5:52 am
Posts: 335
Actually, you should be able to add a new element to a bag that's an inverse collection without initializing it first. From the documentation:

Quote:
Just before you ditch bags forever, there is a particular case in which bags (and also lists) are much more performant than sets. For a collection with inverse="true" (the standard bidirectional one-to-many relationship idiom, for example) we can add elements to a bag or list without needing to initialize (fetch) the bag elements! This is because IList.Add() or IList.AddRange() must always succeed for a bag or IList (unlike a Set).


Cheers,

Symon.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 10 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.