-->
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.  [ 1 post ] 
Author Message
 Post subject: How to bulk populate many-to-many relationships?
PostPosted: Wed Aug 01, 2007 11:13 am 
Newbie

Joined: Wed Aug 01, 2007 9:10 am
Posts: 1
I've been struggling to find an way to populate many-to-many relationships using Hibernate stateless sessions or using HSQL. I'm using Hibernate 3.2.4ga and Hibernate Annotations 3.3.0.

Up to now, we have performed bulk data loads using standard Hibernate persistance, but this is starting to perform very badly under big imports. This is mostly due to the interactions with the second-level cache used with some of the objects causing the memory usage to grow and grow.

I have investigated using stateless sessions which works fine for all the standard entities and for one-to-many relationships (using mappedBy), but completely breaks down as collections within an entity are not persisted and there seems to be no way to persist just the collection. I've tried exploring the API thoroughly and reading chapter 13 over and over, but cannot for the life of we see how I'm supposed to do it.

I've even tried resorting to HQL for this, but all my attempts at constructing appropriate HQL were met with invalid SQL being passed to the database or various errors thrown by Hibernate. Again, none of the examples in Chapter 14 seem to help.

Ultimately, in the example below I really want to generate the SQL: insert into a_b (a_id, m1_id) values (?,?)

So, is this possible to achieve without using the standard Hibernate ORM model?

Here is my example, modelling just a simple many-to-many relationship:

Code:
@javax.persistence.Entity
@Table(name = "a")
public class A {
    @Id
    @GeneratedValue(generator = "generator")
    @GenericGenerator(name = "generator", strategy = "com.isolutions.poc.hibernate.ralf.Generator")
    public Long id;
    public String name;

    @ManyToMany(fetch = FetchType.LAZY, targetEntity = B.class)
    @JoinTable(name = "a_b")
    @Cascade(value = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.SAVE_UPDATE, CascadeType.REFRESH})
    public Set<B> bs;
}

Code:
@javax.persistence.Entity
@Table(name = "b")
public class B {
    @Id
    @GeneratedValue(generator = "generator")
    @GenericGenerator(name = "generator", strategy = "com.isolutions.poc.hibernate.ralf.Generator")
    public Long id;
    public String name;


    @ManyToMany(fetch = FetchType.LAZY, targetEntity = A.class, mappedBy = "bs")
    @JoinTable(name = "a_b")
    @Cascade(value = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.SAVE_UPDATE, CascadeType.REFRESH})
    public Set<B> as;
}

Code:
public class Generator implements IdentifierGenerator {
    static long base = System.currentTimeMillis();

    public Serializable generate(SessionImplementor session, Object object) throws HibernateException {
        return base++;
    }
}

Code:
public class SimpleTest {
    private static final Logger log = Logger.getLogger(SimpleTest.class);

    ListFactoryBean factoryBean = new ListFactoryBean();

    private SessionFactory sessionFactory;

    @Before
    public final void setUp() {
        AnnotationConfiguration configuration = new AnnotationConfiguration();
        configuration
                .setProperty("hibernate.dialect", "com.isolutions.hibernate.dialect.MySQLDialect")
                .setProperty("hibernate.connection.driver_class", "com.mysql.jdbc.Driver")
                .setProperty("hibernate.connection.url", "jdbc:mysql://termite/v4ralf")
                .setProperty("hibernate.connection.username", "v4ralf")
                .setProperty("hibernate.connection.password", "v4ralf")
                .setProperty("hibernate.connection.pool_size", "20")
                .setProperty("hibernate.order_updates", "true")
                .setProperty("hibernate.show_sql", "true")
                .setProperty("hibernate.hbm2ddl.auto", "update");

        configuration.addAnnotatedClass(A.class);
        configuration.addAnnotatedClass(B.class);

        sessionFactory = configuration.buildSessionFactory();
    }

    @After
    public final void tearDown() {
        sessionFactory.close();
    }

    protected final SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    @Test
    public void testCreate() {
        StatelessSession session = getSessionFactory().openStatelessSession();
        Transaction transaction = session.beginTransaction();

        B b1 = new B();
        b1.name = "B 1";
        Long b1fp = (Long) session.insert(b1);

        B b2 = new B();
        b2.name = "B 2";
        Long b2fp = (Long) session.insert(b2);

        B b3 = new B();
        b3.name = "B 3";
        Long b3fp = (Long) session.insert(b3);

        A a1 = new A();
        a1.name = "A 1";
        Long a1fp = (Long) session.insert(a1);

        A a2 = new A();
        a2.name = "A 2";
        Long a2fp = (Long) session.insert(a2);

        HashSet<Long> members = new HashSet<Long>();
        members.add(b1fp);
        members.add(b2fp);
        members.add(b3fp);

        Query fetchQuery = session.
                createQuery("from B where id in (:members)").
                setParameterList("members", members);
        for (Object o : fetchQuery.list()) {
            log.debug(o);
        }

/**/
        Query query = session.
                createQuery("update A a set a.bs=(from B b where b.id in (:members)) where a.id = :fp").
                setParameterList("members", members).
                setLong("fp", a1fp);
        log.debug("Update returned " + query.executeUpdate());
/**/

        transaction.commit();
        session.close();

    }

}


If I run this with the code between the two /**/ markers removed, the 5 database objects are created and the fetch query works fine. With the code as-is, Hibernate generates the following SQL:
Code:
2007-08-01 16:09:53,998 DEBUG [main] org.hibernate.SQL  - update a,  set .=(select b3_.id from b b3_ where b3_.id in (? , ? , ?)) where id=?
Hibernate: update a,  set .=(select b3_.id from b b3_ where b3_.id in (? , ? , ?)) where id=?

I'm really struggling to understand how I should proceed further with this. At this stage, I'm open to pretty much any solution that doesn't involve using a standard Hibernate session (for the aforementioned level 2 cache problem causing memory exhaustion before the database commit).


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 

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.