代码之家  ›  专栏  ›  技术社区  ›  marek.kapowicki

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

  •  3
  • marek.kapowicki  · 技术社区  · 7 年前

    我正在尝试使用spring数据jpa实现简单的cqrs应用程序 因此,我有两个用于编写的表-例如person&汽车(一个人可以拥有汽车列表)。 我还使用创建的一个视图作为“从个人加入汽车中选择*”。。。

    因此,中的示例查询可以给出输出(一个用户有两辆车)

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

    但在我的情况下,它不起作用。你知道怎么修吗 此外,一对一的映射(人最多有一辆车)工作得很酷

    1 回复  |  直到 7 年前
        1
  •  6
  •   Cepr0    7 年前

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

    @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

    已更新

    要将视图映射到实体,可以执行以下操作:

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