-->
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.  [ 3 posts ] 
Author Message
 Post subject: Problem retrieving a collection (many-to-one relation)
PostPosted: Fri Feb 09, 2007 12:00 pm 
Newbie

Joined: Fri Feb 09, 2007 11:06 am
Posts: 3
I'm having a problem using NHibernate (1.0.4.0) with SQL Server 2005.

Sorry for the size of this post, but i think you can help me better with more information than with less.

The problem is: I have a table named Page, that is accessed by users. Thus, I log all the accesses in the Access table. The pages belong to a site, so I have also a table named Site.

Here is the SQL code for this:

Code:
create table site(
   url nvarchar(50) constraint pk_site primary key,
)

create table page(
   filepath nvarchar(50),
   url nvarchar(50) constraint fk_page_site foreign key references site(url),
   constraint pk_page primary key (filepath, url)
)

create table access(
   date datetime,
   url nvarchar(50),
   filepath nvarchar(50),
   constraint fk_access_page foreign key (filepath, url) references page(filepath, url),
   constraint pk_access primary key (date, url, filepath)
)


Thus, the Access table has a composite primary key, composed by a datetime and a composite foreign key for the table Page. The Page table has a composite primary key, composed by its relative path and the url of the associated site. This means that both Access and Page are 'weak entities'.

The C# classes look like the following:

Code:
public class Site{
  private string url;
  private IList pages;

  public string Url{
    get{return url;}
  }
  public IList Pages{
    get{return pages;}
  }
}


public class Page{
  private string filepath;
  private Site site;
  private IList accesses;

  public string Filepath{
    get{return filepath;}
  }
  public Site Site{
    get{return site;}
  }
  public IList Accesses{
    get{return accesses;}
  }
}


public class Access{
  private DateTime date;
  private Page page;

  public DateTime Date{
    get{return date;}
  }
  public Page Page{
    get{return page;}
  }
}


Nothing special about that. Site and Page are connected in both directions, just like Page and Access. (Note that I have omitted the constructors for brevity. I know that it has to have at least a no-arg constructor).

Now the mapping files:

Site.hbm.xml
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
  <class name="Site" table="site">
     <id name="url" column="url" type="String" length="50" access="field">
       <generator class="assigned" />
     </id>
    <bag name="pages" inverse="true" lazy="true" order-by="filepath" cascade="all" access="field">
      <key column="url" />
      <one-to-many class="Page" />
    </bag>
  </class>
</hibernate-mapping>



Page.hbm.xml
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
  <class name="Page" table="page">
    <composite-id>
      <key-many-to-one name="site" column="url" class="Site" access="field" />
      <key-property name="filepath" column="filepath"  type="string" length="50" access="field" />
    </composite-id>
    <bag name="accesses" inverse="true"  order-by="date" lazy="true" cascade="all" access="field">
      <key>
        <column name="url" />
        <column name="filepath" />
      </key>
      <one-to-many class="Access" />
    </bag>
  </class>
</hibernate-mapping>



Access.hbm.xml
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
  <class name="Access" table="access">
    <composite-id>
      <key-property name="date" column="date" type="DateTime" access="field" />
      <key-many-to-one class="Page" name="page" access="field">
        <column name="url" not-null="true" length="50"/>
        <column name="filepath" not-null="true" length="50"/>
      </key-many-to-one>
    </composite-id>
  </class>
</hibernate-mapping>


For testing this, i have the following test code to populate the database:

Code:
Configuration cfg = new Configuration();
cfg.AddAssembly("CoolNHibernateDAL");

ISessionFactory factory = cfg.BuildSessionFactory();
ISession session = factory.OpenSession();
         
DateTime date = DateTime.Now;
string url = "http://nhibernate.test.com";
string filepath = "/xpto/xptu.html";

Site site = new Site(domainUrl);
Page page = new Page(site, filepath);
Access access = new Access(date, page);

session.Save(site);
session.Save(page);
session.Save(access);

session.Flush();
session.Close();


If I manually query the database, i can se those values there, so it seems good.
The problem is when i try to retrieve the values using NHibernate, which i do with the following code (assume that i've open the session, like i did previously):

Code:
Site site = session.Load(typeof(Site), url) as Site;
IList pages = site.Pages;
Page page = new Page(site, filepath);
session.Load(page, page);
IList accesses = page.Accesses;
Access access = new Access(date, page);
session.Load(access, access);



This all works well, with one exception: the line " IList accesses = page.Accesses;". The accesses IList is returned with a count of 0, when it has to have one element! All the other values are retrieved successfuly (including the collection pages).

There are two lines int this last piece of code, that I "don't like", and that were the only way I found for loading the page and the access:

Code:
session.Load(page, page);
session.Load(access, access);


Given the fact that both relations have a composite id, and all the Session.Load methods accept one (and only one) id object, i didn't found another way for doing it.

So, the questions i have are:

- Is that other way for getting the page and access values, without passing a reference to the page/access object in the id place?

- Why can't I retrieve the accesses collection? Why it return always 0?

I hopefully expect that you could help me with this "nasty" problem.

Thanks for the time reading this!


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 09, 2007 2:43 pm 
Contributor
Contributor

Joined: Sat Sep 24, 2005 11:25 am
Posts: 198
Turn on SQL logging (use hibernate.show_sql = true) and check what queries it generates.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Feb 10, 2007 12:08 pm 
Newbie

Joined: Fri Feb 09, 2007 11:06 am
Posts: 3
Well, NHibernate is generating lots of queries when I access to the "accesses" collection.

Here are the queries:


First Query
Code:
NHibernate:

SELECT accesses0_.url as url__, accesses0_.filepath as filepath__, accesses0_.date as date__, accesses0_.date as date0_, accesses0_.url as url0_, accesses0_.filepath as filepath0_
FROM access accesses0_
WHERE accesses0_.url=@p0 and accesses0_.filepath=@p1 ORDER BY accesses0_.date

@p0 = 'http://nhibernate.test.com'
@p1 = '/xpto/xptu.html'


First it queries the DB for the accesses collection, parameterized with the foreign key for Page (url and filepath), and it even order for date,just like it is in the xml config file. The only thing I think is strange here is that it select the date, url and filepath two times:

Code:
SELECT accesses0_.url as url__, accesses0_.filepath as filepath__, accesses0_.date as date__, accesses0_.date as date0_, accesses0_.url as url0_, accesses0_.filepath as filepath0_



Second Query
Code:
NHibernate:

SELECT page0_.url as url0_, page0_.filepath as filepath0_
FROM page page0_
WHERE page0_.url=@p0 and page0_.filepath=@p1

@p0 = 'http://nhibernate.test.com'
@p1 = '/xpto/xptu.html'


Here it retrieves the page from which i've asked for the accesses collection. I don't know why.


Third Query
Code:
NHibernate:

SELECT page0_.url as url0_, page0_.filepath as filepath0_
FROM page page0_
WHERE page0_.url=@p0 and page0_.filepath=@p1

@p0 = 'http://nhibernate.test.com'
@p1 = '/xpto/xptu.html'


This third query is equal to the second...


Fourth Query
Code:
NHibernate:

SELECT access0_.date as date0_, access0_.url as url0_, access0_.filepath as filepath0_
FROM access access0_
WHERE access0_.date=@p0 and access0_.url=@p1 and access0_.filepath=@p2

@p0 = '10-02-2007 15:47:17'
@p1 = 'http://nhibernate.test.com'
@p2 = '/xpto/xptu.html'


Here it queries the database for the Access that i've put there, for its primary key (date included). The date in this last query is the date that is in the database. That is: this query must return the access in the db.



If it only has made the first query, my accesses collection must have one element, the element that is in the database. But in fact, the collection is empty!

Anyone knows what's happening?


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