Hibernate Spring数据JPA+;弹簧批+;休眠和双向@OneToMany关系

Hibernate Spring数据JPA+;弹簧批+;休眠和双向@OneToMany关系,hibernate,jpa,spring-batch,spring-data-jpa,Hibernate,Jpa,Spring Batch,Spring Data Jpa,我看到了与标准实践不一致的行为,并将通过SpringDataJPA保持JPA双向关系作为SpringBatch作业的一部分。我的工作步骤如下所示: @Bean public Step importSinglePatient(StepBuilderFactory stepBuilderFactory, ItemReader<Patient> singlePatientReader,

我看到了与标准实践不一致的行为,并将通过SpringDataJPA保持JPA双向关系作为SpringBatch作业的一部分。我的工作步骤如下所示:

@Bean
public Step importSinglePatient(StepBuilderFactory stepBuilderFactory,
                                ItemReader<Patient> singlePatientReader,
                                ItemWriter<Patient> patientWriter) {
    return stepBuilderFactory.get("importSinglePatient")
        .<Patient, Patient>chunk(1)
        .reader(singlePatientReader)
        .writer(patientWriter)
        .build();
}

@Bean
public Step importSingleEncounter(StepBuilderFactory stepBuilderFactory,
                                  ItemReader<Encounter> singleEncounterReader,
                                  ItemWriter<Encounter> encounterWriter) {
    return stepBuilderFactory.get("importSingleEncounter")
        .<Encounter, Encounter>chunk(1)
        .reader(singleEncounterReader)
        .writer(encounterWriter)
        .build();
}
@Entity
public class Patient implements Serializable {

    public static final long serialVersionUID = 1L;

    @Id
    private Long patientId;

    @OneToMany(mappedBy = "patient", cascade = CascadeType.ALL)
    private List<Encounter> encounters;

    // getters & setters
}

@Entity
public class Encounter implements Serializable {

    public static final long serialVersionUID = 1L;

    @Id
    private Long encounterId;

    @ManyToOne
    @JoinColumn(name = "patient_id")
    private Patient patient;

    // getters & setters
}
@Component
public class EncounterRowMapper implements RowMapper<Encounter> {

    @Autowired
    private PatientRepository patientRepository

    public static final String PATIENT_ID = "PATIENT_ID";

    @Override
    public Encounter mapRow(ResultSet rs, int rowNum) throws SQLException {
        Encounter encounter = new Encounter;
        Patient patient = patientRepository.findOne(rs.getLong(PATIENT_ID));
        encounter.setPatient(patient);
        return encounter;
    }
}
接下来,假设所有患者都已从源数据库读入,并作为前一步的一部分进行了持久化。执行的下一步是使用
行映射器通过
JdbcPagingItemReader
读取所有遭遇(子项)。
RowMapper
代码如下所示:

@Bean
public Step importSinglePatient(StepBuilderFactory stepBuilderFactory,
                                ItemReader<Patient> singlePatientReader,
                                ItemWriter<Patient> patientWriter) {
    return stepBuilderFactory.get("importSinglePatient")
        .<Patient, Patient>chunk(1)
        .reader(singlePatientReader)
        .writer(patientWriter)
        .build();
}

@Bean
public Step importSingleEncounter(StepBuilderFactory stepBuilderFactory,
                                  ItemReader<Encounter> singleEncounterReader,
                                  ItemWriter<Encounter> encounterWriter) {
    return stepBuilderFactory.get("importSingleEncounter")
        .<Encounter, Encounter>chunk(1)
        .reader(singleEncounterReader)
        .writer(encounterWriter)
        .build();
}
@Entity
public class Patient implements Serializable {

    public static final long serialVersionUID = 1L;

    @Id
    private Long patientId;

    @OneToMany(mappedBy = "patient", cascade = CascadeType.ALL)
    private List<Encounter> encounters;

    // getters & setters
}

@Entity
public class Encounter implements Serializable {

    public static final long serialVersionUID = 1L;

    @Id
    private Long encounterId;

    @ManyToOne
    @JoinColumn(name = "patient_id")
    private Patient patient;

    // getters & setters
}
@Component
public class EncounterRowMapper implements RowMapper<Encounter> {

    @Autowired
    private PatientRepository patientRepository

    public static final String PATIENT_ID = "PATIENT_ID";

    @Override
    public Encounter mapRow(ResultSet rs, int rowNum) throws SQLException {
        Encounter encounter = new Encounter;
        Patient patient = patientRepository.findOne(rs.getLong(PATIENT_ID));
        encounter.setPatient(patient);
        return encounter;
    }
}
@组件
公共类遇到错误Apper实现行映射器{
@自动连线
私人病人
公共静态最终字符串PATIENT\u ID=“PATIENT\u ID”;
@凌驾
公共遭遇映射行(ResultSet rs,int rowNum)抛出SQLException{
遭遇=新的遭遇;
患者=患者阳性。芬顿(rs.getLong(患者ID));
遭遇。设定病人(病人);
回击;
}
}
然后将
遭遇
传递给
RepositoryItemWriter
,后者将遭遇保存到
遭遇库

我的理解是,这不是最佳做法,原因如下:

  • 我应该做一个
    病人.getConferences.add(遭遇)
    ;然而,我认为这并不适合划船制图员应该做的事情。也许我错了。可以将其移动到
    ItemProcessor
    并将
    ItemWriter
    改为
    ItemWriter
    。不过,我会一直坚持我的父母,如果孩子是这段关系的主人,这并不理想——父母也不会改变
  • 如果不执行#1,我很可能会看到Hibernate缓存问题。事实似乎并非如此。我已经通过Spring MVC Controld确认,在工作完成后,在我的所有域(包括上面的域)中,父域和子域的关系看起来都与预期的一样,并且没有在我的代码中的任何地方执行
    patient.getConferences.add(Conference)
  • 在整个应用程序中,我有很多双向关系。我读到过双向关系不好,应该用存储库来代替,但我认为Spring Batch的
    ItemReader
    ItemProcessor
    ItemWriter
    模型没有好的方法来实现这一点

  • 希望有人能帮助我理解为什么我看不到第2个和对第1个和第3个的想法。

    您意识到从
    ItemReader
    返回的项目在您使用
    RepositoryItemWriter
    持久化之前与hibernate没有关联,对吗?这只是一个普通的POJO,是的,我理解。我试图理解不执行patient.getConferences.add(Conference)在我的代码中的任意位置为双向关系的另一端添加(Conference)的后果。将遭遇添加到列表在我的代码中不存在,但在遭遇被持久化后,我仍然可以通过控制器看到我的关系的预期行为。双向关系是OO代码中的一个概念…而不是关系数据库。当您检索新对象时,您的JPA提供程序(假设为Hibernate)会为您处理额外的内容。看起来我想得太多了。您意识到从
    ItemReader
    返回的项目与hibernate不关联,直到您使用
    RepositoryItemWriter
    将其持久化,对吗?这只是一个普通的POJO,是的,我理解。我试图理解不执行patient.getConferences.add(Conference)在我的代码中的任意位置为双向关系的另一端添加(Conference)的后果。将遭遇添加到列表在我的代码中不存在,但在遭遇被持久化后,我仍然可以通过控制器看到我的关系的预期行为。双向关系是OO代码中的一个概念…而不是关系数据库。当您检索新对象时,您的JPA提供程序(假设为Hibernate)会为您处理额外的内容。看来我想得太多了。