4

I have:

@Entity
public class EmailAndName {
...
}

and

@Entity
public class MessageDetails {
    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinTable(name = "MessageDetails_to")
    public Set<EmailAndName> getTo() {
        return to;
    }
}

when I

public static void main(String []a)
{
    StatelessSession sess = HibernateUtils.getSessionFactory().openStatelessSession();
    sess.beginTransaction();
    MessageDetails messageDetails = new MessageDetails();
    messageDetails.setTo(new HashSet<EmailAndName>());
    EmailAndName emailAndName = (EmailAndName) sess.get(EmailAndName.class, 1L);
    if (emailAndName == null ) throw new RuntimeException();
    messageDetails.getTo().add(emailAndName);
    sess.insert(messageDetails);
    sess.getTransaction().commit();
}

MessageDetails_to table is not populated. What should I do? I don't want to write native queries. Thank you.

Stepan Yakovenko
  • 8,670
  • 28
  • 113
  • 206
  • Can you provide table structure in detail? – Vijay Krish Dec 18 '12 at 13:37
  • I know you said you don't want to write native queries, but I found that the only way to populate the many-to-many association table in a stateless session (thereby benefiting from the speed of a stateless session). i.e. `sess.CreateSQLQuery("insert into MessageDetails_to (...) values (:id1, id2).SetParameter... etc.` – Francois Botha Mar 23 '15 at 09:16

3 Answers3

5

You havent read through hibernate-doc for stateless session

It clearly states that:

Operations performed using a stateless session never cascade to associated instances. Collections are ignored by a stateless session.

And you are trying to add a Set<EmailAndName>. A stateless session is a lower-level abstraction, much closer to the underlying JDBC. SO if you really want make your code work and populate MessageDetails_to.. You need to go for Session. You will need to define the equals and hashCode methods for your POJO's :)

so your modified code will be:

public static void main(String []a)
{
   try{
    Session sess = HibernateUtils.getSessionFactory().openSession();
    sess.beginTransaction();
    MessageDetails messageDetails = new MessageDetails();
    messageDetails.setTo(new HashSet<EmailAndName>());
    EmailAndName emailAndName = (EmailAndName) sess.get(EmailAndName.class, 1L);
    if (emailAndName == null ) throw new RuntimeException();
    messageDetails.getTo().add(emailAndName);
    sess.save(messageDetails);
    sess.getTransaction().commit();
 }
catch(HibernateException e)
 {
   sess.getTransaction.rollback();
   e.printStackTrace();
 }
  finally{
       sess.close();
  }

You must always have a try catch enclosed, so that you can identify the exceptions(if any) and make it work :)

DarkHorse
  • 2,740
  • 19
  • 28
0

First, are you sure that the transaction is commited?

Second, you are using a Set. Do you have sure that the equals and hashCode method of the EmailAndName class are well-defined?

  • I commit. I use stateless session, that is why there is no need to implement hash and equals. – Stepan Yakovenko Dec 14 '12 at 19:26
  • What does the type of session you're using have to do with whether or not your model objects need equals and hashCode? – Marvo Dec 14 '12 at 19:29
  • The `Set` really need an equals and a hashCode method. Without these, it will never work. – Victor Stafusa - BozoNaCadeia Dec 14 '12 at 19:29
  • Take a look at the last answer to http://stackoverflow.com/questions/1638723/equals-and-hashcode-in-hibernate. Stateless sessions can not be attached to. That is why there is no need for equals and hashcode. Though I've implemented them and join table is still empty. – Stepan Yakovenko Dec 14 '12 at 19:38
  • 1
    The fact that your sessions are stateless has nothing to do with the need to define the `equals` and `hashCode` methods. You must define them just because you are adding it to a `Set`. If you use a `List` instead of a `Set`, then you really don't need them. The `Set` are intended to disallow repeated items, and it uses the `equals` method to decide if the element is already there or not. If you don't implement the `equals` method, the `Set` can't check for duplicates and it won't work. – Victor Stafusa - BozoNaCadeia Dec 14 '12 at 22:02
  • Can you give more information about where you call the `sess.insert(messageDetails);`? What you do before and after that? – Victor Stafusa - BozoNaCadeia Dec 14 '12 at 22:03
  • I've added details. Would you be so kind to take a look? – Stepan Yakovenko Dec 15 '12 at 09:12
  • I took a look and found nothing. Run out of ideas, sorry. – Victor Stafusa - BozoNaCadeia Dec 17 '12 at 20:44
0

Well, I think that the main reason your code is not working is due to the use of a stateless session, but in any case I would recommend you that when you implement 1-N and N-M relationships define the inverse side of the relationship and update both sides.

In addition, don't let external classes to manipulate a set directly, because it breaks encapsulation. Don't expose a set method for your collections, it may cause very nasty exceptions hard to debug. Use an add and a remove method to update your set.

@Entity
public class MessageDetails {

    private Set<EmailAndName> to = new HashSet<EmailAndName>();

    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinTable(name = "MessageDetails_to", 
       joinColumns = {@JoinColumn(name = "MESSAGE_DETAILS_ID"},
       inverseJoinColumns = {@JoinColumn(name = "EMAIL_AND_ADDRESS_ID")})
    public Set<EmailAndName> getTo() {
        return Collections.unmodifiableSet(to);
    }

    public void addEmaiAndName(EmailAndName emailAndName) {
       emailAndName.setMessageDetails(this);
       to.add(emailAndName);
    }

    public void removeEmailAndName(EmailAndName emailAndName) {
       emailAndName.setMessageDetails(null);
       to.remove(emailAndName);
    }

}

The other part of the code should be something like:

Session sess = HibernateUtils.getSessionFactory().openSession();
sess.beginTransaction();
MessageDetails messageDetails = new MessageDetails();
EmailAndName emailAndName = (EmailAndName) sess.get(EmailAndName.class, 1L);
if (emailAndName == null ) throw new RuntimeException();
messageDetails.addEmailAndName(emailAndName);
sess.save(messageDetails);
sess.getTransaction().commit();
Diego Pino
  • 11,278
  • 1
  • 55
  • 57