我遇到的问题比我预期的要多,因此我决定降低第一次迭代的要求。我目前正在尝试仅允许在整个“公司”实体上使用这样的扩展,换句话说,我放弃了整个所有者的要求。因此,问题可以重新表述为“如何在运行时向实体添加虚拟列(在另一个实体中的条目,像额外的列)?”
我的当前实现如下(过滤掉不相关的部分):
@Entity
class Company {
@Transient
public Set<Extension> getExtensions { .. }
@OneToMany(fetch = FetchType.EAGER)
@JoinColumn(name = "companyId")
public Set<ExtensionEntry> getExtensionEntries { .. }
}
@Entity
class Extension {
public String getLabel() { .. }
public ValueType getValueType() { .. }
}
@Entity
class ExtensionEntry {
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "extensionId")
public Extension getExtension() { .. }
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "companyId", insertable = false, updatable = false)
public Company getCompany() { .. }
public String getValueAsString() { .. }
}
现有的实现允许我加载一个公司实体,Hibernate将确保所有其扩展条目也被加载,并且我可以访问对应于这些扩展条目的扩展。换句话说,如果我想在网页上显示此附加信息,我可以按以下方式访问所有必需的信息:
Company company = findCompany();
for (ExtensionEntry extensionEntry : company.getExtensionEntries()) {
String label = extensionEntry.getExtension().getLabel();
String value = extensionEntry.getValueAsString();
}
然而,这里有许多问题。首先,当使用FetchType.EAGER与@OneToMany时,Hibernate使用外连接,因此会返回重复的公司(每个ExtensionEntry一个)。可以通过使用Criteria.DISTINCT_ROOT_ENTITY来解决这个问题,但这反过来又会导致我的分页出现错误,因此这不是一个可接受的答案。另外一个选择是将FetchType更改为LAZY,但这意味着我将始终需要“手动”加载ExtensionEntries。就我所知,例如,如果我加载100个Companies的列表,我必须循环查询每个公司,生成100个SQL语句,这在性能上是不可接受的。
另一个问题是,理想情况下,我希望在加载公司时加载所有的扩展。我的意思是说,我希望@Transient getter命名为getExtensions(),以返回任何公司的所有扩展。问题在于,公司和扩展之间没有外键关系,因为扩展不适用于任何单个公司实例,而是适用于所有公司。目前,我可以通过像下面展示的代码来解决这个问题,但是当访问引用实体时(例如,如果我有一个实体Employee,它引用了Company,则通过employee.getCompany()检索到的Company将不会加载扩展):
List<Company> companies = findAllCompanies();
List<Extension> extensions = findAllExtensions();
for (Company company : companies) {
company.setExtensions(extensions);
}
目前我就在这个位置,不知道如何继续以解决这些问题。 我想我的整个设计可能有缺陷,但我不确定还有其他什么方法可以尝试。
欢迎提出任何想法和建议!