在 Spring Data JPA 中连接两个表实体

Posted

技术标签:

【中文标题】在 Spring Data JPA 中连接两个表实体【英文标题】:Joining two table entities in Spring Data JPA 【发布时间】:2013-11-27 10:22:51 【问题描述】:

我想写一个像SELECT * FROM Release_date_type a LEFT JOIN cache_media b on a.id=b.id 这样的查询。我是 Spring Data JPA 的新手。我不知道如何为 Join 查询编写实体。这是一个尝试:

@Entity
@Table(name = "Release_date_type")
public class ReleaseDateType 

    @Id
    @GeneratedValue(strategy=GenerationType.TABLE)
    private Integer release_date_type_id;
    // ...
    @Column(nullable = true) 
    private Integer media_Id;
    // with getters and setters...

另一个实体是:

@Entity
@Table(name = "Cache_Media")
public class CacheMedia 

    @Id
    @GeneratedValue(strategy=GenerationType.TABLE)
    private Integer id;
    // ...
    private Date loadDate; //with the getter and setter ..

我想写一个crudRepository这样的接口

public interface ReleaseDateTypeRepository extends CrudRepository<ReleaseDateType, Long>
    @Query("SELECT * FROM Release_date_type a LEFT JOIN cache_media b on a.id=b.id")
    public List<ReleaseDateType> FindAllWithDescriptionQuery();

【问题讨论】:

您需要实体之间的关联。不要存储其他实体的 ID。存储对其他实体的引用,并使用 OneToOne、ManyToOne、OneToMany 和 ManyToMany 关联。您的 JPA 教程(或 Hibernate 文档)应该涵盖这些内容。 您好 Nizet,感谢您的快速回复,您是否有任何教程可以为我提供有关与实体关联的更多信息。 在docs.jboss.org/hibernate/orm/4.2/manual/en-US/html_single中搜索OneToOne、OneToMany、ManyToOne和ManyToMany 实体之间如何添加关联?我不太了解,但我添加为 `@OneToMany @JoinColumn( name="Description") Set cacheMedia;'在 ReleaseDateType 实体中。问题仍然存在。 【参考方案1】:

有关员工拥有一部或多部手机的典型示例,请参阅this wikibook section。

对于您的具体示例,如果您想建立one-to-one 关系,您应该更改 ReleaseDateType 模型中的下一个代码:

@Column(nullable = true) 
private Integer media_Id;

为:

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name="CACHE_MEDIA_ID", nullable=true)
private CacheMedia cacheMedia ;

在 CacheMedia 模型中你需要添加:

@OneToOne(cascade=ALL, mappedBy="ReleaseDateType")
private ReleaseDateType releaseDateType;

然后在您的存储库中您应该替换:

@Query("Select * from A a  left join B b on a.id=b.id")
public List<ReleaseDateType> FindAllWithDescriptionQuery();

作者:

//In this case a query annotation is not need since spring constructs the query from the method name
public List<ReleaseDateType> findByCacheMedia_Id(Integer id); 

或通过:

@Query("FROM ReleaseDateType AS rdt WHERE cm.rdt.cacheMedia.id = ?1")    //This is using a named query method
public List<ReleaseDateType> FindAllWithDescriptionQuery(Integer id);

或者,如果您更喜欢建立 @OneToMany@ManyToOne 关系,您应该更改 ReleaseDateType 模型中的下一个代码:

@Column(nullable = true) 
private Integer media_Id;

为:

@OneToMany(cascade=ALL, mappedBy="ReleaseDateType")
private List<CacheMedia> cacheMedias ;

在 CacheMedia 模型中你需要添加:

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="RELEASE_DATE_TYPE_ID", nullable=true)
private ReleaseDateType releaseDateType;

然后在您的存储库中您应该替换:

@Query("Select * from A a  left join B b on a.id=b.id")
public List<ReleaseDateType> FindAllWithDescriptionQuery();

作者:

//In this case a query annotation is not need since spring constructs the query from the method name
public List<ReleaseDateType> findByCacheMedias_Id(Integer id); 

或通过:

@Query("FROM ReleaseDateType AS rdt LEFT JOIN rdt.cacheMedias AS cm WHERE cm.id = ?1")    //This is using a named query method
public List<ReleaseDateType> FindAllWithDescriptionQuery(Integer id);

【讨论】:

嗨 Bigluis,您确定您的答案是正确的吗?我试了一下,收到了:Caused by: org.hibernate.AnnotationException: Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements: CacheMedia.releaseDateType 看起来,你是对的,应该是List&lt;CacheMedia&gt; cachedMedias而不是CacheMedia cachedMedia 或者如果你更喜欢一对一的关系,你应该在两个模型中都使用@OneToOne public List&lt;ReleaseDateType&gt; findByCacheMedia_Id(Integer id) 如果在一对多的情况下我有 cacheMediaId 数组而不是 Single Integer 怎么办?反之亦然? @bigluis @karmal,你应该在方法方法的末尾使用In,例如:public List&lt;ReleaseDateType&gt; findByCacheMedia_IdIn(List&lt;Integer&gt; ids)【参考方案2】:
@Query("SELECT rd FROM ReleaseDateType rd, CacheMedia cm WHERE ...")

【讨论】:

小心,这会在 ReleaseDateType 和 CacheMedia 之间进行交叉连接,在某些情况下(例如在计数和分组时)可能会产生意外结果。【参考方案3】:

这是一个老问题,但解决方案非常简单。如果您不确定如何在 hibernate 中编写条件、连接等,那么最好的方法是使用本机查询。这不会降低性能并且非常有用。方程。下面

    @Query(nativeQuery = true, value = "your sql query")
returnTypeOfMethod methodName(arg1, arg2);

【讨论】:

使用本机查询会将您锁定到特定的数据库实现。这会阻止您轻松交换数据库。 @Jezor 如果存在复杂的连接和具有 300 或 400 列的表,我发现 ORM 或 JPA 非常困难。特别是在数据仓库项目中。所以 JDBC 就派上用场了。 If you are ever unsure about how to write criterias, joins etc in hibernate then best way is 了解您正在使用的工具。没那么难。

以上是关于在 Spring Data JPA 中连接两个表实体的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Spring Data JPA 连接两个表

如何在 Spring Data JPA 中更改数据库连接?

Spring Data JPA 多个实体类表联合视图查询

Spring Data JPA闭合连接

Spring Data JPA 规范 - 连接中的不同+按列排序

将实体分配给持久性单元(spring-boot,spring-data-jpa)