-->
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.  [ 5 posts ] 
Author Message
 Post subject: subclass, inverse many-to-one, one-table-per-hierarchy
PostPosted: Wed Mar 03, 2004 4:58 pm 
Beginner
Beginner

Joined: Wed Oct 29, 2003 11:52 am
Posts: 37
Location: Gothenburg, Sweden
The table:
Code:
                               Table "public.networkcables"
     Column     |  Type   |                           Modifiers                           
----------------+---------+---------------------------------------------------------------
id             | integer | not null default nextval('public.networkcables_id_seq'::text)
cabletype      | integer | not null
note           | text    |
connectiontype | integer | not null
computer       | integer |
outlet         | integer |
port           | integer |
downlink       | integer |


This table is supposed to model all network cables in a network. Cables are one of four types: 1) computer->outlet, 2) computer->port, 3) outlet->port or 4) port->port (where one is downlink, and the other uplink=port). The discriminator column is connectionType and discriminator-values are either 1, 2, 3 or 4.

The hibernate mapping file:
Code:
<?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="se.csbnet.nvg.sad.beans.NetworkCable" table="NetworkCables"
               discriminator-value="not null">
                <id name="id" column="id">
                        <generator class="sequence">
                                <param name="sequence">NetworkCables_id_seq</param>
                        </generator>
                </id>
                <discriminator column="connectionType" type="integer" />

                <property name="note" type="text" />

                <many-to-one name="cableType" not-null="true" />

                <subclass name="se.csbnet.nvg.sad.beans.NetworkCableComputerPort"
                          discriminator-value="2">
                        <many-to-one name="computer" />
                        <many-to-one name="port" />
                </subclass>
                <!-- FIXME: three more subclasses to be entered -->
        </class>
</hibernate-mapping>


The mapping seems to work but I can't figure out how to map <many-to-one> relations to these classes. Take this SwitchPort for example:
Code:
<?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="se.csbnet.nvg.sad.beans.SwitchPort" table="SwitchPorts">
                <id name="id" column="id">
                        <generator class="sequence">
                                <param name="sequence">SwitchPorts_id_seq</param>
                        </generator>
                </id>   
                               
                <property name="name" not-null="true" />
                <property name="immortal" not-null="true" />

                <many-to-one name="switch" not-null="true" />
                <many-to-one name="portType" not-null="true" />

                <!-- magic stuff should happen here -->
                <many-to-one name="networkCable" />

        </class>
</hibernate-mapping>


I do understand that the above doesn't work, I just want to know how I can make Hibernate load the darn cable for me. I can't use one-to-one since NetworkCable doesn't have the property port. The one way I guess I could get this working would be to use <set> elements. I'm too tired to test this right now after a long long day.

I greatefully appreciate any help or directions I can get.

Thanks in advance, Fredrik


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 03, 2004 5:07 pm 
Hibernate Team
Hibernate Team

Joined: Thu Dec 18, 2003 9:55 am
Posts: 1977
Location: France
try this

<many-to-one name="networkCable"
column="networkCable???"
class="se.csbnet.nvg.sad.beans.NetworkCable"/>

if i doesn't work give more details about SwitchPorts table

doing SwitchPorts .getNetworkCable() will return a NetworkCable, you have to cast to have the desired subclass...


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 03, 2004 5:23 pm 
Hibernate Team
Hibernate Team

Joined: Thu Dec 18, 2003 9:55 am
Posts: 1977
Location: France
what do you want to do?

1- many switch to one cable ? this is your example --> are you sure?

2- or one (switch) to many (cables), this more logic? i'm not a network expert lol --> for this you have to declare on switch mapping file a bag with a one to many.

All depends of what you wanna do
mySwitch.getCables() --> returns the list of cables connected to your switch
myCable.getSwitch() --> returns the switch the cable is connected to
...

..... please give switch table details, and what you really want to do


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 03, 2004 6:35 pm 
Beginner
Beginner

Joined: Wed Oct 29, 2003 11:52 am
Posts: 37
Location: Gothenburg, Sweden
You really didn't get it, guess I didn't make much sence. :)

Just start imagining a student campus network (~1200 computers).

A Switch has several SwitchPorts in it. (The word Port is rather ambigious in our environment, hence SwitchPort is used.) There can only be one cable plugged in in each SwitchPort. This cable either leads to a Computer, an Outlet (found on the wall) or another SwitchPort (uplink-downlink).

The way it all should be is:
Computer.getCables()::Set - yes it has to be this way since computer are allowed at several positions in the network and some computer's NICs have more than one actual socket/outlet
Outlet.getCables()::Set - yes a user may have his own tiny switch in his/her room, for what we care he/she is connecting several computers to an outlet
SwitchPort.getCable()::NetworkCable - either ComputerPort, OutletPort or PortPort.

The computer and outlet cases are trivial. The issue is the SwitchPort.

I'm guess this is impossible to do with Hibernate so I'm thinking of loading the cable manually. I won't use Hibernate to create cables anyway, so the only issue is to load the darn thing :) I guess implementing LifeCycle and storing the Session in onLoad and then loading the cable "manually" would do the trick?


Top
 Profile  
 
 Post subject: Follow up
PostPosted: Sun Aug 22, 2004 10:49 am 
Beginner
Beginner

Joined: Wed Oct 29, 2003 11:52 am
Posts: 37
Location: Gothenburg, Sweden
The problem is solved, but with terrible performance.

What I failed to describe is that the SwitchPort always has zero or one NetworkCable. I can't map it as a normal one-to-many though, since one of two columns in the table might be set. Example:


We have four types of cables here

Code:
   id   | connectiontype | computer | outlet | port  | downlink
--------+----------------+----------+--------+-------+----------
108526 |              1 |    11111 |  22222 |       |         
This is a cable from a computer to an outlet. Rather straight forward, both ends are Sets.

Code:
   id   | connectiontype | computer | outlet | port  | downlink
--------+----------------+----------+--------+-------+----------
108447 |              3 |          |  33333 | 44444 |         
The outlet in turn is connected to a port. The outlet-end is a Set but the id in the port column may only appear once*.

Code:
   id   | connectiontype | computer | outlet | port  | downlink
--------+----------------+----------+--------+-------+----------
108518 |              2 |    11112 |        | 44445 |         
This is the case we have in server rooms. The computer is connected directly to the port in the switch. The computer-end is a Set but the id in the port column may only appear once*.

Code:
   id   | connectiontype | computer | outlet | port  | downlink
--------+----------------+----------+--------+-------+----------
  92941 |              4 |          |        | 44446 |    44447
This is case where we have uplink/downlink cables between switches. Here we have two SwitchPorts (44446 and 44447) that are connected with the same cable (a NetworkCablePortPort) but they're referenced from two separate columns.

I currently handle both cases (both columns) by implementing LifeCycle in SwitchPort and the getNetworkCable-method looks like this:
Code:
   public NetworkCable getNetworkCable() {
      if (this.networkCable == null) {
         if (!this.cableLoadAttemptPerformed) {
            this.cableLoadAttemptPerformed = true;
            try {
               this.networkCable = CommonTasks.getSwitchPortsNetworkCable(
                           this.session,
                           this.getId());
            } catch (HibernateException he) {
               throw new LazyInitializationException(
                     "Failed to lazily load network cable", he);
            }
         }
      }

      return this.networkCable;
   }


and the method in CommonTasks looks like this:
Code:
   public static NetworkCable getSwitchPortsNetworkCable(Session hibernate, int portId)
   throws HibernateException
   {
      Logger.log(Logger.DEBUG, "getSwitchPortsNetworkCable(" + portId + ")");
      PreparedStatement pstmt = null;
      ResultSet rs = null;
      try {
         // prepare query
         String query = "SELECT c.id FROM NetworkCables c WHERE c.port=? OR c.downlink=?;";
         pstmt = hibernate.connection().prepareStatement(query);
         pstmt.setInt(1, portId);
         pstmt.setInt(2, portId);

         // execute, get id
         Integer id = null;
         rs = pstmt.executeQuery();
         if (rs.next()) {
            id = new Integer(rs.getInt(1));
            if (rs.next()) {
               silentlyClose(null, pstmt, rs);
               throw new HibernateException(
                     "More than one cable found for port with id " + portId + "!");
            }
         }

         // close up
         rs.close();
         pstmt.close();

         // get NetworkCable object and return it
         if (id == null) {
            return null;
         } else {
            return (NetworkCable) hibernate.load(NetworkCable.class, id);
         }
      } catch (SQLException sqle) {
         silentlyClose(null, pstmt, rs);
         Logger.logException(Logger.DEBUG, sqle);
         throw new HibernateException("Failed to find NetworkCable.", sqle);
      } catch (HibernateException he) {
         silentlyClose(null, pstmt, rs);
         Logger.logException(Logger.DEBUG, he);
         throw new HibernateException("Failed to load new NetworkCable.", he);
      }
   }


That's the current implementation but I'm thinking of changing it to map up the SwitchPorts.cable with inverse reference column port and in the getNetworkCable method only look for a cable in the downlink-column if this.cable is null.


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