在通过MySQL数据库使用hibernate和jpa的Spring MVC应用程序中,每当我尝试保存包括子实体的父实体时,都会收到有关子实体的以下错误消息:
Duplicate entry 'string1-string2' for key 'PRIMARY'
在这里,string1
并string2
引用子实体的组合主键的两个部分。 如何解决此错误?
在父Address
实体中定义实体之间的关系的方法如下:
@ManyToOne(cascade = { CascadeType.ALL }, fetch=FetchType.EAGER)
@JoinColumns({ @JoinColumn(name = "usecode", referencedColumnName = "code", insertable = false, updatable = false),
@JoinColumn(name = "usecodesystem", referencedColumnName = "codesystem", insertable = false, updatable = false)
})
public HL7GeneralCode use;
这是在GeneralCode
子实体中定义关系的方式:
@OneToMany(mappedBy = "use", cascade = {CascadeType.ALL})
private Set<HL7Address> addresses;
单击此链接可以查看完整的堆栈跟踪。可以在此链接上找到实体
的完整代码。 Address
GeneralCode
可以在此链接上读取实体的完整代码。
可以在此链接中找到复合主键类的代码。扩展
的BaseEntity
类Address
可以在此链接中找到。
我已经阅读了很多关于此错误消息的信息。其他发布的答案不能解决我的错误消息,并且通常不能解决我的实体使用 复合主键 这一事实。
保留地址的代码是:
@Override
public void savehl7Address(HL7Address addr) {
if ((Integer)addr.getId() == null) {
System.out.println("[[[[[[[[[[[[ about to persist address ]]]]]]]]]]]]]]]]]]]]");
this.em.persist(addr);}
else {
System.out.println("]]]]]]]]]]]]]]]]]] about to merge address [[[[[[[[[[[[[[[[[[[[[");
this.em.merge(addr);}
}
我尝试遵循@
Ben75的建议,但是代码在此行崩溃this.em.persist(addr.getUse());
。请注意,他的if子句不适合我的实际对象模型,因此我将下面的if子句更改为if(addr.getUse() != null && addr.getId()==null)
。这是我的代码。
@Override
public void savehl7Address(HL7Address addr) {
if(addr.getUse() != null && addr.getId()==null){
//this next line prints in the stack trace right before the app crashes
System.out.println("about to this.em.persist(addr.getUse());");
//HL7GeneralCode is not persistent yet
this.em.persist(addr.getUse());
//since there is a cascade ALL on the adresses relationship addr is now persistent
return;
}
System.out.println("=========================== inside jpahl7patientrespository.savehl7Address(addr)");
if ((Integer)addr.getId() == null) {
System.out.println("[[[[[[[[[[[[ about to persist address ]]]]]]]]]]]]]]]]]]]]");
this.em.persist(addr);}
else {
System.out.println("]]]]]]]]]]]]]]]]]] about to merge address [[[[[[[[[[[[[[[[[[[[[");
this.em.merge(addr);}
}
HL7Address的相关部分现在为:
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumns({ @JoinColumn(name = "usecode", referencedColumnName = "code", insertable = false, updatable = false),
@JoinColumn(name = "usecodesystem", referencedColumnName = "codesystem", insertable = false, updatable = false)
})
public HL7GeneralCode use;
HL7GeneralCode的相关部分现在为:
@OneToMany(mappedBy = "use")
private Set<HL7Address> addresses;
单击此链接可以读取新的堆栈跟踪。
如何解决此错误?
我遵循ben75的建议,在保存地址方法中添加了以下代码:
if(addr.getUse() != null && !this.em.contains(addr.getUse())){
System.out.println("about to this.em.persist(addr.getUse());");
this.em.persist(addr.getUse());return;
}
不幸的是,尽管堆栈跟踪SYSO
表明上述代码在应用崩溃之前就在运行,但我仍然遇到相同的错误。
您可以通过单击此链接来读取生成的堆栈跟踪。
首先要清除一些事情:
HL7GeneralCode(父级)和HL7Address(子级)之间存在双向关联。如果HL7GeneralCode.addresses是“反”面(mappedBy),那么为什么拥有方HL7Address.use具有可插入/可更新的false?拥有方应控制此关联,因此您应删除insertable / updatable = false标志。
从父级到子级级联总是有意义的,而不是相反。但是在您的用例中,您尝试保留子项,并自动也保留父项。这就是为什么CASCADE.ALL在多对一末端没有意义的原因。
使用双向关联时,必须强制设置双方:
HL7Address addr = new HL7Address();
HL7GeneralCode code = new HL7GeneralCode();
...
code.getAddresses().add(addr);
addr.setUse(code);
持久操作旨在插入瞬态实体,而不要合并它们或重新附加实体。这意味着在您调用服务方法时,HL7Address和HL7GeneralCode都是新实体。如果您已经保存了具有相同ID的HL7GeneralCode,则将获得主键约束冲突异常。
如果HL7GeneralCode可能存在,则应从db获取它。
HL7GeneralCode code = em.find(HL7GeneralCode, pk);
HL7Address addr = new HL7Address();
if(code != null) {
code = new HL7GeneralCode();
em.persist(code);
}
code.getAddresses().add(addr);
addr.setUse(code);
em.persist(addr);
更新
HL7Address地址不会覆盖equals / hashCode,因此将应用默认对象相同的引用检查规则。这将确保我们可以从code.addresses列表中添加/删除地址。万一以后改变主意,请确保正确实现equals和hashCode。
尽管与您的问题无关,但您可能希望使用getter / setter而不是将字段公开。这样可以提供更好的封装,并且可以避免将setter与公共领域的访问权混在一起。
savehl7Address方法:
@Override
public void savehl7Address(HL7Address addr) {
HL7GeneralCode code = addr.use();
if(code != null && code.getId()==null){
//HL7GeneralCode is not persistent. We don't support that
throw new IllegalStateException("Cannot persist an adress using a non persistent HL7GeneralCode");
//In case you'd want to support it
//code = em.find(HL7GeneralCode, code.getId());
}
//Merge the code without any address info
//This will ensure we only reattach the code without triggering the address
//transitive persistence by reachability
addr.setUse(null);
code.getAddresses().remove(addr);
code = em.merge(code);
//Now set the code to the address and vice-versa
addr.setUse(code);
code.getAddresses().add(addr);
if ((Integer)addr.getId() == null) {
System.out.println("[[[[[[[[[[[[ about to persist address ]]]]]]]]]]]]]]]]]]]]");
em.persist(addr);
}
else {
System.out.println("]]]]]]]]]]]]]]]]]] about to merge address [[[[[[[[[[[[[[[[[[[[[");
addr = em.merge(addr);
}
}
问题内容: 所以我的MySQL数据库表现得有些奇怪。这是我的桌子: 当我尝试插入表时出现此#1062错误。因此,我进一步研究了它,并意识到当我尝试在名称和共享值相同的表中插入值时,它将返回#1062错误。例如,如果我插入: 它将返回错误。但是,如果我将共享数更改为6,它将运行正常。是因为我的专栏之一可能是唯一的,还是仅与mysql有关? 问题答案: 您需要删除作为OR
问题内容: 尝试在数据库中插入值时,mysql表出现问题。 我遵循了本教程 http://sqllessons.com/categories.html 并像教程中的表格一样创建表格 表格代码 错误的 SQL查询:编辑编辑 帮我解决这个问题。 问题答案: 声明要自动递增的值,不要插入它。所以: 接着:
问题内容: 我在MySQL 5.5.24中有下表 它具有大量数据,并且其他两个表具有和并具有多对一关系。 现在,我需要更改结构并在表中引入单独的主键,同时仍保留现有的关系和数据。为此,我执行了以下查询: 不幸的是,我的第二次查询失败,并出现以下错误: 1062-键“ PRIMARY”的条目“ 0”重复 有人可以指出这个问题吗?我想问题是现有的关系,但是我不想丢失具有数千行的现有关系或数据。有什么方
我的数据库中有这些(简化的)表 我已经用这两个(简化的)类映射了表 公司 如果我注释第26、28、30和32行(上面标记的),同样的代码可以完美地工作。但我想知道为什么会产生异常。为什么是复制的钥匙? 提前谢了。
问题内容: 尝试以下操作时,我在此错误消息上遇到了问题: 错误代码:1062。键“ PRIMARY”的条目“ 1”重复 我没有auto_increment数据,请帮助我! 这是与表格相关的, UFFICIO-INFORMAZIONI 插入 问题答案: 该 主 为什么已经产生错误的原因是因为已经有一个现有值的列在其中将其定义为( 值是唯一 在要插入的表格)。 为什么不将列设置为? 当您插入记录时,您
问题内容: 如何在cygwin中使用grep查找包含 两个 单词的所有文件。 这就是我用来递归搜索目录中所有文件的一个单词的方法: 如何扩展以上内容以查找同时包含“ db-connect.php”和“版本”的文件。 我试过了:但这是一个OR,即它获取包含一个或另一个的文件。 谢谢大家的帮助 问题答案: