Querydsl继承实体无法获取主键查询类型的替代方案咨询
Hey there! Let’s break down how to solve your problem where entities inheriting a primary key base class don’t include ID fields in generated join queries, while still handling dynamic BooleanExpr filters without falling back to raw SQL. Here are practical, framework-friendly solutions:
1. Explicitly Include ID Fields in Your Query Selection
The simplest fix is to just add the ID fields directly to your list of selected columns. Since your base class handles the primary key, you can reference the ID from the entity itself or the base class (depending on your ORM’s support):
// Example with explicit ID selection query.from(customer) .leftJoin(company).on(customer.company.eq(company.id)) .list( customer.id, // Reference the entity's inherited ID customer.firstName, customer.lastName, company.id, company.name );
If your ORM lets you reuse the base class field (like JOOQ with mapped superclasses), you can cast the entity to the base class for consistency:
query.from(customer) .leftJoin(company).on(customer.company.eq(company.id)) .list( BaseEntity.id.cast(customer), // Reuse base class ID definition customer.firstName, customer.lastName, BaseEntity.id.cast(company), company.name );
This plays nicely with dynamic filters too—just chain your BooleanExpr into a .where() clause as usual.
2. Use DTO Projections for Structured, Reusable Results
For complex queries or reusable result shapes, create a DTO class that includes all the fields you need (including IDs) and use your ORM’s projection feature to map results directly to it. This keeps code clean and simplifies dynamic filter handling:
First, define your DTO:
public class CustomerCompanyDTO { private Long customerId; private String firstName; private String lastName; private Long companyId; private String companyName; // Constructor matching the query selection order public CustomerCompanyDTO(Long customerId, String firstName, String lastName, Long companyId, String companyName) { this.customerId = customerId; this.firstName = firstName; this.lastName = lastName; this.companyId = companyId; this.companyName = companyName; } // Getters for your use case }
Then query and map to the DTO, adding your dynamic filter:
// Example dynamic filter BooleanExpr dynamicFilter = customer.firstName.like("%Doe%").and(company.name.contains("Inc")); List<CustomerCompanyDTO> results = query.from(customer) .leftJoin(company).on(customer.company.eq(company.id)) .where(dynamicFilter) .select( customer.id, customer.firstName, customer.lastName, company.id, company.name ) .fetchInto(CustomerCompanyDTO.class); // ORM-specific projection method
3. Adjust Entity Inheritance Configuration
If your ORM isn’t picking up the inherited ID field automatically, tweak your entity setup to ensure the ID is visible to the query API:
- For JOOQ: Configure your code generator to include base class fields in child entities. In your generator XML, set the base record class:
<generator> <strategy> <matchers> <tables> <table> <recordClass>com.yourpackage.BaseEntity</recordClass> </table> </tables> </matchers> </strategy> </generator> - For Hibernate: Use
@MappedSuperclasson your base primary key class to ensure its fields are mapped to child entity tables. This makescustomer.idandcompany.iddirectly referenceable in HQL or Criteria queries.
Once configured, your ORM will recognize the ID fields automatically, so you can include them in queries without extra work.
4. Use Raw Records and Extract IDs Manually
If you don’t want to create DTOs or adjust configuration, work directly with your ORM’s raw record objects (like JOOQ’s Record or Hibernate’s Object[] results) and extract IDs manually:
BooleanExpr filter = customer.lastName.eq("Smith"); List<Record> records = query.from(customer) .leftJoin(company).on(customer.company.eq(company.id)) .where(filter) .list(customer.id, customer.firstName, customer.lastName, company.id, company.name); // Extract fields from records for (Record record : records) { Long customerId = record.get(customer.id); String firstName = record.get(customer.firstName); Long companyId = record.get(company.id); // Handle other fields as needed }
This works great for quick debugging or one-off queries, though it’s less maintainable for long-term use.
内容的提问来源于stack exchange,提问作者Sandeep Deb

