从一个视图映射具有嵌入式List的实体

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从一个视图映射具有嵌入式List的实体相关的知识,希望对你有一定的参考价值。

我试图使用spring-data-jpa实现简单的cqrs应用程序所以我有2个表用于编写 - 例如人和汽车(一个人可以有汽车列表)。我还使用了一个作为select * from person join car创建的视图...

所以来自的示例查询可以给出输出(一个用户有2辆车)

firstName|lastName| car_brand | car_model |
marek    |k       | tesla     | s         |
marek    |k       | mercdes   | 190       |  

现在我试图在jpa中映射这个视图,我试图嵌入列表

@Embeddable
class CarSnapshot {
   private String carBrand;
   private String carModel;
}

class PersonSnapshot {
   private String firstName;
   @Embedded // I tried also @OneToMany and ElementCollection
   private Set<CarSnapshot> cars;
}

但它在我的情况下不起作用。你有任何想法如何解决它而且一对一的映射(人有最多一辆车)非常酷

答案

如果要使用嵌入类型,可以执行以下操作:

@Entity
@Table(name = "persons")
public class Person {
    @Id
    private Integer id;

    @ElementCollection
    @CollectionTable(name = "person_cars", joinColumns = @JoinColumn(name = "person_id"), foreignKey = @ForeignKey(name = "person_cars_persons_fk"))
    private List<PersonCar> cars;
}

@Embeddable
class PersonCar {

   @Column(length = 32, nullable = false)
   private String brand;

   @Column(length = 32, nullable = false)
   private String model;
}

在这种情况下,您的db模式可以是这样的:

create table persons (
  id integer not null constraint persons_pkey primary key,
);

create table person_cars (
  person_id integer not null constraint person_cars_persons_fk references persons,

  brand varchar(32) not null,
  model varchar(32) not null,

  constraint supported_docs_pkey primary key (doc_type, country_code)
);

(这是postgresql方言)

更多信息在这里:Hibernate User Guide - Collections of value types

更新

要将View映射到实体,您可以这样做:

@Data // It's Lombok annotation - c-tor, getters/setters etc.
@Entity
@Immutable
@IdClass(View.class)
@Subselect("select p.name as person_name, c.brand as car_brand, c.model as car_model from persons p join cars c on p.id = c.person_id")
public class View implements Serializable {

    @Id private String personName;
    @Id private String carBrand;
    @Id private String carModel;
}

您可以使用带有视图名称的@Subselect注释,而不是使用@Table注释:

@Data
@Entity
@Immutable
@IdClass(View.class)
@Table(name = "my_view")
public class View implements Serializable {...}

工作demo

更新2

后处理的解决方法......

DTO的:

@Value
public class PersonDto {
    private String name;
    private List<CarDto> cars = new ArrayList<>();

    public PersonDto addCars(List<CarDto> cars) {
        this.cars.addAll(cars);
        return this;
    }
}

@Value
public class CarDto {
    private String brand;
    private String model;
}

ViewRepo

public interface ViewRepo extends JpaRepository<View, View> {

    List<View> findByPersonName(String name);

    default PersonDto getPersonByName(String personName) {
        return new PersonDto(personName)
                .addCars(findByPersonName(personName)
                        .stream()
                        .map(p -> new CarDto(p.getCarBrand(), p.getCarModel()))
                        .collect(Collectors.toList()));
    }
}

以上是关于从一个视图映射具有嵌入式List的实体的主要内容,如果未能解决你的问题,请参考以下文章

EF添加关联的提示问题:映射从第 260 行开始的片段时有问题:

实体框架代码优先 - 为 SqlQuery 配置映射

如何从片段内的列表视图打开链接网址?

EntityFramework 映射片段问题

实体框架6不适用于Temporal表

添加新实体标量时实体框架 4 映射片段错误