-->
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.  [ 2 posts ] 
Author Message
 Post subject: Stumped on how to implement derived object properties
PostPosted: Fri Jun 04, 2010 5:00 pm 
Newbie

Joined: Tue Feb 23, 2010 3:10 pm
Posts: 2
Hi,

I'm working on an application where 1 java object has a series of read-only derived properties. The object is a phone number; so in addition to the usual properties you'd expect a phone number to have (country dial code, npa number, exchange number and station) it also has some properties that deal with geographic location. In other words, based on the format of the phone number, I'm using a series of database tables to figure out where in the world that phone number is.

I have a fairly lengthy but efficient sql query that allows me to do this. The problem I'm now having is telling Hibernate that my DID object (a DID is a phone number) has some additional properties that aren't present in the main table but instead need to be calculated at query time.

I understand that Hibernate allows you to stuff custom sql inside a formula for specific properties. I don't want to use this because I have about 12 derived properties (city, country, state, country, toll free, etc). If I need to copy the geo-location logic inside each formula, Hibernate would have run the whole query to figure out where a phone numbers is 12 times and that wouldn't be very efficient.

My initial thought was that I could simply use custom sql inside the Hibernate mapping file to tell Hibernate how to load an object and set the derived properties to be insert=false and update=false; like so:

Hibernate mapping file:

Code:
<hibernate-mapping>
    <class name="com.acmecorp.didmanager.shared.model.DID" table="tpn_did_pool" catalog="agile">
        <id name="id" type="java.lang.Long">
            <column name="id"/>
            <generator class="identity" />
        </id>
        <many-to-one name="account" class="com.acmecorp.didmanager.shared.model.Account" fetch="join">
           <column name="account_id"/>
        </many-to-one>
       <many-to-one name="csa" class="com.acmecorp.didmanager.shared.model.CSA" fetch="join">
          <column name="csa_id"/>
       </many-to-one>
       <many-to-one name="carrier" class="com.acmecorp.didmanager.shared.model.Carrier" fetch="join">
          <column name="carrier_id"/>
       </many-to-one>
       <property name="countryDialCode" type="int" not-null="true">
          <column name="country_code"/>
       </property>
        <property name="npa" type="string" not-null="true">
           <column name="npa"/>
        </property>
        <property name="nxx" type="string" not-null="true">
           <column name="nxx"/>
        </property>
        <property name="station" type="string" not-null="true">
           <column name="station"/>
        </property>
        <property name="dateReserved" type="java.lang.Long">
           <column name="date_reserved"/>
        </property>
        <property name="portStatus" type="string">
           <column name="port_status"/>
        </property>
        <property name="cname" type="string">
           <column name="cname"/>
        </property>
        <property name="notes" type="string">
           <column name="notes"/>
        </property>
        <property name="city" lazy="true" insert="false" update="false" type="string"/>
        <property name="county" lazy="true" insert="false" update="false"  type="string"/>
        <property name="stateCode" lazy="true" insert="false" update="false"  type="string"/>
        <property name="stateName" lazy="true" insert="false" update="false"  type="string"/>
        <property name="countryCode" lazy="true" insert="false" update="false"  type="string"/>
        <property name="countryName" lazy="true" insert="false" update="false"  type="string"/>
        <property name="tollFree" lazy="true" insert="false" update="false"  type="boolean"/>
        <property name="active" lazy="true"  insert="false" update="false" type="boolean"/>
        <property name="sacService" lazy="true" insert="false" update="false"  type="boolean"/>
        <property name="localUse" lazy="true" insert="false" update="false"  type="boolean"/>
        <loader query-ref="did"/>
    </class>
    <sql-query name="did">
       <return alias="did" class="com.acmecorp.didmanager.shared.model.DID">
          <return-property name="id" column="id"/>
          <return-property name="account" column="account_id"/>
          <return-property name="csa" column="csa_id"/>
          <return-property name="carrier" column="carrier_id"/>
          <return-property name="countryDialCode" column="country_dial_code"/>
          <return-property name="npa" column="npa"/>
          <return-property name="nxx" column="nxx"/>
          <return-property name="station" column="station"/>
          <return-property name="dateReserved" column="date_reserved"/>
          <return-property name="portStatus" column="port_status"/>
          <return-property name="cname" column="cname"/>
          <return-property name="notes" column="notes"/>
          <return-property name="city" column="city"/>
          <return-property name="county" column="county"/>
          <return-property name="stateCode" column="state_code"/>
          <return-property name="stateName" column="state_name"/>
          <return-property name="countryCode" column="country_code"/>
          <return-property name="countryName" column="country_name"/>
          <return-property name="tollFree" column="toll_free"/>
          <return-property name="active" column="active"/>
          <return-property name="sacService" column="sac_service"/>
          <return-property name="localUse" column="local_use"/>
       </return>
       select   
         pool.id,
         pool.account_id,
         pool.csa_id,
         pool.carrier_id,
         pool.country_code as country_dial_code,
         pool.npa,
         pool.nxx,
         pool.station,
         pool.date_reserved,
         pool.port_status,
         pool.cname,
         pool.notes,
         group_concat(DISTINCT loc.city ORDER BY loc.city) as city,
         group_concat(DISTINCT loc.county ORDER BY loc.county) as county,
         group_concat(DISTINCT state.state_code ORDER BY state.state_code) as state_code,
         group_concat(DISTINCT state.state_name ORDER BY state.state_name) as state_name,
         group_concat(DISTINCT country.country_code ORDER BY country.country_code) as country_code,
         group_concat(DISTINCT country.country_name ORDER BY country.country_name) as country_name,
         (CASE WHEN nxx_match.toll_free IS NOT NULL THEN nxx_match.toll_free
               WHEN npa_match.toll_free IS NOT NULL THEN npa_match.toll_free
               ELSE 0
         END) as toll_free,
         (CASE WHEN nxx_match.active IS NOT NULL THEN nxx_match.active
             WHEN npa_match.active IS NOT NULL THEN npa_match.active
             WHEN country_match.active IS NOT NULL THEN country_match.active
             ELSE 0
         END) as active,
            
         (CASE WHEN nxx_match.sac_service IS NOT NULL THEN nxx_match.sac_service
             WHEN npa_match.sac_service IS NOT NULL THEN npa_match.sac_service
         END) as sac_service,
              
         (CASE WHEN nxx_match.local_use IS NOT NULL THEN nxx_match.local_use
             WHEN npa_match.local_use IS NOT NULL THEN npa_match.local_use
         END) as local_use
         
         FROM tpn_did_pool pool
            
         LEFT JOIN tpn_did_location_mapping nxx_match
         on pool.country_code = nxx_match.country_dial_code
         AND pool.npa = nxx_match.npa
         and pool.nxx = nxx_match.nxx
         
         LEFT JOIN tpn_did_location_mapping npa_match
         on pool.country_code = npa_match.country_dial_code
         AND pool.npa = npa_match.npa
         and npa_match.nxx is null
         
         LEFT JOIN tpn_did_location_mapping country_match
         on pool.country_code = country_match.country_dial_code
         AND country_match.npa is null
         AND country_match.nxx is null
                
         LEFT JOIN tpn_did_countries country
         ON country.id =
         (CASE WHEN nxx_match.country_id IS NOT NULL THEN nxx_match.country_id
             WHEN npa_match.country_id IS NOT NULL THEN npa_match.country_id
             WHEN country_match.country_id IS NOT NULL THEN country_match.country_id
             ELSE null
         END)
         
         LEFT JOIN tpn_did_states state
         ON state.id =
         (CASE WHEN nxx_match.state_id IS NOT NULL THEN nxx_match.state_id
             WHEN npa_match.state_id IS NOT NULL THEN npa_match.state_id
             ELSE null
         END)
         
         LEFT JOIN tpn_did_locations loc
         ON loc.id =
         (CASE WHEN nxx_match.location_id IS NOT NULL THEN nxx_match.location_id
             WHEN npa_match.location_id IS NOT NULL THEN npa_match.location_id
             WHEN country_match.location_id IS NOT NULL THEN country_match.location_id
             ELSE NULL
         END)
         
         WHERE pool.id = ?
         
         GROUP BY 
         country_dial_code,
         npa,
         nxx,
         station
    </sql-query>
</hibernate-mapping>


This works - I can fetch individual DIDs; and I can even create new ones and persist them to the database. The problems begin when I try to search for a DID by using a criteria-driven Hibernate query. As soon as I do that, Hibernate seems to default back to the normal table description and ignore the custom sql; because it starts complaining that the derived properties do not exist in the tpn_did_pool table (and indeed, they don't); i.e.:

Code:
java.sql.SQLException: Unknown column 'this_.city' in 'field list'


I guess I'm confused about the purpose of using custom SQL for loading Hibernate objects - what's the point if you can't query against them?

So how exactly do you solve this problem? This has to be a fairly common requirement: how do you write a Hibernate mapping file for an object where not every property of that object is mapped directly to a column in the database?


Top
 Profile  
 
 Post subject: Re: Stumped on how to implement derived object properties
PostPosted: Thu Jun 17, 2010 8:11 am 
Beginner
Beginner

Joined: Wed Aug 24, 2005 5:32 am
Posts: 23
Hi,
I once posted in my blog a tactic to avoid multiple formula calculations using views. It doesn't always the right answer for your needs but you can try and take a look on it in http://blog.eyallupu.com/2009/07/hibernate-derived-properties.html

Eyal

_________________
-----------
Eyal Lupu
Blog:http://blog.eyallupu.com/
(Old blog: http://www.jroller.com/eyallupu)


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