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

MaN*_*aNn 14 java mysql sql jpa

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

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

@Entity
class PersonA{
     String sample_field;
}

@Entity
class Person{
     String id;
     String name;

}
Run Code Online (Sandbox Code Playgroud)

以上两个是jpa的实体.

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

class PersonC
{
   Strind id;
   String address;
}
Run Code Online (Sandbox Code Playgroud)

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

@SqlResultSetMapping(name="PersonC", 
classes = {
   @ConstructorResult(targetClass = PersonC.class, 
    columns = {@ColumnResult(name="name")
              , @ColumnResult(name="address")
    )}
Run Code Online (Sandbox Code Playgroud)

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

zbi*_*big 34

@SqlResultSetMapping可以放在任何实体类中(不要注释POJO - 它不起作用).@ConstructorResult在JPA 2.1版中添加了映射到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();
Run Code Online (Sandbox Code Playgroud)

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


xag*_*far 10

刚刚使用 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();
Run Code Online (Sandbox Code Playgroud)

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

更多信息请点击此处

  • 你是英雄,我希望我能对这个答案投票 100 次,并将你的答案打印到我的 T 恤上并永远穿着:) (2认同)

pch*_*que 5

这篇文章与休眠有关。

把的建议@SqlResultSetMapping@NamedNativeQuery(或@NamedQuery)内部@Entity类定义是不优雅,看样子不遵循的原则,关注分离。

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

SingerExtended.java(该类必须是abstract):

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 {
}
Run Code Online (Sandbox Code Playgroud)

然后是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<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;
    }

}
Run Code Online (Sandbox Code Playgroud)

最后是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 ...
}
Run Code Online (Sandbox Code Playgroud)

如果按照上述方式将所有内容放在一起,我们将获得适当的解决方案:

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

  • 我收到“没有为该名称定义查询 [SingerExtendedAsc]”。有任何想法吗? (2认同)