【问题标题】:Save ManyToMany collection with stateless session使用无状态会话保存 ManyToMany 集合
【发布时间】:2012-12-02 19:50:11
【问题描述】:

我有:

@Entity
public class EmailAndName {
...
}

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

当我

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 表未填充。我该怎么办?我不想编写本机查询。谢谢。

【问题讨论】:

  • 能否提供详细的表结构?
  • 我知道你说过你不想编写原生查询,但我发现在无状态会话中填充多对多关联表的唯一方法(从而受益于无状态会话)。即sess.CreateSQLQuery("insert into MessageDetails_to (...) values (:id1, id2).SetParameter... etc.

标签: java hibernate hql


【解决方案1】:

好吧,我认为您的代码无法正常工作的主要原因是由于使用了无状态会话,但无论如何我建议您在实现 1-N 和 NM 关系时定义关系并更新双方。

另外,不要让外部类直接操作集合,因为它破坏了封装。不要为您的集合公开 set 方法,这可能会导致难以调试的非常讨厌的异常。使用 addremove 方法来更新您的集合。

@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);
    }

}

代码的另一部分应该是这样的:

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();

【讨论】:

    【解决方案2】:

    你还没有通读hibernate-doc 的无状态会话

    它明确指出:

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

    您正在尝试添加Set&lt;EmailAndName&gt;。无状态会话是一种较低级别的抽象,更接近底层的 JDBC。所以如果你真的想让你的代码工作并填充 MessageDetails_to.. 你需要去 Session。你需要为你的 POJO 定义 equals 和 hashCode 方法:)

    所以您修改后的代码将是:

    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();
      }
    

    您必须始终包含一个 try catch,以便您可以识别异常(如果有)并使其工作:)

    【讨论】:

      【解决方案3】:

      首先,你确定事务已经提交了吗?

      其次,您使用的是Set。您确定EmailAndName 类的equalshashCode 方法定义明确吗?

      【讨论】:

      • 我承诺。我使用无状态会话,这就是为什么不需要实现 hash 和 equals。
      • 您使用的会话类型与您的模型对象是否需要 equals 和 hashCode 有什么关系?
      • Set 确实需要一个 equals 和一个 hashCode 方法。没有这些,它永远不会工作。
      • 看看stackoverflow.com/questions/1638723/…的最后一个答案。无法附加无状态会话。这就是为什么不需要equals和hashcode的原因。虽然我已经实现了它们并且连接表仍然是空的。
      • 会话是无状态的这一事实与定义equalshashCode 方法的需要无关。您必须定义它们只是因为您将其添加到Set。如果您使用List 而不是Set,那么您真的不需要它们。 Set 旨在禁止重复项,它使用equals 方法来确定元素是否已经存在。如果不实现equals 方法,Set 无法检查重复项,它将不起作用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-10
      • 1970-01-01
      • 1970-01-01
      • 2012-02-06
      • 2012-09-27
      • 2014-08-06
      相关资源
      最近更新 更多