当关联表是一个对所有一对多关系时,如何实现一对多映射?
Posted
技术标签:
【中文标题】当关联表是一个对所有一对多关系时,如何实现一对多映射?【英文标题】:How to implement One-to-Many mapping when the associative table is one for all one-many relationships? 【发布时间】:2010-01-04 14:18:05 【问题描述】:一般情况:第一个表代表一个-side,第二个表代表many-side。第三个表作为两者之间的链接。
我的情况:第一张和第二张桌子是一样的。第三个表用作具有一对多关系的所有表对之间的链接。第三个表有附加字段(字符串),其中包含有关 2 个表的信息。
小例子。假设我们有表 Project 和 Category(一个类别 --> 许多项目)。要获取所有具有类别的项目,我们需要执行下一个查询:
select project.name, category.name
from nodeassociation, project, category
where nodeassociation.association_name='ProjectCategory'
and nodeassociation.source_id=project.id
and nodeassociation.sink_id=category.id
如何通过 JPA 指定关联名称标准?
UPD:如果 JPA 不可能,但 hibernate 可以处理它,那么没关系,hibernate 解决方案是什么?
【问题讨论】:
【参考方案1】:建议您在association_name
列过滤的数据库中创建多个视图,然后根据这些在映射中定义多对多关系,并在代码中强制执行一对多语义。这种中间表的情况只有在 Hibernate 中使用多对多映射才能真正处理。
【讨论】:
【参考方案2】:这通常称为qualified association。这种关联应该用Map
而不是List
来实现。在hibernate中没有内置对这些的支持。如果您不关心限定符,则该关联将成为可以使用 hibernate 处理的普通多对多。
但在您的情况下,这不是逻辑级别的合格关联。如果我理解得很好,一个关联表用于表示实际上是什么几个关联:
如果您可以将 db 模式更改为每个 逻辑 关联的表,问题就会消失。 使用数据库视图“模拟”具有单独的表(如 David M 所建议)是一种替代方法。每个逻辑关联创建一个视图并将其映射为多对多。【讨论】:
【参考方案3】:另一个可行的解决方案也许是在休眠中为NodeAssociation
提供一个多态实体。每种关联类型将有一个NodeAssociationX
实体。然后Project
和NodeAssociation
之间存在一对多关联。每个NodeAssociationX
和相应的表/实体(Category
等)都有一对多。您可以映射私有字段,以便提供公共 getter/setter,在逻辑级别提供正确视图。
public List getCategories()
List categories = new ArrayList();
for( NodeAssociation na : nodeAssociations )
if( typeof( na ) = NodeAssociationCategory )
categories.addAll( ((NodeAssociationCategory)na).getCategories() );
return categories;
但这很丑陋。如果可能,请尝试其他解决方案。
【讨论】:
【参考方案4】:@Entity
public class Category
private Integer id;
@Id
public Integer getId()
return this.id;
private LinkBetweenOneCategoryAndManyProject linkClass = new LinkBetweenOneCategoryAndManyProject();
@OneToOne
public LinkBetweenOneCategoryAndManyProject getLinkClass()
return this.linkClass;
public void addProject(Project project)
getLinkClass().getProjectList().add(project);
// delegates to LinkClass
public String getAdditionalProperty()
getLinkClass().getAdditionalProperty();
现在我们的项目
@Entity
public class Project
private Integer id;
@Id
public Integer getId()
return this.id;
现在我们的 LinkBetweenOneCategoryAndManyProject 类
@Entity
public class LinkBetweenOneCategoryAndManyProject
private Integer categoryId;
private String additionalField;
List<Project> projectList;
@Id
public Integer getCategoryId()
return this.categoryId;
@OneToMany
public List<Project> getProjectList()
return projectList;
public String additionalProperty()
return this.additionalField;
所以如果你想检索一个类别及其项目,请执行以下操作
select distinct c from Category c left join fetch c.linkedClass lc left join fetch lc.projectList
请注意,我认为 Category 和 LinkBetweenOneCategoryAndManyProject 之间的关系是 OneToOne
问候,
【讨论】:
【参考方案5】:我找到了适合本机查询的解决方案。
简而言之:
-
我为项目和类别制作了简单的映射,没有任何关系(如 OneToMany)
我将字段
category
添加到项目实体并将其标记为@Transient
在 ProjectDAO 中,我使用原生查询手动将类别插入到项目中。
关于JPA Native Queries 和related jboss docs 的文章是我的起点。
【讨论】:
那么你没有通过hibernate自动持久化关系:如果你在你的项目中添加一个类别,并保存项目,你需要自己持久化类别和关联。你会失去很多休眠的力量。如果您使用它保存对象,DAO 可以完成这项工作,但是您不能简单地加载/修改实体,您需要每次加载/修改/保存。也许 EntityListener 可以以更透明的方式完成这项工作。 我将了解 EntityListener。你是对的,在你的评论出现之前我就知道这一切,但我看不到任何其他出路。我无法修改数据库架构。我的应用程序只从数据库中读取,这允许我手动更改对象。否则我可能会在应用我的解决方案之前三思而后行。以上是关于当关联表是一个对所有一对多关系时,如何实现一对多映射?的主要内容,如果未能解决你的问题,请参考以下文章