我在删除具有单向 @OneToMany自定义关系的实体时遇到问题。这里是“基础”实体的关系(仅相关列):
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "Id", updatable = false)
protected Integer id;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "ObjectId", referencedColumnName = "Id")
protected Collection<Attachment> attachmentsCollection;
这里是“子”实体的相关列:
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "Id", updatable = false)
protected Integer id;
@NotNull
@Basic(optional = false)
@Size(min = 1, max = 64)
@Column(name = "ObjectTable", updatable = false)
protected String objectTable;
@Basic(optional = false)
@Column(name = "ObjectId", updatable = false)
protected Integer objectId;
@NotNull
@Basic(optional = false)
@Lob
@Column(name = "Data")
protected byte[] data;
@NotNull
@Basic(optional = false)
@Column(name = "SizeInBytes")
protected Long sizeInBytes;
@NotNull
@Basic(optional = false)
@Size(min = 1, max = 128)
@Column(name = "Name")
protected String name;
这里解释为什么这是一个自定义关系:基础对象是所有实体的超类。除了自己的 id 之外,它还有机会通过附件集合关联任意数量的附件。由于表(实体)之间的 ID 不是唯一的,因此需要在子表(附件表)中添加额外的列。此附加列 (ObjectTable) 标识拥有附件的实体种类。将此列添加到entity'id(ObjectId)列中,关系就完成了:
假设实体 Invoice 的记录 99 有 2 个附件(附件“Z”和附件“Y”):
Table Invoice
-------------
Id ColumnA ColumnB ColumnC...
99 'xyz' '2343' 'zyx'
.
.
Table Attachment
----------------
Id ObjectTable ObjectId Data SizeInBytes Name
43542 'Invoice' 99 11100110 437834 'Z.pdf'
43543 'Invoice' 99 101110 867454 'Y.pdf'
我设法使用映射定制器加载关系:
public static final String TABLENAME = "TECAttachment";
public static final String OBJECTIDFIELDNAME = TABLENAME + ".ObjectId";
public static final String OBJECTTABLEFIELDNAME = TABLENAME + ".ObjectTable";
// Customize how records are selecting inside entity's attachments collection: include the entities table name
@Override
public void customize(ClassDescriptor descriptor) {
OneToManyMapping mapping = (OneToManyMapping)descriptor.getMappingForAttributeName(AttachmentEntitySessionCustomizer.ATTACHMENTSCOLLECTIONNAME);
ExpressionBuilder eb = new ExpressionBuilder();
Expression eObjectIdNotNull = eb.getField(AttachmentEntitySessionCustomizer.OBJECTIDFIELDNAME).notNull();
Expression eObjectId = eb.getField(AttachmentEntitySessionCustomizer.OBJECTIDFIELDNAME).equal(eb.getParameter(descriptor.getPrimaryKeyFields().get(0)));
Expression eObjectTable = eb.getField(AttachmentEntitySessionCustomizer.OBJECTTABLEFIELDNAME).equalsIgnoreCase(descriptor.getTableName());
mapping.setSelectionCriteria(eObjectIdNotNull.and(eObjectId.and(eObjectTable)));
}
...但我在任何实体的删除操作期间都遇到了问题。由于我仍然不明白的原因,JPA 正在附件表上执行更新语句,而不考虑 ObjectTable 列。这是我从表中删除记录时发生的情况PRHTABidParticipationItem
:
Finest: Execute query DeleteObjectQuery(com.tec.uportal.prhta.model.bid.participation.PRHTABidParticipationItem[ id=24 ])
Finest: Execute query DataModifyQuery()
Fine: UPDATE TECAttachment SET ObjectId = ? WHERE (ObjectId = ?)
bind => [null, 24]
Fine: DELETE FROM TECPRHTABidParticipationItem WHERE (Id = ?)
bind => [24]
Finer: end unit of work flush
Finer: resume unit of work
Finer: begin unit of work commit
Finer: commit transaction
我的问题是表上的 UPDATE 语句TECAttachment
更新了具有给定 Id 的所有记录,而不仅仅是那些与 Entity 相关的记录TECPRHTABidParticipationItem
。我想我必须重写 sql 语句DeleteObjectQuery
,或者DataModifyQuery
但不知道如何。
任何帮助将不胜感激。我正在使用 eclipselink-2.7.4
预先感谢!