簡體   English   中英

如何在 @EmbeddedId 屬性中使用 Hibernate 的 @Filter 注釋

[英]How to use Hibernate's @Filter annotation in an @EmbeddedId property

tl;博士

無法使用嵌入的 id 屬性使 Hibernate 過濾器工作。

此處重現問題的示例項目

實際問題

我在這個查詢上掙扎了很長一段時間。

假設以下實體映射示例:

@Entity
class Client {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "client_id")
    @Basic(optional = false)
    private Integer id;

    @Basic(optional = false)
    private String name;

    @OneToMany(mappedBy = "client")
    private List<CarRent> rentHistory;

    // ... getters and setters
}

@Entity
class Car {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "car_id")
    @Basic(optional = false)
    private Integer id;

    @Basic(optional = false)
    private String foo;

    // ... getters and setters
}

@Entity
class CarRent {
    @EmbeddedId
    private CarRentKey carRentKey;

    @MapsId("clientId")
    @ManyToOne()
    @JoinColumn(name = "client_id", nullable = false, insertable = false, updatable = false)
    private Client client;

    @MapsId("carId")
    @ManyToOne()
    @JoinColumn(name = "car_id",  nullable = false, insertable = false, updatable = false)
    private Car car;

    @Basic(optional = false)
    private String bar;

    // ... getters and setters
}

@Embeddable
class CarRentKey {
    private int clientId;
    private int carId;
    @Column(name = "date_due")
    private Date dateDue;

    // ... getters and setters
}

我需要從某個日期獲取所有使用 CarRents 填充的rentHistory 的客戶。 以下查詢對我來說非常適合:

from Client cl
    left outer join fetch c.rentHistory as rent with rent.car = c and rent.dateDue = :date

但是 Hibernate 一直告訴我在獲取異常中的連接時使用過濾器。

我試過了

@Entity
@FilterDef(name="dateDueFilter", parameters= {
    @ParamDef( name="dateDue", type="date" ),
})
@Filters( {
    @Filter(name="dateDueFilter", condition="dateDue = :dateDue"),
})
class CarRent {
    // ...
}

但是當我運行我的查詢時:

EntityManager em;
// ...
Session hibernateSession = em.unwrap(Session.class);
hibernateSession.enableFilter("dateDueFilter").setParameter("dateDue", dateDue);
em.createQuery("from Client cl"
    + "left outer join fetch c.rentHistory");
List<Client> clientList = q.getResultList();
// clientList contains CarRent of all dates

過濾器被忽略。 condition="carRentKey.dateDue = :dateDue"condition="date_due = :dateDue"

我對同一個查詢的其他左外連接使用過濾器,它們工作得很好。 但是這種演化嵌入參數的關系我找不到讓它起作用的方法。

是否可以? 有替代品嗎?

PS:在 where 部分過濾,例如from Client cl left outer join fetch c.rentHistory as rent where rent.dateDue is null or rent.dateDue = :date不是一個選項,因為我的真實查詢有其他連接,結果被過濾並得到當我這樣做時真的很慢。

我不知道,如果我理解正確,但是:

em.createQuery("from Client cl"
+ "left outer join fetch c.rentHistory");

不使用應該被過濾的@Embeddable

編輯:

您需要使用您設置的Session 用它打開交易並查詢結果:

hibernateSession.openTransaction();
results = hibernateSession.createQuery(...).list();
hibernateSession.close();

原來我在這種情況下濫用了@Filter 注釋。

Vlad Mihalcea 幫助我解決了我在 Hibernate 論壇上的帖子中的問題

根據他的方向,我設法使用沒有獲取和結果轉換器的連接查詢解決了沒有過濾器的問題。

該示例的解決方案是:

org.hibernate.query.Query<Client> q = em.createQuery("select cl, cr " + 
        "from Client cl " + 
        "join CarRent cr on cr.client = cl and cr.carRentKey.dateDue = :date")
        .setParameter("date", exampleDate)
        .unwrap(org.hibernate.query.Query.class).setResultTransformer(new BasicTransformerAdapter() {
            @Override
            public List transformList(List list) {
                Map<Serializable, Client> clientMap =
                        new LinkedHashMap<>(list.size());

                for (Object entityArray: list) {
                    if (Object[].class.isAssignableFrom(entityArray.getClass())) {
                        Client client = null;
                        CarRent carRent = null;

                        Object[] tuples = (Object[]) entityArray;

                        for (Object tuple : tuples) {
                            em.detach(tuple);

                            if (tuple instanceof Client) {
                                client = (Client) tuple;
                            }
                            else if (tuple instanceof CarRent) {
                                carRent = (CarRent) tuple;
                            }
                            else {
                                throw new UnsupportedOperationException(
                                    "Tuple " + tuple.getClass() + " is not supported!"
                                );
                            }
                        }

                        if (client != null) {
                            if (!clientMap.containsKey(client.getId())) {
                                clientMap.put(client.getId(), client);
                                client.setRentHistory(new ArrayList<>());;
                            }
                            if (carRent != null) {
                                client.getRentHistory().add(carRent);
                            }
                        }
                    }
                }
                return new ArrayList<>(clientMap.values());
            }
        });

List<Client> clientList = q.getResultList();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM