我有一个引用另一个模型类的模型类,似乎遇到了@OneToOne注释修复了一个问题但导致另一个问题的问题。删除它会导致逆转。
JPA抛出"多次分配到同一列"在尝试保存对模型的更改时。生成的SQL有重复的列,我不确定原因。
这里预览了类的外观:
父类引用如下所示:
public class Appliance {
public Integer locationId;
@Valid
@OneToOne
public Location location;
}
子Location类有一个id字段和一些其他文本字段 - 非常简单:
public class Location {
public Integer id;
public String name;
}
当我尝试执行保存操作时,是否有人知道为什么JPA为Appliance表创建一个insert语句,该表包含名为" location_id"?
的两个字段如果我希望能够从相应的数据库表中检索数据以在屏幕上显示,我需要使用@OneToOne注释对子类的引用。但是,如果我删除@OneToOne,保存工作正常,但在查询数据库时,显然不会将位置数据加载到子对象中。
提前致谢!
答案 0 :(得分:0)
您似乎没有在父类上定义@InheritanceType。由于您没有,默认情况下是将父类和子类组合到单表策略中的同一个表中。
由于两个实体都进入同一个表,我认为@OneToOne试图将id写入两次 - 无论它在哪一侧。
如果您希望将父项保存在自己的表中,请查看InheritanceType.JOINED。 或者考虑重新分解,以便您不会单独持久保存父级,因为JOINED不被视为某些JPA提供程序的安全选项。
请参阅下面的官方Oracle文档。
http://docs.oracle.com/javaee/7/tutorial/doc/persistence-intro002.htm#BNBQR
37.2.4.1每个类层次结构策略的单个表 使用此策略(对应于默认的InheritanceType.SINGLE_TABLE),层次结构中的所有类都映射到数据库中的单个表。此表有一个discriminator列,其中包含一个值,用于标识行所代表的实例所属的子类。
答案 1 :(得分:0)
在OpenJPA中,根据文档(http://openjpa.apache.org/builds/1.0.1/apache-openjpa-1.0.1/docs/manual/jpa_overview_mapping_field.html),第8.4节,一对一映射中的外键列:
默认为关系字段名称,加上下划线和名称 引用的主键列。
JPA API似乎同意这一点(http://docs.oracle.com/javaee/6/api/javax/persistence/JoinColumn.html)
我认为这意味着在一对一映射中,依赖类中属性的默认列名是parentClassFieldName_dependentClassFieldName(或者在您的情况下为location_id)。如果是这种情况,您在Appliance类中定义的location_id列与将为您的Location类生成的location_id默认列名称冲突。
您应该能够通过在@OneToOne关系中使用@Column(name =" someColumnName")注释和@JoinColumn注释来强制执行此操作,以强制列名称是唯一的。
答案 2 :(得分:0)
以下是新代码的样子,然后是简要说明......
父类:
public class Appliance {
public Integer locationId;
@Valid
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name="location_id", referencedColumnName="id")
public Location location;
}
儿童班:
public class Location {
public Integer id;
public String name;
}
这个难题的第一部分是在父类中明确添加“cascade = CascadeType.ALL”。通过允许子对象被持久化,这解决了初始的“对同一列的多次赋值”。
但是,我在更新操作期间遇到了一个问题,这是由于EBean和JPA之间存在某种冲突,因此它会触发嵌套子对象的save()操作,而不是级联update()操作。我通过发布子对象的显式更新然后在父更新操作发生之前将其设置为null来解决这个问题。这有点像黑客攻击,但似乎所有这些持久性框架都解决了一系列问题而导致了其他问题 - 我想这就是为什么我一直在上学并且总是推出自己的持久性代码直到现在。