在 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 中连接两个表实体的主要内容,如果未能解决你的问题,请参考以下文章