我有一个实体,它有两个多对一关系,其中一个实际上保存得很好,另一个返回:
Exception in thread "main" org.hibernate.TransientObjectException: object references an
unsaved transient instance - save the transient instance before flushing : dto.publicSchema.Pessoas
以下是有效实体的代码:
@Entity
@Table(name="`Doc_tipo`", schema="public")
public class Doc_tipo implements Serializable {
private static final long serialVersionUID = 1859372890916956036L;
@Id
@Column(nullable=false)
private int tp_doc;
@Column(nullable=false,columnDefinition="CHAR(255)")
private String descricao;
@Column(nullable=false,columnDefinition="CHAR(255)")
private String tp_emissor;
//getters and setters
}
以下是不允许级联的实体代码:
@Entity
@Table(name="`Pessoas`", schema="public")
public class Pessoas implements Serializable {
private static final long serialVersionUID = 8292302132119274975L;
@Id @GeneratedValue
@Column(nullable=false,columnDefinition="serial NOT NULL")
private int seq_pessoa;
static Date padrao_dt_criacao = new Date();
@Column(nullable=false, columnDefinition="date NOT NULL")
private Date dt_criacao = padrao_dt_criacao;
@Column(columnDefinition="CHAR(255)")
private String nome;
@Column(columnDefinition="CHAR(1) NULL")
private char tp_pessoa;
@Column(columnDefinition="CHAR(255)")
private String fantasia;
@Column(columnDefinition="VARCHAR(25)")
private String idioma;
@Column(columnDefinition="VARCHAR(25)")
private String login;
@Column(columnDefinition="VARCHAR(25)")
private String senha;
static Date padrao_dt_i = new Date();
@Column(nullable=false, columnDefinition="date NOT NULL")
private Date dt_i = padrao_dt_i;
//Pessoa está ativa para o sitema se este campo estiver em branco
@Column(columnDefinition="date")
private Date dt_f;
@Column(columnDefinition="oid")
private int foto;
//getters and setters
}
以下是与上述两者有多对一关系的班级 但是级联只适用于第一个:
@Entity
@Table(name="`Documentos`", schema="public")
public class Documentos implements Serializable {
private static final long serialVersionUID = -4874330647877687810L;
@Id
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="seq_pessoa",columnDefinition="integer",referencedColumnName="seq_pessoa",nullable=false)
private Pessoas seq_pessoa;
@Id @GeneratedValue
@Column(nullable=false,columnDefinition="serial NOT NULL")
private int cd_doc;
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="tp_doc",referencedColumnName="tp_doc",nullable=false)
private Doc_tipo tp_doc;
@Column(nullable=false)
private int tp_emissor;
@Column(nullable=false,columnDefinition="CHAR(2) NOT NULL DEFAULT 'DF'::bpchar")
private String tp_emissor_uf="DF";
@Column(columnDefinition="CHAR(5)")
private String alfa_doc;
@Column(nullable=false,columnDefinition="CHAR(20)")
private String nr_doc;
//Data de validade do documento
@Column(columnDefinition="date")
private Date dt_f_valid;
@Transient
transient static Date padrao_dt_i = new Date();
@Column(columnDefinition="date DEFAULT now()")
private Date dt_i = padrao_dt_i;
@Column(columnDefinition="date")
private Date dt_f;
//getters and setters
}
当我去保存Documentos对象时,hibernate将Doc_tipo插入其表中 正如它应该的那样,而不是插入Pessoa对象也会抛出异常。
这是操纵会话的类(它仅用于测试):
public class Hibernate {
public static SessionFactory getSessionFactory() {
SessionFactory sessionFactory = null;
try {
Configuration configuration = new Configuration();
configuration.configure();
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(
configuration.getProperties()).buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (HibernateException hbe) {
hbe.printStackTrace();
}
return sessionFactory;
}
public static void main(String[] args) {
SessionFactory sessionFactory = getSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
Pessoas a = new Pessoas();
a.setDt_criacao(new Date());
a.setDt_f(new Date());
a.setDt_i(new Date());
a.setFantasia("teste");
a.setFoto(12);
a.setIdioma("aa");
a.setLogin("aa");
a.setNome("aa");
a.setSenha("a");
a.setTp_pessoa('H');
Doc_tipo b = new Doc_tipo();
b.setDescricao("aa");
b.setTp_doc(5);
b.setTp_emissor("aaa");
Documentos c = new Documentos();
c.setAlfa_doc("aaa");
c.setDt_f(new Date());
c.setDt_f_valid(new Date());
c.setDt_i(new Date());
c.setNr_doc("aa");
c.setSeq_pessoa(a);
c.setTp_doc(b);
c.setTp_emissor(1);
c.setTp_emissor_uf("aa");
//session.save(a);
session.save(c);
session.getTransaction().commit();
session.close();
}
}
如果我删除对save()Pessoas对象的注释,一切正常,但我不应该这样做,当我尝试级联保存在另一个时发生同样的异常 与Pessoas有多对一关系的实体。
答案 0 :(得分:0)
Documentos使用主键(Pessoas.seq_pessoa)引用Pessoas,该主键仅在Pessoas使用serial后保存/刷新到数据库后创建。所以在保存/持久化实际发生之前没有什么可以参考的。
此外,除非您还定义了包含上述@Id字段的@IdClass,否则不应使用多个@Id注释来定义复合标识。或者你也可以@EmbeddedId注释。 JPA支持两种不同的复合PK方法。在每种情况下,必须有一个包含字段的PK类。
A)实体上的多个@Id字段/属性。实体中的字段名称和类型必须与PK类中的字段相匹配。还必须在类上有@IdClass注释。例如:
public class EmpPK {
int id;
String name;
...
}
@Entity
@IdClass(EmpPK.class)
public class Employee {
@Id int id;
@Id String name;
...
}
B)在实体中嵌入PK类的属性。在这种情况下,属性用@EmbeddedId标记,PK类必须用@Embeddable注释。例如:
@Embeddable
public class EmpPK {
int id;
String name;
...
}
@Entity
public class Employee {
@EmbeddedId EmpPK empId;
...
}