-->
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.  [ 8 posts ] 
Author Message
 Post subject: newbie - need a little help with mapping and constraints
PostPosted: Fri Mar 04, 2005 7:49 am 
Newbie

Joined: Fri Mar 04, 2005 7:10 am
Posts: 12
trying to familiarise myself with with eclipse and hibernate.

I am running the jboss eclipse build with hibernate r3b4.

couple of issues.

1 I am trying to use inheritance with with concrete table per subclass (union-subclass) and an abstract base class.

my database is MySQL 4.1

I have tried to create an asbtract base class with generator = increment defined in the base, and a concrete subclass that inherits.

here is the mapping file


Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<!--

  This mapping demonstrates how to use a composite
  element mapping to model a parent/child association.
     
-->

<hibernate-mapping package="inventory">
   
   <class name="Element" table="Element" abstract="true">
      <id name="id" type = "long" column="ID" unsaved-value="0" >
         <generator class="increment"/>
      </id>

      <version name="version"
                 type="int"
                 column="version"/>
                 
      <property name="key" type = "java.lang.Long" column="uniqueKey" unique="true" update="false" access="field"/>
      <property name="name" type = "java.lang.String" column="name" length="100" />
      <property name="nameAlias" type = "java.lang.String" column="nameAlias" length="100" />
      <map name="flexAtt" table="AttVals" cascade="all">
         <key column="id"/>
         <map-key column="attribute" type="java.lang.String"/>
         <element column="value" type="java.lang.String"/>
      </map>

      <union-subclass name="VirtualNetwork" table="VirtualNetwork" extends="Element">
         <property name="bandwidth" type = "java.lang.String" column="bandwidth" length="30"/>
         <property name="VCI" type = "java.lang.String" column="vci" length="30"/>
         <property name="VPI" type = "java.lang.String" column="vpi" length="30"/>
      
      </union-subclass>

   </class>

<!--   
   <dynamic-class entity-name="FlexAttVals">
      <id name="id" type="long" column="ID">
         <generator class="native"/>
      </id>

      <property name="attribute" type = "java.lang.Long" column="attribute" length="50"/>
      <property name="value" type = "java.lang.String" column="value" length="500" />

      <many-to-one name="parent" column="parentID" class="FlexAttVals"/>
      
      <bag name="children" inverse="true" lazy="false" cascade="all">
         <key column="parentID"/>
         <one-to-many class="FlexAttVals"/>
      </bag>
   </dynamic-class> -->

</hibernate-mapping>


when I run the test code I get the following error. Essentially this is trying to access the element table in the DB, where one does not exist as I have declared both the mapping and the java base class to be 'abstract'



Code:
48640 [main] DEBUG org.hibernate.id.IncrementGenerator  - fetching initial value: select max(ID) from Element
48660 [main] DEBUG org.hibernate.util.JDBCExceptionReporter  - could not fetch initial value [select max(ID) from Element]
java.sql.SQLException: Table 'test.element' doesn't exist
   at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2851)
   at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1534)
   at com.mysql.jdbc.ServerPreparedStatement.serverPrepare(ServerPreparedStatement.java:1485)
   at com.mysql.jdbc.ServerPreparedStatement.<init>(ServerPreparedStatement.java:151)
   at com.mysql.jdbc.Connection.prepareStatement(Connection.java:1309)
   at com.mysql.jdbc.Connection.prepareStatement(Connection.java:1281)
   at org.hibernate.id.IncrementGenerator.getNext(IncrementGenerator.java:69)
   at org.hibernate.id.IncrementGenerator.generate(IncrementGenerator.java:43)
   at org.hibernate.event.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:84)
   at org.hibernate.event.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:180)
   at org.hibernate.event.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:169)
   at org.hibernate.event.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:92)
   at org.hibernate.event.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:65)
   at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:466)
   at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:461)
   at persistence.HibernatePersistenceManager.add(HibernatePersistenceManager.java:148)
   at hibernatedemo.DemoDB.main(DemoDB.java:73)
48670 [main] WARN org.hibernate.util.JDBCExceptionReporter  - SQL Error: 1146, SQLState: 42S02
48680 [main] ERROR org.hibernate.util.JDBCExceptionReporter  - Table 'test.element' doesn't exist
Exception in thread "main" java.lang.RuntimeException: could not fetch initial value
   at persistence.HibernatePersistenceManager.add(HibernatePersistenceManager.java:153)
   at hibernatedemo.DemoDB.main(DemoDB.java:73)
Caused by: org.hibernate.exception.SQLGrammarException: could not fetch initial value
   at org.hibernate.exception.ErrorCodeConverter.convert(ErrorCodeConverter.java:70)
   at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
   at org.hibernate.id.IncrementGenerator.getNext(IncrementGenerator.java:90)
   at org.hibernate.id.IncrementGenerator.generate(IncrementGenerator.java:43)
   at org.hibernate.event.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:84)
   at org.hibernate.event.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:180)
   at org.hibernate.event.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:169)
   at org.hibernate.event.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:92)
   at org.hibernate.event.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:65)
   at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:466)
   at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:461)
   at persistence.HibernatePersistenceManager.add(HibernatePersistenceManager.java:148)
   ... 1 more
Caused by: java.sql.SQLException: Table 'test.element' doesn't exist
   at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2851)
   at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1534)
   at com.mysql.jdbc.ServerPreparedStatement.serverPrepare(ServerPreparedStatement.java:1485)
   at com.mysql.jdbc.ServerPreparedStatement.<init>(ServerPreparedStatement.java:151)
   at com.mysql.jdbc.Connection.prepareStatement(Connection.java:1309)
   at com.mysql.jdbc.Connection.prepareStatement(Connection.java:1281)
   at org.hibernate.id.IncrementGenerator.getNext(IncrementGenerator.java:69)
   ... 10 more



The top of this abstract class is declared as

Code:
package inventory;


import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;

public abstract class Element
{

    static Logger logger = Logger.getLogger(Element.class);

    protected long id;      //DB pkey column
    protected long key;    // internal unique key
    protected String name;
    protected String nameAlias;
    protected int version;
    protected Map<String,String> flexAtt = new HashMap<String, String>();

....
   


If I remove the abstract statement from the base class mapping I get two tables created in the DB, however when I run the test code to insert records for the virtual network object (my concrete class) the ID column, in the database pkey is always set to 1, and does not increment which the generator id declaration in the base class should do for me.

The generator works fine for non inherited classes mapped and I get a nice incrementing seq of id for standalone non inherited classes.

2. Second problem is I appear to have misunderstood how the <map> element should work can anyone help.

I have declared a Map element in my base class to hold tags and values, which i wanted inheriated into the concrete sub classes.

in the mapping I set the map to point to the AttVals table, set the key (to be the id field of the owning table, and created the 'attribute' map-key and 'value' element tag.

This appears to create a table okay, however when I build the instances in the code and then persist them with my persistence manager class (pm).

i get a constraint error. Looking at the database table for the attval, the id field is set with a FK constraint pointing to the element table (now that I have had to make this concrete in the mapping). whereas the hash is being used on a subclass and no record is inserted into the element table which i think is causing the error.



Code:
6379 [main] DEBUG org.hibernate.impl.SessionImpl  - after transaction completion
Exception in thread "main" java.lang.RuntimeException: Could not execute JDBC batch update
   at persistence.HibernatePersistenceManager.add(HibernatePersistenceManager.java:153)
   at hibernatedemo.DemoDB.main(DemoDB.java:73)
Caused by: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
   at org.hibernate.exception.ErrorCodeConverter.convert(ErrorCodeConverter.java:74)
   at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
   at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:162)
   at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:226)
   at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:140)
   at org.hibernate.event.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:271)
   at org.hibernate.event.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:24)
   at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:719)
   at persistence.HibernatePersistenceManager.dispose(HibernatePersistenceManager.java:110)
   at persistence.HibernatePersistenceManager.add(HibernatePersistenceManager.java:149)
   ... 1 more
Caused by: java.sql.BatchUpdateException: Cannot add or update a child row: a foreign key constraint fails
   at com.mysql.jdbc.ServerPreparedStatement.executeBatch(ServerPreparedStatement.java:827)
   at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:58)
   at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:155)
   ... 8 more


How can I inherit classes and correctly get a generic map attribute to work through inheritance.

Any help would be greatfully received.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 04, 2005 8:25 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
(1) increment generator does not currently work for union-subclass, I added a more friendly exception (it would be a bit of a pain to make this work, though it *is* possible)

(2) Hibernate DDL export is generating an incorrect fk constraint to superclasses of a union-subclass hierarchy when the superclass is declared non-abstract - however, you should seriously reconsider this data model! It is fundamentally broken, since there is no FK constraint possible. Now, Hibernate can handle it (at least it can handle it apart from the DDL generation), but I would not recommend this.

(3) union-subclass is considered an "exotic" usecase, and does not usually result in quality data models. It is not really for new users. Use one of the other mapping strategies.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 04, 2005 8:39 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
The bug i mentioned in (2) - the incorrect constraint - is now fixed in CVS.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Mar 06, 2005 7:55 pm 
Regular
Regular

Joined: Fri Oct 01, 2004 2:19 am
Posts: 111
Location: Melbourne, Australia
gavin,

you mention the union-subclass as an 'exotic' use case and not for the
faint of heart ;), but how is one supposed to model cases with root
base class (abstract for all but exceptional cases), and subclasses which
define hierarchies of their own?

I have a need to model a similar model to that of woodmawa and
would like to know how to go about this (I've asked this before and you
stated that it should be able to be supported, but I'm not sure whether
this is here and now or in a future release of Hibernate, in which case
I'll need to reconsider Hibernate for the current task)

_________________
Cheers,

Bonny

please don't forget to rate :)


Top
 Profile  
 
 Post subject:
PostPosted: Sun Mar 06, 2005 8:45 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
There is no problem with mapping an abstract superclass as the root of a <subclass> or <joined-subclass> hierarchy, in fact that is quite normal usage.

The advantage of this is that you can have proper foreign key constraints for associations defined by the superclass, which is impossible for <union-subclass>.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Mar 06, 2005 9:13 pm 
Regular
Regular

Joined: Fri Oct 01, 2004 2:19 am
Posts: 111
Location: Melbourne, Australia
gavin,

Thanks for the prompt reply. I've got then a couple more questions:

if I use join-subclass, must I end up with a table for the root class?
This implies that all references to any class would involve at least
one join per type - is this correct? if so what are the performance
implications when trying to load multiple instances of multiple types
(a parent owning multiple children)?

if I use subclass, how do I avoid having all the classes mapped to
the same table?

Basically it boils down to the question of how to map the following
model:
Code:
         Holder <>------>*    Base
                               |
                               |
                 +-------------+-----------+
                 D1            D2          D3
                 |             |           |
                 |             |           |
              +-----+       +-----+     +-----+
              D11   D12     D21   D22   D31   D32


Where Base is abstract, D1..D3 represent subhirarchies mapped each
to a table nad each such table is used with a discriminator to distinguish
between subclasses of each hirarchy root, and Holder maintaining a
collection of polymorphic references to Base.

_________________
Cheers,

Bonny

please don't forget to rate :)


Top
 Profile  
 
 Post subject: other workaround
PostPosted: Mon Mar 07, 2005 9:11 am 
Newbie

Joined: Fri Mar 04, 2005 7:10 am
Posts: 12
Gavin,

Thanks for your help - still thinking my way through various approaches.

perhaps if i just fill in my thinking you might see where I was coming from.

essentially I have about 5 concrete sub class trees for elements (abstract base).

each concrete subtype is sufficiently different (except for pkey id, and possibley a map of flexible attributes) that I created the concrete types such as Bearers, NetworkServices, CPE, VirtualNetwork as distinct concrete classes that could then be additionally subtyped if required.

This was fine but what I wanted was a way to query from the abstract base class for all instances that met a constraint (the example in mind is a TT system that is querying the datamodel for a list of elements (the generic abstraction) where the pkeys across the concerete tables dont clash.

Once an element has been selected, it can then be expanded by correctly querying the element from its proper type, and gtet all the relevant data.

couple of problems here - I am using Mysql to mock this up and it neither supports DB seq nor views.

what i was trying to do in mock up was use the increment generator on the abstract class to generate a single unique pkey in each of the union-subclass types id columns - which didnt work as expected (ps when does the fix you mention get published back into the main release - i'm not i'm brave enough to try a full manual ANT build from CVS - i did try and didnt get it to work so I need to do some more reading to understand this)

In my current work around (given that I am still exploring how hibernate) options map to the database is to chnage the id generator to hilo, and move my flexible attribute mapping into the union-subclasses.

This seems to work at the expense of one flex attribute/value table per subclass

I understand if I went to one table per hierarchy approach i could fix the above, but at the cost of a master element table that has lots of redundant fields within it.

heres the modified mapping that i am now playing with

Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<!--

  This mapping demonstrates how to use a composite
  element mapping to model a parent/child association.
     
-->

<hibernate-mapping package="inventory">
   
   <class name="Element" table="Element" abstract="true">
      <id name="id" type = "long" column="id" unsaved-value="0" >
         <generator class="hilo">
            <param name="table">hi_value</param>
            <param name="column">next_value</param>
            <param name="max_lo">0</param>      
         </generator>
      </id>

      <version name="version"
                 type="int"
                 column="version"/>
                 
      <property name="key" type = "java.lang.Long" column="uniqueKey" unique="true" update="false" access="field"/>
      <property name="name" type = "java.lang.String" column="name" length="100" />
      <property name="nameAlias" type = "java.lang.String" column="nameAlias" length="100" />

      <!--
      <union-subclass name="VirtualNetwork" table="VirtualNetwork" extends="Element">
         <property name="bandwidth" type = "java.lang.String" column="bandwidth" length="30"/>
         <property name="VCI" type = "java.lang.String" column="vci" length="30"/>
         <property name="VPI" type = "java.lang.String" column="vpi" length="30"/>
      
      </union-subclass>
      -->
      <union-subclass name="VirtualNetwork" table="VirtualNetwork" extends="Element">
         <!--<key column="elemID"/> -->
         <property name="bandwidth" type = "java.lang.String" column="bandwidth" length="30"/>
         <property name="VCI" type = "java.lang.String" column="vci" length="30"/>
         <property name="VPI" type = "java.lang.String" column="vpi" length="30"/>
         <map name="flexAtt" table="VNAttVals" cascade="all">
            <key column="id"/>
            <map-key column="attribute" type="java.lang.String"/>
            <element column="value" type="java.lang.String"/>
         </map>
      
      </union-subclass>
   </class>
</hibernate-mapping>


what i have the done is declared an interface that each concrete subclass implements that maps the generic abstraction for the TT system onto the concrete classes in the hierarchy.

havnt actually tried this on the query routine yet to make sure this works


happy to here your additional thoughts on the approach or best way to do this - though I think I can see why you suggested the single table hierarchy as the best fix. I was most worried about the number of redundent records for query tools (which dont know the mapping in java).

I felt it was easier to provide one table per concrete class so that the data could be accessed more readily by reporting developers.

Cheers Will


Top
 Profile  
 
 Post subject: Re: newbie - need a little help with mapping and constraints
PostPosted: Mon Oct 12, 2009 10:40 am 
Newbie

Joined: Mon Oct 12, 2009 9:47 am
Posts: 3
This is in reference to the question posted by bonnyr. It is such a critical thing to know what is being asked here. Why hasn't there been a reply to this? If <union-subclass> mapping is for exotic usecases and <subclass> and <join-class> mapping dont perform well for wide hierarchies. What do we use for domain models that have complex associations.(Where inheritance cannot be replaced with composition/aggregation).

Thanks,
Vinay.


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