Hey Jordan,
maybe what you are looking for is Blaze-Persistence Entity Views?
https://github.com/Blazebit/blaze-persistence#entity-view-usage
Query caching should work since it builds on top of scalar queries, but
lazy loading is something I don't support and honestly don't think will
support.
Personally I don't think dynamic-instantiations (ConstructorResults) are
hacky at all. In fact I love dynamic-instantiations for all kinds of use
cases. I wonder if your concern with them is their limited capabilities.
For example, JPA does not define support for nesting dynamic-instantiations