คุณสร้างแบบสอบถามที่แตกต่างใน HQL ได้อย่างไร


100

มีวิธีสร้างแบบสอบถามที่แตกต่างใน HQL หรือไม่ ไม่ว่าจะโดยใช้คำหลัก "เฉพาะ" หรือวิธีอื่น ๆ ฉันไม่แน่ใจว่าความแตกต่างเป็นคีย์เวิร์กที่ถูกต้องสำหรับ HQL หรือไม่ แต่ฉันกำลังมองหา HQL ที่เทียบเท่ากับคำหลัก SQL

คำตอบ:


124

นี่คือตัวอย่างของ hql ที่เราใช้ (ชื่อถูกเปลี่ยนเพื่อปกป้องตัวตน)

String queryString = "select distinct f from Foo f inner join foo.bars as b" +
                " where f.creationDate >= ? and f.creationDate < ? and b.bar = ?";
        return getHibernateTemplate().find(queryString, new Object[] {startDate, endDate, bar});

ฉันเคยใช้โหมดไฮเบอร์เนตกับ MySQL เท่านั้น - ไม่แน่ใจว่าจะจัดการกับปัญหา mssql อย่างไร
ฟุต

ฟังก์ชัน getHibernateTemplate () เป็นของ Spring Framework ไม่ใช่ของ API มาตรฐาน คุณรู้จักสิ่งที่เทียบเท่าโดยไม่ใช้ Spring Framework หรือไม่?
Matthieu.V

57

เป็นที่น่าสังเกตว่าdistinctคีย์เวิร์ดใน HQL ไม่ได้แมปโดยตรงกับdistinctคีย์เวิร์ดใน SQL

หากคุณใช้distinctคีย์เวิร์ดใน HQL บางครั้งไฮเบอร์เนตจะใช้distinctคีย์เวิร์ด SQL แต่ในบางสถานการณ์จะใช้ตัวแปลงผลลัพธ์เพื่อสร้างผลลัพธ์ที่แตกต่างกัน ตัวอย่างเช่นเมื่อคุณใช้การรวมภายนอกเช่นนี้:

select distinct o from Order o left join fetch o.lineItems

เป็นไปไม่ได้ที่จะกรองรายการที่ซ้ำกันในระดับ SQL ในกรณีนี้ดังนั้นไฮเบอร์เนตจึงใช้ResultTransformerเพื่อกรองรายการที่ซ้ำกันหลังจากที่ดำเนินการสืบค้น SQL แล้ว



16

ทำอะไรแบบนี้ในครั้งต่อไป

 Criteria crit = (Criteria) session.
                  createCriteria(SomeClass.class).
                  setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

 List claz = crit.list();

1
นั่นคือสิ่งที่ไม่เหมาะสม: แทนที่จะทิ้งการทำซ้ำในระดับฐานข้อมูลมันจะดึงข้อมูลจากฐานข้อมูลไปยังหน่วยความจำด้วยการทำซ้ำและทั้งหมดแล้วทิ้งการทำซ้ำในภายหลัง ขึ้นอยู่กับความถี่ที่ข้อมูลซ้ำซึ่งสามารถเพิ่มการดำเนินการ I / O ได้ค่อนข้างมาก
Haroldo_OK

9

คุณยังสามารถใช้Criteria.DISTINCT_ROOT_ENTITYกับแบบสอบถาม Hibernate HQL ได้เช่นกัน

ตัวอย่าง:

Query query = getSession().createQuery("from java_pojo_name");
query.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
return query.list();

1
นั่นคือสิ่งที่ไม่เหมาะสม: แทนที่จะทิ้งการทำซ้ำในระดับฐานข้อมูลมันจะดึงข้อมูลจากฐานข้อมูลไปยังหน่วยความจำด้วยการทำซ้ำและทั้งหมดแล้วทิ้งการทำซ้ำในภายหลัง ขึ้นอยู่กับความถี่ที่ข้อมูลซ้ำซึ่งสามารถเพิ่มการดำเนินการ I / O ได้ค่อนข้างมาก
Haroldo_OK

4

ฉันมีปัญหาบางอย่างกับตัวแปลงผลลัพธ์รวมกับแบบสอบถาม HQL เมื่อได้ลองแล้ว

final ResultTransformer trans = new DistinctRootEntityResultTransformer();
qry.setResultTransformer(trans);

มันไม่ได้ผล ฉันต้องแปลงร่างด้วยตนเองดังนี้:

final List found = trans.transformList(qry.list());

ด้วย Criteria API transformers ทำงานได้ดี


ไปถึง 10k (:
timmz

3

ข้อความค้นหาหลักของฉันมีลักษณะเช่นนี้ในโมเดล:

@NamedQuery(name = "getAllCentralFinancialAgencyAccountCd", 
    query = "select distinct i from CentralFinancialAgencyAccountCd i")

และฉันก็ยังไม่ได้รับสิ่งที่ฉันคิดว่าเป็นผลลัพธ์ที่ "แตกต่าง" พวกเขาแตกต่างกันเพียงแค่ขึ้นอยู่กับคีย์ผสมหลักบนตาราง

ดังนั้นDaoImplฉันจึงเพิ่มการเปลี่ยนแปลงหนึ่งบรรทัดและได้รับผลตอบแทนที่ "แตกต่าง" ตามที่ฉันต้องการ ตัวอย่างเช่นแทนที่จะเห็น 00 สี่ครั้งตอนนี้ฉันเห็นเพียงครั้งเดียว นี่คือรหัสที่ฉันเพิ่มในDaoImpl:

@SuppressWarnings("unchecked")
public List<CacheModelBase> getAllCodes() {

    Session session = (Session) entityManager.getDelegate();
    org.hibernate.Query q = session.getNamedQuery("getAllCentralFinancialAgencyAccountCd");
    q.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); // This is the one line I had to add to make it do a more distinct query.
    List<CacheModelBase> codes;
    codes = q.list();
    return codes;       
}

ฉันหวังว่านี่จะช่วยได้! อีกครั้งสิ่งนี้อาจใช้ได้ผลก็ต่อเมื่อคุณปฏิบัติตามแนวทางการเขียนโค้ดที่ใช้บริการ dao และประเภทโมเดลของโครงการ


2

สมมติว่าคุณมีเอนทิตีลูกค้าที่แมปกับตาราง CUSTOMER_INFORMATION และคุณต้องการได้รับรายชื่อชื่อลูกค้าที่แตกต่างกัน คุณสามารถใช้ตัวอย่างข้อมูลด้านล่างเพื่อรับสิ่งเดียวกัน

Query distinctFirstName = session.createQuery("select ci.firstName from Customer ci group by ci.firstName");
Object [] firstNamesRows = distinctFirstName.list();

ฉันหวังว่ามันจะช่วยได้ ดังนั้นเราจึงใช้ group by แทนที่จะใช้คำหลักที่แตกต่างกัน

ก่อนหน้านี้ฉันพบว่ามันยากที่จะใช้คำสำคัญที่แตกต่างกันเมื่อฉันต้องการใช้กับหลายคอลัมน์ ตัวอย่างเช่นฉันต้องการรับรายชื่อของ firstName ที่แตกต่างกัน lastName จากนั้นจัดกลุ่มโดยใช้ ฉันมีปัญหาในการใช้ความแตกต่างในกรณีนี้


1

ฉันได้รับคำตอบสำหรับ Hibernate Query Language เพื่อใช้เขตข้อมูลที่แตกต่างกัน คุณสามารถใช้ * SELECT DISTINCT (TO_CITY) จาก FLIGHT_ROUTE * หากคุณใช้แบบสอบถามSQLจะส่งคืนรายการสตริง คุณไม่สามารถใช้มันส่งคืนค่าโดยเอนทิตีคลาส ดังนั้นคำตอบในการแก้ประเภทของปัญหาที่มีการใช้งานHQLกับSQL

FROM FLIGHT_ROUTE F WHERE F.ROUTE_ID IN (SELECT SF.ROUTE_ID FROM FLIGHT_ROUTE SF GROUP BY SF.TO_CITY);

จากSQLคำสั่งแบบสอบถามมี DISTINCT ROUTE_ID และอินพุตเป็นรายการ และในแบบสอบถามกรอง TO_CITY ที่แตกต่างจาก IN (รายการ)

ประเภท Return คือประเภท Entity Bean ดังนั้นคุณจึงสามารถใน AJAX เช่นAutoComplement

ทั้งหมดอาจจะโอเค


1

คุณสามารถใช้คำหลักที่แตกต่างกันได้ในเครื่องมือสร้างเกณฑ์ของคุณเช่นนี้

CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Orders> query = builder.createQuery(Orders.class);
Root<Orders> root = query.from(Orders.class);
query.distinct(true).multiselect(root.get("cust_email").as(String.class));

และสร้างตัวสร้างฟิลด์ในคลาสโมเดลของคุณ


0

หากคุณจำเป็นต้องใช้คำหลักใหม่สำหรับ DTO ที่กำหนดเองในคำสั่งที่คุณเลือกและต้องการองค์ประกอบที่แตกต่างกันให้ใช้คำหลักใหม่นอกเหนือจากสิ่งใหม่ดังนี้ -

select distinct new com.org.AssetDTO(a.id, a.address, a.status) from Asset as a where ...

0

คุณสามารถเพิ่ม GROUP BY แทน Distinct ได้

@Query(value = "from someTableEntity where entityCode in :entityCode" +
            " group by entityCode, entityName, entityType")
List<someTableEntity > findNameByCode(@Param("entityCode") List<String> entityCode);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.