我的Hibernate-JPA域模型具有以下实体:
AttributeType ------< AttributeValue相关的Java类如下所示(getter和setter省略了):
@Entity
public class AttributeType {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(unique = true, nullable = false)
private String name;
@OneToMany(mappedBy = "attributeType", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
private List<AttributeValue> values = new ArrayList<AttributeValue>();
}
@Entity @Table(uniqueConstraints = @UniqueConstraint(columnNames = {"value", "attribute_type_id"}))
public class AttributeValue {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@ManyToOne(optional = false)
private AttributeType attributeType;
@Column(nullable = false)
private String value;
}注意,AttributeValue.value和AttributeValue.attributeType有一个唯一的约束,因为对于属性类型(例如大小),我们不希望不止一次地出现属性值(例如小)。
如果我通过在单个事务中执行以下操作来更新AttributeType:
我得到一个异常,表示违反了唯一约束。这表明Hibernate-JPA在删除之前执行属性值的插入,这似乎没有明显的原因导致了这种问题。
执行AttributeType更新的类如下所示:
@Transactional(propagation = Propagation.SUPPORTS)
public class SomeService {
private EntityManager entityManager; // set by dependency injection
@Transactional(propagation = Propagation.REQUIRED)
public AttributeType updateAttributeType(AttributeType attributeType) throws Exception {
attributeType = entityManager.merge(attributeType);
entityManager.flush();
entityManager.refresh(attributeType);
return attributeType;
}
}我可以通过迭代属性值来解决这个问题,找出哪些属性值已被更新/删除/插入,然后按以下顺序执行:
但似乎ORM应该能为我做到这一点。我已经读过,Oracle提供了一个"deferConstraints“选项,该选项只在事务完成后才会检查约束。但是,我使用的是Server,因此这不会对我有帮助。
发布于 2011-08-09 18:29:28
您需要使用复合ID而不是生成的ID。
HHH-2801 当向集合中添加具有生成ID的新关联实体时,就会出现问题。当合并包含此集合的实体时,第一步是级联保存新的关联实体。必须在对集合进行其他更改之前进行级联。因为此新关联实体的唯一键与已持久化的实体相同,因此抛出一个ConstraintViolationException。,这是预期的行为。 使用新集合(如上一条注释中建议的一次删除)也会导致违反约束,因为新的关联实体将保存在新集合的级联上。 其中一种方法(使用复合ID而不是生成的ID)的示例演示了>在manytomanywithassocclass.tar.gz中,并被签入Svn。
@Entity
public class AttributeType {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Integer id;
@Column(unique = true, nullable = false)
private String name;
@OneToMany(mappedBy = "attributeType", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
private List<AttributeValue> values = new ArrayList<AttributeValue>();
//Getter, Setter...
}
@Entity
@Table (uniqueConstraints = @UniqueConstraint(columnNames = { "value", "attributeType_id" }))
public class AttributeValue{
@EmbeddedId AttributeValueId id;
@MapsId(value= "id")
@ManyToOne(optional = false)
private AttributeType attributeType;
private String value2;
public AttributeValue() {
this.id = new AttributeValueId();
}
public AttributeType getAttributeType() {
return attributeType;
}
public void setAttributeType(AttributeType pAttributeType) {
this.id.setAttributeTypeID(pAttributeType.getId());
this.attributeType = pAttributeType;
}
public String getValue() {
return id.getAttributeValue();
}
public void setValue(String value) {
this.id.setAttributeValue(value);
}
@Embeddable
public static class AttributeValueId implements Serializable {
private Integer id;
private String value;
public AttributeValueId() {
}
public AttributeValueId(Integer pAttributeTypeID, String pAttributeValue) {
this.id = pAttributeTypeID;
this.value = pAttributeValue;
}
public Integer getAttributeTypeID() {
return id;
}
public void setAttributeTypeID(Integer attributeTypeID) {
this.id = attributeTypeID;
}
public String getAttributeValue() {
return value;
}
public void setAttributeValue(String attributeValue) {
this.value = attributeValue;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime
* result
+ ((id == null) ? 0 : id
.hashCode());
result = prime
* result
+ ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AttributeValueId other = (AttributeValueId) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
return true;
}
}
}有关如何使用JPA注释执行此操作,请参见5.1.2.1.复合标识符。
请参阅第8章.组件映射
请参阅8.4。组件作为复合标识符
发布于 2011-08-10 21:28:00
我不确定随着时间的推移,我是否理解了这个问题,但我首先要尝试的是覆盖AttributeValue的等于方法,以包含这两个唯一的字段。
发布于 2011-08-09 15:06:54
在hibernate会话中,有一个队列用于删除,一个用于插入。调试以查看是否在插入之前删除。
看看合并。尝试使用update。
https://stackoverflow.com/questions/6857517
复制相似问题