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

87

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

@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();
}

9
你需要在实体之间建立关联。不要存储其他实体的ID。应该存储对其他实体的引用,并使用一对一、多对一、一对多和多对多的关联。你的JPA教程(或Hibernate文档)应该涵盖这个内容。 - JB Nizet
嗨Nizet,感谢您的快速回复。您有没有任何教程可以让我更多地了解实体之间的关联? - S Atah Ahmed Khan
在http://docs.jboss.org/hibernate/orm/4.2/manual/en-US/html_single中搜索OneToOne、OneToMany、ManyToOne和ManyToMany。 - JB Nizet
如何在实体之间添加关联?我不是很清楚,但我在ReleaseDateType实体中添加了`@OneToMany @JoinColumn(name="Description") Set<CacheMedia> cacheMedia;',问题仍然存在。 - S Atah Ahmed Khan
给自己一个好处,不要在列名中使用大写字母。https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS - four-eyes
3个回答

116

一个员工拥有一台或多台手机的典型示例,请参见此Wikibook章节

对于您的特定示例,如果您想建立一个一对一的关系,您应该更改ReleaseDateType模型中的下一行代码:

@Column(nullable = true) 
private Integer media_Id;

for:

@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);

2
你好,Bigluis, 你确定你的答案是正确的吗?我尝试了一下,收到了以下错误信息:Caused by: org.hibernate.AnnotationException: Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements: CacheMedia.releaseDateType - qizer
看起来,你是对的,应该是 List<CacheMedia> cachedMedias 而不是 CacheMedia cachedMedia - Luis Vargas
1
@karmal,你应该在方法结尾处使用In,例如:public List<ReleaseDateType> findByCacheMedia_IdIn(List<Integer> ids) - Luis Vargas
1
Luis Vargas,你确定你的答案是正确的吗?例如,你如何将ManyToOne关联映射到List<CacheMedia> cacheMedias?仅对于OneToMany关联才能映射到List<>。 - Oleg Ushakov
抱歉,我把它们搞反了。我会更正这个答案。你可以查看:https://en.wikibooks.org/wiki/Java_Persistence/ManyToOne - Luis Vargas
显示剩余6条评论

-1
@Query("SELECT rd FROM ReleaseDateType rd, CacheMedia cm WHERE ...")

3
注意,这会在发布日期类型和缓存媒体之间执行一个交叉连接(CROSS JOIN),在某些情况下可能会产生意外的结果(例如在计数和分组时)。 - Ramy Arbid

-5

这是一个老问题,但解决方案非常简单。如果您对在Hibernate中编写条件、连接等操作不确定,最好的方法是使用本地查询。这不会降低性能,非常有用。例如下面的代码:

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

3
使用本地查询将限定您使用特定的数据库实现,这会防止您轻松更换数据库。 - Jezor
5
如果涉及到复杂的联接和拥有300或400列的表格,特别是在数据仓库项目中,我觉得ORM或JPA很困难。因此,使用JDBC会更加方便。 - Stunner
2
如果你对于在Hibernate中如何编写条件、连接等方面感到不确定,那么最好的方法是学习你正在使用的工具。这并不难。 - Vsevolod Golovanov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接