facebook

hibernate mapping for link tables

  1. MyEclipse Archived
  2.  > 
  3. Database Tools (DB Explorer, Hibernate, etc.)
Viewing 6 posts - 1 through 6 (of 6 total)
  • Author
    Posts
  • #252471 Reply

    ceronj
    Member

    I have the following tables: Meal, Food, MealFoodLink. The MealFoodLink table is a link table linking the other two tables by their respective id’s. I select the three tables in the database explorer and launch the wizard to generate the mappings. The mapping file for the MealFoodLink has the id’s for the other two tables as a one-to-many relationship. When I try to save a meal, which should contain one or more foods, the Meal table is inserted but not the link table. Shouldn’t the mapping be many-to-many? Do you have an example that I can review?

    😕

    #252472 Reply

    Haris Peco
    Member

    ceronj,

    Please send us eclipse/MyEclipse version , database vendor and version and if you can, ‘create table script’, mapping and your code for saving

    Thanks

    #252522 Reply

    ceronj
    Member

    I remove the “catelog=renaissance” tag from the mapping files because saves fail when I leave it.

    
     MyEcllpse version : 4.1.1
    Database: MySQL 4.1.16
    
    TABLE SCHEMA
    
    
    DROP TABLE IF EXISTS `renaissance`.`food`;
    CREATE TABLE  `renaissance`.`food` (
      `id` bigint(20) unsigned NOT NULL auto_increment,
      `name` varchar(100) NOT NULL default '',
      `servingSize` float NOT NULL default '0',
      `servingType` varchar(6) NOT NULL default '',
      `protein` float NOT NULL default '0',
      `carbs` float NOT NULL default '0',
      `fat` float NOT NULL default '0',
      `saturatedFat` float NOT NULL default '0',
      `transFat` float NOT NULL default '0',
      `cholesterol` float NOT NULL default '0',
      `sodium` float NOT NULL default '0',
      `fiber` float NOT NULL default '0',
      `sugars` float NOT NULL default '0',
      `classification` varchar(45) NOT NULL default '',
      PRIMARY KEY  (`id`),
      UNIQUE KEY `idx_1` USING BTREE (`name`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
    
    
    DROP TABLE IF EXISTS `renaissance`.`food_additives`;
    CREATE TABLE  `renaissance`.`food_additives` (
      `code` char(3) NOT NULL default '',
      `name` varchar(45) NOT NULL default '',
      `description` text NOT NULL,
      PRIMARY KEY  (`code`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
    
    
    DROP TABLE IF EXISTS `renaissance`.`foods_additives_link`;
    CREATE TABLE  `renaissance`.`foods_additives_link` (
      `food_id` bigint(20) unsigned NOT NULL default '0',
      `additive_id` char(3) NOT NULL default '',
      PRIMARY KEY  (`food_id`,`additive_id`),
      KEY `FK_contains_additive_2` (`additive_id`),
      CONSTRAINT `FK_contains_additive_1` FOREIGN KEY (`food_id`) REFERENCES `food` (`id`),
      CONSTRAINT `FK_contains_additive_2` FOREIGN KEY (`additive_id`) REFERENCES `food_additives` (`code`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
    
    
    MAPPINGS
    
    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <!-- 
        Mapping file autogenerated by MyEclipse - Hibernate Tools
    -->
    <hibernate-mapping>
        <class name="com.nimble.spider.renaissance.persistence.Food" table="food">
            <id name="id" type="java.lang.Long">
                <column name="id" />
                <generator class="native"></generator>
            </id>
            <property name="name" type="java.lang.String">
                <column name="name" length="100" not-null="true" unique="true" />
            </property>
            <property name="servingSize" type="java.lang.Float">
                <column name="servingSize" precision="12" scale="0" not-null="true" />
            </property>
            <property name="servingType" type="java.lang.String">
                <column name="servingType" length="6" not-null="true" />
            </property>
            <property name="protein" type="java.lang.Float">
                <column name="protein" precision="12" scale="0" not-null="true" />
            </property>
            <property name="carbs" type="java.lang.Float">
                <column name="carbs" precision="12" scale="0" not-null="true" />
            </property>
            <property name="fat" type="java.lang.Float">
                <column name="fat" precision="12" scale="0" not-null="true" />
            </property>
            <property name="saturatedFat" type="java.lang.Float">
                <column name="saturatedFat" precision="12" scale="0" not-null="true" />
            </property>
            <property name="transFat" type="java.lang.Float">
                <column name="transFat" precision="12" scale="0" not-null="true" />
            </property>
            <property name="cholesterol" type="java.lang.Float">
                <column name="cholesterol" precision="12" scale="0" not-null="true" />
            </property>
            <property name="sodium" type="java.lang.Float">
                <column name="sodium" precision="12" scale="0" not-null="true" />
            </property>
            <property name="fiber" type="java.lang.Float">
                <column name="fiber" precision="12" scale="0" not-null="true" />
            </property>
            <property name="sugars" type="java.lang.Float">
                <column name="sugars" precision="12" scale="0" not-null="true" />
            </property>
            <property name="classification" type="java.lang.String">
                <column name="classification" length="45" not-null="true" />
            </property>
            
             
            <set name="foodsAdditivesLinks" inverse="true">
                <key>
                    <column name="food_id" not-null="true" />
                </key>
                <one-to-many class="com.nimble.spider.renaissance.persistence.FoodsAdditivesLink" />
            </set>
            
            <!--
            <set name="mealsFoodsLinks" inverse="true">
                <key>
                    <column name="food_id_link" not-null="true" />
                </key>
                <one-to-many class="com.nimble.spider.renaissance.persistence.MealsFoodsLink" />
            </set>
            -->
        </class>
    </hibernate-mapping>
    
    
    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <!-- 
        Mapping file autogenerated by MyEclipse - Hibernate Tools
    -->
    <hibernate-mapping>
        <class name="com.nimble.spider.renaissance.persistence.FoodAdditives" table="food_additives">
            <id name="code" type="java.lang.String">
                <column name="code" length="3" />
                <generator class="native" />
            </id>
            <property name="name" type="java.lang.String">
                <column name="name" length="45" not-null="true" />
            </property>
            <property name="description" type="java.lang.String">
                <column name="description" length="65535" not-null="true" />
            </property>
            <set name="foodsAdditivesLinks" inverse="true">
                <key>
                    <column name="additive_id" length="3" not-null="true" />
                </key>
                <one-to-many class="com.nimble.spider.renaissance.persistence.FoodsAdditivesLink" />
            </set>
        </class>
    </hibernate-mapping>
    
    
    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <!-- 
        Mapping file autogenerated by MyEclipse - Hibernate Tools
    -->
    <hibernate-mapping>
        <class name="com.nimble.spider.renaissance.persistence.FoodsAdditivesLink" table="foods_additives_link">
            <composite-id name="id" class="com.nimble.spider.renaissance.persistence.FoodsAdditivesLinkId">
                <key-property name="foodId" type="java.lang.Long">
                    <column name="food_id" />
                </key-property>
                <key-property name="additiveId" type="java.lang.String">
                    <column name="additive_id" length="3" />
                </key-property>
            </composite-id>
            <many-to-one name="food" class="com.nimble.spider.renaissance.persistence.Food" update="false" insert="false" fetch="select">
                <column name="food_id" not-null="true" />
            </many-to-one>
            <many-to-one name="foodAdditives" class="com.nimble.spider.renaissance.persistence.FoodAdditives" update="false" insert="false" fetch="select">
                <column name="additive_id" length="3" not-null="true" />
            </many-to-one>
        </class>
    </hibernate-mapping>
    
    
    SAVE CODE:
    
    
    
    ....
    
    
    if(ParamValidator.isChecked(request.getParameter(StaticCache.getAdditiveTblPHO()))) {
                FoodsAdditivesLinkId id = new FoodsAdditivesLinkId();
                FoodAdditives pho  = CacheDBO.getCachedFoodAdditive(StaticCache.getAdditiveTblPHO());
                
                link = new FoodsAdditivesLink();
                link.setFoodAdditives(pho);
                link.setFood(food);
                
                id.setFoodId(food.getId());
                id.setAdditiveId(pho.getCode());
                
                link.setId(id);
                linkSet.add(link);
            }
            
            if(!linkSet.isEmpty()) {
                food.setFoodsAdditivesLinks(linkSet);
            }
    
    ....
    
    QueryDBO.savePojo(request, food);
    
    ....
    
    protected static void saveOrUpdatePojo(PersistencePojo pojo, dboOp op) {
            final String thisMethod = "saveOrUpdatePojo(PersistencePojo pojo, dboOp op)";
            if(logger.isDebugEnabled()) {
                logger.debug("Entering " + thisMethod);
            }
            Args.checkArgForNull(pojo, logger.getName());
            
            Session session = null;
            Transaction tx  = null;
            
            try {
                session = HibernateUtil.currentSession();
                tx = session.beginTransaction();
        
                switch(op)     {
                    case DBO_SAVE: {
                        if(logger.isInfoEnabled()) {
                            //logger.info("Executing save for: " + pojo.getClass().getName());
                            //logger.info("Pojo: " + pojo.toString());
                        }
                        session.save(pojo);
                        break;
                    }
                    case DBO_MODIFY: {
                        if(logger.isInfoEnabled()) {
                            logger.info("Executing update for: " + pojo.getClass().getName());
                            logger.info("Pojo: " + pojo.toString());
                        }
                        session.update(pojo);
                        break;
                    }
                    default: {
                        String msg = MsgFormat.eMsg("Unspported Database operation " + op.getOp(), thisMethod);
                        logger.fatal(msg);
                        throw new RuntimeException(msg);
                    }
                }
                
                tx.commit();
                
            } catch(Exception e_database) {
                String e_cause = MsgFormat.eMsg(e_database, thisMethod);
                
                if(tx != null) {
                    try {
                        tx.rollback();
                    }
                    catch(HibernateException e_rollback) {
                        e_cause += MsgFormat.eMsg(e_rollback, thisMethod);
                    }
                }
                
                logger.fatal(e_cause);
                throw new RuntimeException(e_cause);            
            }
            finally {
                try {
                    HibernateUtil.closeSession();
                }
                catch(HibernateException e_session) {
                    String e_cause = MsgFormat.eMsg(e_session, thisMethod);
                    logger.fatal(e_cause);
                    throw new RuntimeException(e_cause);
                }
            }
        }
    
    
    #252532 Reply

    Haris Peco
    Member

    I remove the “catelog=renaissance” tag from the mapping files because saves fail when I leave it.

    There is bug in hibernate 3.0 (stable MyEclipse use hibernate 3.0) and we fixed in version 4.1.1
    Please use latest stable version 4.1.1

    I saw your mapping and MyEclipse don’t set cascade operations (default to hibernate is “none”
    and child objects sin’t persist)

    You can try add cascade parameter in mappings , for example

    
    <one-to-many class="com.nimble.spider.renaissance.persistence.FoodsAdditivesLink" cascade="all"/>
     

    see description for cascade in hibernate documentation (cascade=”all” will do cascade for all operations persist, save,update,delete,lock etc and it isn’t what you want , maybe)

    You have change MyEclipse templates for adding this parameter automatic.We will make manipulate with templates better in 5.0.
    For now, MyEclipse set default cascade (no cascade or cascade=”none”)

    Best regards

    #252535 Reply

    ceronj
    Member

    I do have version 4.1.1, and it doesn’t work.

    At any rate, cascade or not the relationships are associative and hence many-to-many, not one-to-many. And the implementation here is way bloated. I fixed the problem yesterday using:

    <set name=”additives” table=”food_additives_link”>
    <key column=”food_id”>
    <many-to-many column=”additive_id” class =”com.nimble.spider.renaissance.persistence.FoodAdditives”/>
    </set>

    In the Food mapping file.

    That’s it. No foodsAdditivesLinks class or mapping file, or mention of Food in the FoodAdditves class or mapping file is required. It works like a charm. And it drastically reduces the save code to since all I need to do is add an additive to the Set “additives” in the Food class.

    Also, MyEclipse created an additional class for the foodadditivesId (the composite key); not needed with the mapping above.

    Why all the bloat? Frankly, I’m disappointed. Is this going to be fixed or simplified?

    #252559 Reply

    Haris Peco
    Member

    ceronj ,

    I do have version 4.1.1, and it doesn’t work.

    If you think for catalog – it work with myeclipse 4.1.1 hibernate libraries (they are patched for catalog bug).You have to use myEclipse libraries or hibernate 3.1 libraries.
    You are correct about cascade (many-to-many is better solution – sorry)

    About many-to-many :
    It’s very hard decide when you want many-to-many.In relational databases this is resolved with link table (you use it) and we can’t find where is many-to-many in reverse engineering (we add one-to-many or many-to-one from foreign keys).It’s possible tell: if table have just PK with two columns and every column is FK to other table – then it’s many-to-many, but it’s very hard wehn exists composite keys (for example, fi your table Food and FoodActivities have composite ids)

    About composite id :
    MyEclipse doesn’t create many-to-many relation and your link table have composite id (FK with 2 columns) – for this cases MyEclipse create separate class for id.

    You can use cascade like this :

    <set name=”foodsAdditivesLinks” inverse=”true” cascade=”save-update”>
    <key>
    <column name=”food_id” not-null=”true” />
    </key>
    <one-to-many class=”com.genuitec.mysql.FoodsAdditivesLink” />
    </set>

    but your many-to-many is superior for your case, because with cascade you have to save 2 objects (food and foodActivities, link will be saved with cascade).

    Best

Viewing 6 posts - 1 through 6 (of 6 total)
Reply To: hibernate mapping for link tables

You must be logged in to post in the forum log in