Java 17 "records" create some interesting possibilities as quick DTOs. Mapping complex SQL is still rather painful in Cayenne. You'd get an Object[] as a result and/or need complex scripting within SQL. I think records and some API tweaks can help:
1. SQL result mapping. record MyRecord(String lastName, String firstName) {} // non-persistent, not in DataMap SQLSelect.query("select * from x") // new API analogous to "#result" directive but simpler to use // also we can implement some implicit name conversions ("AB_C" -> "abC") .resultColumn(0, "firstName") .resultColumn("LAST_NAME", "lastName") // new API - auto-mapping the result to a POJO (record in this case) .selectAs(MyRecord.class, context); 2. Entity result mapping (e.g. a replacement of column and data row queries). class MyEntity extends _MyEntity {} // Persistent record MyEntityDTO(..) {} // non-persistent, not in DataMap List<MyEntityDTO> result = ObjectSelect(MyEntity.class) .where(MyEntity.NAME.like("Joe")) .prefetch(MyEntity.ANOTHER.joint()) // new API - auto-mapping the result to a POJO (record in this case) .selectAs(MyEntityDTO.class, context); It will be faster than fetching MyEntity (without ObjectContext registration, uniquing, merging), and will be a good replacement of column queries API, requiring no explicit column declarations, and producing a specific type instead of Object[]. Prefetches can be auto-mapped to record hierarchies. Both examples would work with either records or regular POJOs, it is just that record definitions are so easy to create on the spot, that they can be used in a multitude of very narrow contexts. Andrus