JPA-在非实体类中连接两个表

我是新手,试图谷歌,但我无法解决我的疑问。 请帮忙。

我试图映射两个实体:我的POJO类PersonC中的PersonA和Person

@Entity class PersonA{ String sample_field; } @Entity class Person{ String id; String name; } 

以上两个是jpa的实体。

现在我想将它们合并到一个pojo类中。

 class PersonC { Strind id; String address; } 

尝试下面的代码,但当我尝试获取地址/外键字段时,它不起作用。

 @SqlResultSetMapping(name="PersonC", classes = { @ConstructorResult(targetClass = PersonC.class, columns = {@ColumnResult(name="name") , @ColumnResult(name="address") )} 

我应该在哪里定义@SqlResultSetMapping,从上面的哪个类? )})

@SqlResultSetMapping可以放在任何实体类中(不要注释POJO – 它不起作用)。 在JPA 2.1版中添加了使用@ConstructorResult映射到POJO类。 与映射一起使用的POJO必须具有正确的构造函数。

必须使用ConstructorResult批注的columns元素以与构造函数的参数列表相同的顺序指定与预期构造函数的参数对应的所有列。

请参考以下有关查询用法的示例,并相应地计算出您的案例。

 @Entity public class Address { @Id int id; String street; } @SqlResultSetMapping(name="PersonDTOMapping", classes = { @ConstructorResult(targetClass = PersonDTO.class, columns = {@ColumnResult(name="name"), @ColumnResult(name="street")} )} ) @Entity public class Person { @Id int id; String name; Address address; } public class PersonDTO { String name; String street; public PersonDTO(String name, String street) { this.name = name; this.street = street; } } // usage Query query = em.createNativeQuery( "SELECT p.name AS name, a.street AS street FROM Person p, Address a WHERE p.address_id=a.id", "PersonDTOMapping"); List result = query.getResultList(); 

请注意,别名( AS nameAS street )必须与@ColumnResult中的名称匹配。 该示例针对Ecliselink 2.5.1进行了测试。

这篇文章涉及Hibernate。

@SqlResultSetMapping@NamedNativeQuery (或@NamedQuery )放在@Entity类定义中的建议并不优雅,显然不遵循关注点分离原则。

更合适的解决方案是使用@MappedSuperclass注释,如下所示:

SingerExtended.java (该类必须是抽象的 ):

 package pl.music.model.singer.extended; import javax.persistence.ColumnResult; import javax.persistence.ConstructorResult; import javax.persistence.MappedSuperclass; import javax.persistence.NamedNativeQueries; import javax.persistence.NamedNativeQuery; import javax.persistence.SqlResultSetMapping; @MappedSuperclass @SqlResultSetMapping( // @formatter:off name = "SingerExtendedMapping", classes = @ConstructorResult( targetClass = SingerExtendedDTO.class, columns = { @ColumnResult(name = "singer_id", type = Long.class), @ColumnResult(name = "first_name"), @ColumnResult(name = "last_name"), @ColumnResult(name = "count_albums", type = Long.class) } ) ) @NamedNativeQueries({ @NamedNativeQuery( name = "SingerExtendedAsc", query = "select" + " singer.singer_id," + " singer.first_name," + " singer.last_name," + " (select count(*) from album where album.singer_id = singer.singer_id) as count_albums" + " from singer" + " group by singer.singer_id" + " order by last_name collate :collation asc, first_name collate :collation asc", resultSetMapping = "SingerExtendedMapping" ) }) // @formatter:on public abstract class SingerExtended { } 

然后DAO类SingerExtendedDAO.java

 package pl.music.model.singer.extended; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.TypedQuery; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class SingerExtendedDAO { @PersistenceContext EntityManager entityManager; @Autowired private String collation; public List getAll(Integer page, Integer count) { TypedQuery query = entityManager.createNamedQuery("SingerExtendedAsc", SingerExtendedDTO.class); query.setParameter("collation", collation); if ((count != null) && (count.intValue() > 0)) { query.setMaxResults(count.intValue()); if ((page != null) && (page.intValue() >= 0)) { query.setFirstResult(count.intValue() * page.intValue()); } } List singerExtendedDTOs = query.getResultList(); return singerExtendedDTOs; } } 

最后是DTO类SingerExtendedDTO.java (你必须提供“完整”构造函数):

 package pl.music.model.singer.extended; public class SingerExtendedDTO { private Long singerId; private String firstName; private String lastName; private Long countAlbums; // IMPORTANT: this constructor must be defined !!! public SingerExtendedDTO(Long singerId, String firstName, String lastName, Long countAlbums) { this.singerId = singerId; this.firstName = firstName; this.lastName = lastName; this.countAlbums = countAlbums; } ... getters & setters ... } 

如果以上述方式将所有这些组合在一起,我们将获得一个合适的解决方案:

  • 一切都在一个包中,
  • 查询声明不会污染任何不关心的实体,
  • 保留关注点分离(分离查询+映射,DAO和DTO)。

刚刚使用JPQL找到了一个更简单的解决方案。 我从@ zbig的答案中偷走了部分示例:

 @Entity public class Address { @Id int id; String street; } @Entity public class Person { @Id int id; String name; Address address; } public class PersonDTO { String name; String street; public PersonDTO(String name, String street) { this.name = name; this.street = street; } } List listOfPersons = em.createQuery("select new com.example.PersonDTO(p.name, a.street) " + "from Person p, Address a " + "WHERE p.address.id=a.id", PersonDTO.class).getResultList(); 

这个解决方案的好处是你不需要使用@SqlResultSetMapping注释,它必须放在任何实体类上,而不是DTO类! 这有时令人困惑,因为实体类只能部分相关(例如,当连接多个表时)。

更多信息在这里