使用Hibernate在Postgres中使用@EmbeddedId和@ElementCollection持久保存实体的问题

时间:2016-07-18 11:24:59

标签: java hibernate orm

我想使用Hibernate在Postgres 9上执行CRUD操作。

实体:

@Entity
@Table(name = "MESSAGE_HISTORY_RECORD")

public class MessageHistoryRecord {

    @EmbeddedId
    private MessageCompoundKey compoundKey;

    @Column
    private String responseChannel;

    @ElementCollection
    private List<Trace> traces;

    @Column
    private byte[] payload;

    //getters and setters
}

复合ID实体:

@Embeddable
public class MessageCompoundKey implements Serializable {

    private static final long serialVersionUID = 9084329307727034214L;

    @Column
    private String correlatedMsgId;

    @Column
    private String messageId;

    @Column
    private String endpointId;

    //getters and setters
}

ElementCollection实体:

@Embeddable
public class Trace implements Serializable{

    private static final long serialVersionUID = 9084329307727034214L;

    private Long timestamp;

    private String description;

   //getters and setters
}

我正在使用hibernate.hbm2ddl.auto=update为我创建架构。

它为我创建了表格:

CREATE TABLE "public"."message_history_record"
(
   correlatedmsgid varchar(255) NOT NULL,
   endpointid varchar(255) NOT NULL,
   messageid varchar(255) NOT NULL,
   payload bytea,
   responsechannel varchar(255),
   CONSTRAINT message_history_record_pkey PRIMARY KEY (correlatedmsgid,endpointid,messageid)
)
;
CREATE UNIQUE INDEX message_history_record_pkey ON "public"."message_history_record"
(
  correlatedmsgid,
  endpointid,
  messageid
)
;

CREATE TABLE "public"."messagehistoryrecord_traces"
(
   messagehistoryrecord_correlatedmsgid varchar(255) NOT NULL,
   messagehistoryrecord_endpointid varchar(255) NOT NULL,
   messagehistoryrecord_messageid varchar(255) NOT NULL,
   description varchar(255),
   timestamp bigint
)

在保留任何对象时,我在messagehistoryrecord_traces表中找不到任何条目。

Hibernate属性:

hibernate.connection.driver_class=org.postgresql.Driver
hibernate.connection.url=jdbc:postgresql://192.xx.xx.xx:5432/testdb
hibernate.connection.username=***
hibernate.connection.password=****
hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
hibernate.connection.pool_size=10
hibernate.show_sql=true
hibernate.hbm2ddl.auto=update

坚持sql:

  

Hibernate:插入MESSAGE_HISTORY_RECORD(payload,responseChannel,correlationMsgId,endpointId,messageId)值(?,?,?,?,?)

3 个答案:

答案 0 :(得分:1)

根据您的配置,默认值应该适用于集合表的表名,列名和连接列名。这些默认值的构造如下:

  1. 表名称:引用实体的名称,附加下划线以及包含元素集合的实体属性的名称(MessageHistoryRecord_traces

  2. 加入列:附加引用实体的名称 带有下划线和实体表的主键列的名称。

  3. 仅当您在父实体中有一个主键字段时才允许第二种情况,在您的情况下不是这种情况。所以你自己指定了连接列,如下所示(我重命名了集合表名和外键列名,因为它们对我的数据库系统来说太长了):

    @ElementCollection
    @CollectionTable(name = "mhr_traces", 
        joinColumns={@JoinColumn(name="mhr_correlatedmsgid", referencedColumnName="correlatedmsgid"), 
                     @JoinColumn(name="mhr_endpointid", referencedColumnName="endpointid"), 
                     @JoinColumn(name = "mhr_messageid", referencedColumnName = "messageid")})
    private List<Trace> traces = new ArrayList<>();
    

    还有一件事:如果你还没有完成主要密钥类的equals()hashCode()方法(你的帖子中看不到它们),你必须实现CONSTRAINT mrFK FOREIGN KEY (mhr_correlatedmsgid, mhr_endpointid, mhr_messageid) REFERENCES MESSAGE_HISTORY_RECORD (correlatedmsgid,endpointid,messageid) org.springframework.http.MediaType.getCharset()方法。

    您的表创建脚本也缺少外键definitino(如果它们不是自动生成的话,请手动添加它们):

    getStringArray

    根据您的数据库语法调整它(我不知道PostgreSQL)

    通过这些调整,一切都适合我;确实在Oracle数据库系统和EclipseLink上作为持久性提供程序。我认为这不是特定于实现的

答案 1 :(得分:1)

您是否在跟踪列表中添加了任何内容,或者它是空的? 这对我的postgresql没有任何调整。随着hbm2ddl.auto设置为更新,hibernate也创建了表和它们之间的外键关系。以下是我使用的示例代码:

public class App 
{
     public static void main( String[] args )
        {
            System.out.println("Maven + Hibernate + Postgresql");
            Session session = HibernateUtil.getSessionFactory().openSession();
            session.beginTransaction();

            MessageCompoundKey cKey = new MessageCompoundKey();
            cKey.setCorrelatedMsgId("correlatedMsgId_2");
            cKey.setEndpointId("endpointId_2");
            cKey.setMessageId("messageId_2");

            MessageHistoryRecord record = new MessageHistoryRecord();
            record.setResponseChannel("ArsenalFanTv");

            List<Trace> traces = new ArrayList<>();
            Trace t1 = new Trace();
            t1.setDescription("description_1");
            t1.setTimestamp(System.currentTimeMillis());
            traces.add(t1);
            Trace t2 = new Trace();
            t2.setDescription("description_2");
            t2.setTimestamp(System.currentTimeMillis());
            traces.add(t2);

            record.setCompoundKey(cKey);
            record.setTraces(traces);

            session.save(record);
            session.getTransaction().commit();
        }
}

和我的配置文件(hibernate.cfg.xml)如下:

<hibernate-configuration>
    <session-factory>
       <!--  <property name="hibernate.bytecode.use_reflection_optimizer">false</property> -->
        <property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
        <property name="hibernate.connection.password">****</property>
        <property name="hibernate.connection.url">jdbc:postgresql://127.0.0.1:5432/testdb</property>
        <property name="hibernate.connection.username">****</property>
        <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.hbm2ddl.auto">update</property>
        <mapping class="com.skm.schema.MessageHistoryRecord"></mapping>
    </session-factory>
</hibernate-configuration>

答案 2 :(得分:0)

我使用的是 StatelessSession而不是会话。根据文件:

  

无状态会话不实现第一级缓存,也不与任何二级缓存交互,也不实现事务性后写或自动脏检查,也不会对关联实例进行级联操作。 无状态会话会忽略收藏集。通过无状态会话执行的操作绕过Hibernate的事件模型和拦截器。由于缺少第一级缓存,无状态会话容易受到数据别名影响。

可在此thread上找到更多详情。

使用Session而不是StatelessSession后,它起作用了。