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

Map the entity with embedded List from one view

我正在尝试使用 spring-data-jpa 实现简单的 cqrs 应用程序 所以我有 2 个表用来写 - 例如人和汽车(一个人可以有汽车清单)。 我还使用创建为 select * 来自 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;
}

在这种情况下,您的数据库架构可以是这样的:

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

已更新

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

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

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

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

工作demo

已更新 2

解决方法 post-processing...

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