hibernate Spring Data JPA查询返回多个CPC而不是单个CPC

pdsfdshx  于 2023-11-21  发布在  Spring
关注(0)|答案(2)|浏览(197)

我使用Spring Data JPA并定义了一个原生SQL查询,旨在基于特定条件检索给定客户(KLIENCI)的单个CPC记录。然而,该查询返回CPC记录列表而不是单个记录,这不是预期的行为。
下面是SQL查询供参考:

@Query(value = "SELECT k.ID_KLIENT, k.NAZWA, k.EMAIL,  \n" +
        "\tc.ID_CPC , c.DATA_ROZLICZENIA, c.ID_MASZYNA, \n" +
        "\tm.ID_MASZYNA, m.MODEL, m.KOLOR  \n" +
        "FROM KLIENCI k \n" +
        "JOIN CPC c ON c.ID_KLIENT = k.ID_KLIENT \n" +
        "JOIN MASZYNY m ON m.ID_KLIENT  = k.ID_KLIENT AND m.ID_MASZYNA = c.ID_MASZYNA \n" +
        "WHERE c.DATA_ROZLICZENIA = (\n" +
        "\tSELECT MAX (c2.DATA_ROZLICZENIA)\n" +
        "\tFROM CPC c2 \n" +
        "\tWHERE  c2.ID_KLIENT  = k.ID_KLIENT AND c2.ID_MASZYNA = c.ID_MASZYNA \n" +
        ") AND k.ID_KLIENT = :customerId",
        nativeQuery = true)
List<CustomerEntity> findCPCsForCustomer(@Param("customerId") int customerId);

字符串
下面是resultsDBeaver 中的样子:
然而,Spring创建了3个查询而不是一个,并返回指定客户的所有CPC:

Hibernate: 
    SELECT
        k.ID_KLIENT,
        k.NAZWA,
        k.EMAIL,
        c.ID_CPC ,
        c.DATA_ROZLICZENIA,
        c.ID_MASZYNA,
        m.ID_MASZYNA,
        m.MODEL,
        m.KOLOR   
    FROM
        KLIENCI k  
    JOIN
        CPC c 
            ON c.ID_KLIENT = k.ID_KLIENT  
    JOIN
        MASZYNY m 
            ON m.ID_KLIENT  = k.ID_KLIENT 
            AND m.ID_MASZYNA = c.ID_MASZYNA  
    WHERE
        c.DATA_ROZLICZENIA = (
            SELECT
                MAX (c2.DATA_ROZLICZENIA)  
            FROM
                CPC c2   
            WHERE
                c2.ID_KLIENT  = k.ID_KLIENT 
                AND c2.ID_MASZYNA = c.ID_MASZYNA  
        ) 
        AND k.ID_KLIENT = ?
Hibernate: 
    select
        x1_0.id_klient,
        x1_0.id_maszyna,
        x1_0.kolor,
        x1_0.model 
    from
        maszyny x1_0 
    where
        x1_0.id_klient=?
Hibernate: 
    select
        c1_0.id_klient,
        c1_0.id_cpc,
        c1_0.data_rozliczenia,
        c1_0.id_maszyna 
    from
        cpc c1_0 
    where
        c1_0.id_klient=?

客户类别

public class CustomerEntity {

    @Id
    @Column(name = "ID_KLIENT")
    private int id;

    @Column(name = "NAZWA")
    private String name;
    private String email;

    @JsonManagedReference
    @OneToMany(mappedBy = "customerEntity", fetch = FetchType.LAZY)
    private List<XeroEntity> xeroEntityList;

    @JsonManagedReference
    @OneToMany(mappedBy = "customerEntity", fetch = FetchType.LAZY)
    private List<CPCEntity> cpcEntityList;
}

Xero机器类

public class XeroEntity {

    @Id
    @Column(name = "ID_MASZYNA")
    private int id;

    private String model;

    @Column(name = "KOLOR")
    private String color;

    @JsonBackReference
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ID_KLIENT")
    private CustomerEntity customerEntity;
}

CPC类

public class CPCEntity {

    @Id
    @Column(name = "ID_CPC")
    private int id;

    @Column(name = "ID_MASZYNA")
    private int xeroId;
    @Column(name = "DATA_ROZLICZENIA")
    private Date settlementDate;

    @JsonBackReference
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ID_KLIENT")
    private CustomerEntity customerEntity;

}


此外,我尝试使用JPQL来解决这个问题,但遇到了同样的问题。
我已确认数据库架构正确,预期结果是特定客户的每台计算机有一条CPC记录。但是,查询返回多条CPC记录。我不确定为什么会发生这种情况,我正在寻找有关如何修改查询或存储库方法以按预期返回一条CPC的指导。

y0u0uwnf

y0u0uwnf1#

您应该为该查询使用自定义实体,或者仅查询该单个CPC问题是,您正在创建一个(普通)CustomerEntity,这意味着当您向该实体请求其cpcEntityList时,它将查询并返回与客户关联的所有CPC实体,这就是为什么Hibernate执行第二个和第三个查询(您的代码可能同时查询了xeroEntityListcpcEntityList)。
事实上,对于第一个查询,Hibernate忽略了所有没有Map到CustomerEntity的列:它只使用了与CustomerEntity直接关联的列。

myzjeezk

myzjeezk2#

我同意Mark Rotteveel的观点。
延伸到他的,
我强烈建议在数据库上创建一个视图,使用与上面相同的查询(没有where子句),视图的投影接口并从Repository调用它。
但如果由于某种原因无法更改实现,则可以使用@ martyGraph

  • 在CustomerEntity类上,实现@NamedEntityGraph
@Entity
@NamedEntityGraph(name = "graph.customer.cpc", attributeNodes = @NamedAttributeNode("cpcEntityList"))
public class CustomerEntity{//Entity members}

字符串

  • 在存储库上,您可以实现以下
@Query(value = "SELECT k \n" +
    "FROM CustomerEntity k \n" +
    "JOIN k.cpcEntityList c \n" +
    "JOIN k.xeroEntityList m \n" +
    "WHERE (k.id = :customerId) and (m.id = c.xeroId) order by c.settlementDate desc limit 1",
    nativeQuery = false)
@EntityGraph(value = "graph.customer.cpc")
List<CustomerEntity> findCPCsForCustomer(@Param("customerId") int customerId);


请注意,这仍然会执行两个查询,您只是限制了CPCEntity的响应,当XeroEntity出现类似行为时,您将面临挑战
参考文献:
1(https://stackoverflow.com/questions/54521443/when-should-i-use-entitygraph-in-spring-data-jpa)-类似堆栈溢出问题2(https://stackoverflow.com/questions/65649418/hibernate-left-join-fetch-with-on-clause-or-alternative)
我希望这能帮助

相关问题