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

Java JPA-在非实体类中连接两个表,java,mysql,sql,jpa,Java,Mysql,Sql,Jpa,我是一个新手,尝试用谷歌搜索,但我无法解决我的问题。 请帮忙 我试图映射两个实体:我的POJO类PersonC中的PersonA和Person @Entity class PersonA{ String sample_field; } @Entity class Person{ String id; String name; } 以上两个是jpa的实体 现在我想把它们合并到一个pojo类中 class PersonC { Strind id; St

我是一个新手,尝试用谷歌搜索,但我无法解决我的问题。 请帮忙

我试图映射两个实体:我的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<PersonDTO> result = query.getResultList();
@实体
公共课堂演讲{
@Id-int-Id;
弦街;;
}
@SQLResultsMapping(name=“PersonDTOMapping”,
类别={
@ConstructorResult(targetClass=PersonDTO.class,
columns={@ColumnResult(name=“name”),@ColumnResult(name=“street”)}
)}
)
@实体
公共阶层人士{
@Id-int-Id;
字符串名;
地址;
}  
公共类个人{
字符串名;
弦街;;
公众人物(字符串名称、字符串街道){
this.name=名称;
这条街;
}
}
//用法
Query Query=em.createNativeQuery(
“选择p.name作为姓名,a.street作为个人p的街道,地址a,其中p.Address_id=a.id”,
“个人地图”);
List result=query.getResultList();
请注意,别名(
AS name
AS street
)必须与
@ColumnResult
中的名称匹配。
该示例针对Ecliselink 2.5.1进行了测试。

刚刚发现了一个使用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<PersonDTO> 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();
@实体
公共课堂演讲{
@Id-int-Id;
弦街;;
}
@实体
公共阶层人士{
@Id-int-Id;
字符串名;
地址;
}  
公共类个人{
字符串名;
弦街;;
公众人物(字符串名称、字符串街道){
this.name=名称;
这条街;
}
}
List listOfPersons=em.createQuery(“选择new com.example.PersonDTO(p.name,a.street)”+
“来自p人,地址a”+
“其中p.address.id=a.id”,PersonDTO.class).getResultList();
此解决方案的好处是您不需要使用@SqlResultSetMapping注释,必须将@SqlResultSetMapping注释放置在任何实体类上,而不是DTO类上!这有时会让人困惑,因为实体类只能部分相关(例如在连接多个表时)


更多信息

这篇文章是关于冬眠的

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

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

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

然后DAO类singerestendedao.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 {
}
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<SingerExtendedDTO> getAll(Integer page, Integer count) {
        TypedQuery<SingerExtendedDTO> 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<SingerExtendedDTO> singerExtendedDTOs = query.getResultList();
        return singerExtendedDTOs;
    }

}
如果按照上述方式将所有这些放在一起,我们将得到一个合适的解决方案:

  • 一切都在一个包裹里
  • 查询声明不会污染任何无关实体
  • 保持关注点的分离(分离的查询+映射、DAO和DTO)

那么,将其映射到pojo的优势是什么呢?您能否给出一个使用@EntityResult而不是@ColumnResult的JPA2.0示例?非常类似于使用新关键字的JPQL。所以,有趣的是,我们现在陷入了旧的JPA。如果您还将表PAIRS OF theu SHOES作为列表加入,您会如何映射它?正如下面的解决方案中所述,您并不总是有实体类来添加注释,至少不是正确的实体类。调用存储过程将结果映射到DTO时非常常见,并且您没有该DTO的实体版本(出于明显的原因)。下面的解决方案解决了这个问题。这是一个比IMHO接受的解决方案好得多的解决方案。在许多情况下,当您将存储的proc结果映射到DTO时,您没有一个实体来放置这些注释。这很容易就解决了这个问题。我没有为这个名称定义任何查询[SingleXtendeDASC]。有什么想法吗?你是英雄,我希望我能把这个答案提高100倍,并把你的答案印在我的T恤上,永远穿着:)
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 ...
}