Java 使用Spring数据存储库和JPQL查询的JPA鉴别器

Java 使用Spring数据存储库和JPQL查询的JPA鉴别器,java,mysql,jpa,eclipselink,spring-data,Java,Mysql,Jpa,Eclipselink,Spring Data,我在MySQL中有两个实体,如下所示。nnm_tran的主键是id和source的组合。讨价还价的主键实际上是指向nnm_tran表的外键链接 我尝试使用JPA继承来表示这些 nnm\u交易实体 @Entity @Table(name = "nnm_tran") @IdClass(CommonTransactionKey.class) @Inheritance(strategy = InheritanceType.JOINED) @DiscriminatorColumn(name = "bar

我在MySQL中有两个实体,如下所示。nnm_tran的主键是id和source的组合。讨价还价的主键实际上是指向nnm_tran表的外键链接

我尝试使用JPA继承来表示这些

nnm\u交易实体

@Entity
@Table(name = "nnm_tran")
@IdClass(CommonTransactionKey.class)
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "bargain_flag", discriminatorType = DiscriminatorType.CHAR)
@DiscriminatorValue("N")
public class CommonTransaction {

    @Id
    @Column(name = "id", nullable = false)
    private String transactionId;

    @Column(name = "plan_number", nullable = false)
    private String planNumber;

    @Column(name = "tran_date")
    private LocalDateTime transactionDatetime;

    @Column(name = "bargain_flag")
    private String bargainFlag;
    ...
}
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "bargains")
@DiscriminatorValue("B")
@PrimaryKeyJoinColumns({ @PrimaryKeyJoinColumn(name = "nnm_tran_id", referencedColumnName = "id"), @PrimaryKeyJoinColumn(name = "nnm_tran_source", referencedColumnName = "source") })
public class Bargain extends CommonTransaction implements Serializable {

    @Column(name = "unit_price")
    private BigDecimal unitPrice;

    @Column(name = "client_price")
    private BigDecimal clientPrice;
    ...
}
public interface CommonTransactionRepository extends CrudRepository<CommonTransaction, CommonTransactionKey> {

    @Query("select t from CommonTransaction t left join IoPlan p ON t.planNumber = p.planNumber "
        + "where (p.planNumber is NULL or p.planNumber = '') "
        + "and t.transactionDatetime between ?1 and ?2 "
        + "and t.cancelled = false")
    public Iterable<CommonTransaction> findOrphanedTransactionsByTranDate(LocalDateTime fromDate, LocalDateTime toDate);
   ...
}
交易实体

@Entity
@Table(name = "nnm_tran")
@IdClass(CommonTransactionKey.class)
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "bargain_flag", discriminatorType = DiscriminatorType.CHAR)
@DiscriminatorValue("N")
public class CommonTransaction {

    @Id
    @Column(name = "id", nullable = false)
    private String transactionId;

    @Column(name = "plan_number", nullable = false)
    private String planNumber;

    @Column(name = "tran_date")
    private LocalDateTime transactionDatetime;

    @Column(name = "bargain_flag")
    private String bargainFlag;
    ...
}
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "bargains")
@DiscriminatorValue("B")
@PrimaryKeyJoinColumns({ @PrimaryKeyJoinColumn(name = "nnm_tran_id", referencedColumnName = "id"), @PrimaryKeyJoinColumn(name = "nnm_tran_source", referencedColumnName = "source") })
public class Bargain extends CommonTransaction implements Serializable {

    @Column(name = "unit_price")
    private BigDecimal unitPrice;

    @Column(name = "client_price")
    private BigDecimal clientPrice;
    ...
}
public interface CommonTransactionRepository extends CrudRepository<CommonTransaction, CommonTransactionKey> {

    @Query("select t from CommonTransaction t left join IoPlan p ON t.planNumber = p.planNumber "
        + "where (p.planNumber is NULL or p.planNumber = '') "
        + "and t.transactionDatetime between ?1 and ?2 "
        + "and t.cancelled = false")
    public Iterable<CommonTransaction> findOrphanedTransactionsByTranDate(LocalDateTime fromDate, LocalDateTime toDate);
   ...
}
我认为到目前为止这一切都是正确连接的。当我附加一个带有自定义查询的spring数据存储库时,我的问题就出现了

存储库

@Entity
@Table(name = "nnm_tran")
@IdClass(CommonTransactionKey.class)
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "bargain_flag", discriminatorType = DiscriminatorType.CHAR)
@DiscriminatorValue("N")
public class CommonTransaction {

    @Id
    @Column(name = "id", nullable = false)
    private String transactionId;

    @Column(name = "plan_number", nullable = false)
    private String planNumber;

    @Column(name = "tran_date")
    private LocalDateTime transactionDatetime;

    @Column(name = "bargain_flag")
    private String bargainFlag;
    ...
}
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "bargains")
@DiscriminatorValue("B")
@PrimaryKeyJoinColumns({ @PrimaryKeyJoinColumn(name = "nnm_tran_id", referencedColumnName = "id"), @PrimaryKeyJoinColumn(name = "nnm_tran_source", referencedColumnName = "source") })
public class Bargain extends CommonTransaction implements Serializable {

    @Column(name = "unit_price")
    private BigDecimal unitPrice;

    @Column(name = "client_price")
    private BigDecimal clientPrice;
    ...
}
public interface CommonTransactionRepository extends CrudRepository<CommonTransaction, CommonTransactionKey> {

    @Query("select t from CommonTransaction t left join IoPlan p ON t.planNumber = p.planNumber "
        + "where (p.planNumber is NULL or p.planNumber = '') "
        + "and t.transactionDatetime between ?1 and ?2 "
        + "and t.cancelled = false")
    public Iterable<CommonTransaction> findOrphanedTransactionsByTranDate(LocalDateTime fromDate, LocalDateTime toDate);
   ...
}
这里的问题是,我是做错了什么,还是这是spring数据和/或eclipselink中的错误


版本:SpringData1.7.2、Eclipselink 2.5.2、MySQL 5.6.28

使用@manish的示例应用程序作为起点,我开始重新分析缺失的复杂性,并很快发现了导致流氓SQL的原因。这取决于我在JPQL中执行的连接

注意:如果你是从未来来到这里的,那么请忽略此答案的其余部分,改为使用@Chris的评论

大多数情况下,我不需要查看甚至思考可以在
@Query

@Query("select t from CommonTransaction t left join IoPlan p ON t.planNumber = p.planNumber "
    + "where (p.planNumber is NULL or p.planNumber = '') "
    + "and t.transactionDatetime between ?1 and ?2 "
    + "and t.cancelled = false")
因此,该表不是作为字段的
CommonTransaction
实体的一部分。甚至这个查询的结果也不太重要,因为它只作为
CommonTransaction
的一次性查询,在
IoPlan
表中没有关联的联接

当我从@manish将连接添加回示例应用程序时,所有连接都以我的应用程序在EclipseLink中的相同方式中断,但在Hibernate中以不同的方式中断。Hibernate需要一个字段供您加入,如果您要求我这样做,那么在
@Query
中编写加入的目的就失败了。事实上,在Hibernate中,您必须纯粹在JPA中定义联接,因此您还可以在JPQL中使用点表示法来访问它

无论如何,按照这个想法,我尝试在我的
CommonTransaction
实体中添加一个虚拟字段来保存
IoPlan
,几乎成功了。它默认了一些连接逻辑,但更接近

SELECT DISTINCT t1.bargain_flag FROM nnm_tran t1 LEFT OUTER JOIN io_plan t0 ON ((t0.ID = t1.IOPLAN_ID) AND (t1.plan_number = t0.plan_number)) WHERE ((((t0.plan_number IS NULL) OR (t0.plan_number = ?)) AND (t1.tran_date BETWEEN ? AND ?)) AND (t1.CANCELLED = ?))
在这种情况下,
t1.IOPLAN\u ID
t0.ID
不存在。因此,我最终在我的
CommonTransaction
实体中定义了整个连接

    @OneToOne
    @JoinColumn(insertable = false, updatable = false, name = "plan_number", referencedColumnName = "plan_number")
    private IoPlan ioPlan;
瞧,它开始工作了。这并不漂亮,现在我有一个多余的连接条件

LEFT OUTER JOIN io_plan t1 
ON ((t1.plan_number = t0.plan_number) AND (t0.plan_number = t1.plan_number)) 

但我可以解决这个问题。我必须为它定义一个字段,这仍然很烦人,我实际上不想也不需要它,更不用说这个查询的结果返回的是没有
IoPlan
CommonTransaction
实体,因此该字段将永久为空。

我怀疑发布的JPA是否会导致发布的SQL查询(JPA查询以
从CommonTransaction t中选择t
开始,而SQL查询是
从nnm_tran t1中选择不同的nnm_tran.讨价还价标志。
。您是否发布了实际代码?我也无法用您提供的版本重现您指出的行为。您可以运行中包含的测试以查看正确的代码。)SQL正在生成。您可以复制示例并将其调整到代码中,以了解为什么会得到不正确的SQL。首先,感谢您花时间和精力为此设置测试。它有助于帮助我看到树木中的树木。:-)为了回答您的问题,是的,这是实际代码,是的,SQL是JPA查询的结果。我已经设法找到了这个怪癖的根源,虽然不是特别优雅,但它目前对我有效。我已经在我的回答中详细说明了它。EclipseLink可能会使用“选择不同的鉴别器列”查询以获取它将需要构建的子类,然后为每个类发出单独的查询。这是可配置的,如下所述:尝试使用自定义程序将其设置为使用外部联接在单个查询中读入子类,如果查询中存在排序或分页,则应使用外部联接。@Chris Holy s**t零食。这太糟糕了关闭我自己的解决方案。添加了自定义程序并已关闭并运行。它确实只需要切换到外部联接即可。:-)谢谢