Spring Data JDBC - Lazy Loading/Projection - spring-data-jdbc

For Spring Data JDBC, is lazy loading possible ? Or is projection possible ?
I would only want two fields in my data but it seems that Spring JDBC is fetching the whole thing.
#Repository
public interface AppUserRepo extends CrudRepository<AppUser, Long> {
#Query("select id, firstname, lastname from m_appuser where firstname=:firstName")
public AppUser findByAppUserName(#Param("firstName") String firstName);
}
This resulted to getting all associated objects.
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [SELECT "ROLE"."ID" AS "ID", "ROLE"."DEL" AS "DEL", "ROLE"."NAME" AS "NAME", "ROLE"."VERSION" AS "VERSION", "ROLE"."DISABLED" AS "DISABLED", "ROLE"."CREATED_DATE" AS "CREATED_DATE", "ROLE"."DESCRIPTION" AS "DESCRIPTION", "ROLE"."REFERENCE_NUMBER" AS "REFERENCE_NUMBER", "ROLE"."LAST_MODIFIED_DATE" AS "LAST_MODIFIED_DATE", "createdBy"."ID" AS "CREATEDBY_ID", "createdBy"."DEL" AS "CREATEDBY_DEL", "createdBy"."EMAIL" AS "CREATEDBY_EMAIL", "createdBy"."STATUS" AS "CREATEDBY_STATUS", "createdBy"."VERSION" AS "CREATEDBY_VERSION", "createdBy"."ENABLED" AS "CREATEDBY_ENABLED", "createdBy"."PASSWORD" AS "CREATEDBY_PASSWORD", "createdBy"."USER_TYPE" AS "CREATEDBY_USER_TYPE", "createdBy"."BRANCH_ID" AS "CREATEDBY_BRANCH_ID", "createdBy"."USERNAME" AS "CREATEDBY_USERNAME", "createdBy"."LASTNAME" AS "CREATEDBY_LASTNAME", "createdBy"."FIRSTNAME" AS "CREATEDBY_FIRSTNAME", "createdBy"."CLEAR_PSWD" AS "CREATEDBY_CLEAR_PSWD", "createdBy"."MIDDLENAME" AS "CREATEDBY_MIDDLENAME", "createdBy"."CREATED_DATE" AS "CREATEDBY_CREATED_DATE", "createdBy"."FAILED_LOGINS" AS "CREATEDBY_FAILED_LOGINS", "createdBy"."MOBILE_NUMBER" AS "CREATEDBY_MOBILE_NUMBER", "createdBy"."LAST_LOGIN_DATE" AS "CREATEDBY_LAST_LOGIN_DATE", "createdBy"."LAST_MODIFIED_DATE" AS "CREATEDBY_LAST_MODIFIED_DATE", "createdBy"."ACCOUNT_NON_LOCKED" AS "CREATEDBY_ACCOUNT_NON_LOCKED", "createdBy"."PROFILE_EXPIRY_DATE" AS "CREATEDBY_PROFILE_EXPIRY_DATE", "createdBy"."IS_SELF_SERVICE_USER" AS "CREATEDBY_IS_SELF_SERVICE_USER", "createdBy"."MOBILE_COUNTRY_CODE" AS "CREATEDBY_MOBILE_COUNTRY_CODE", "createdBy"."ACCOUNT_NON_EXPIRED" AS "CREATEDBY_ACCOUNT_NON_EXPIRED", "createdBy"."PASSWORD_NEVER_EXPIRES" AS "CREATEDBY_PASSWORD_NEVER_EXPIRES", "createdBy"."CREDENTIALS_NON_EXPIRED" AS "CREATEDBY_CREDENTIALS_NON_EXPIRED", "createdBy"."LAST_TIME_PASSWORD_UPDATED" AS "CREATEDBY_LAST_TIME_PASSWORD_UPDATED", "createdBy"."FIRST_TIME_LOGIN_REMAINING" AS "CREATEDBY_FIRST_TIME_LOGIN_REMAINING", "lastModifiedBy"."ID" AS "LASTMODIFIEDBY_ID", "lastModifiedBy"."DEL" AS "LASTMODIFIEDBY_DEL", "lastModifiedBy"."EMAIL" AS "LASTMODIFIEDBY_EMAIL", "lastModifiedBy"."STATUS" AS "LASTMODIFIEDBY_STATUS", "lastModifiedBy"."VERSION" AS "LASTMODIFIEDBY_VERSION", "lastModifiedBy"."ENABLED" AS "LASTMODIFIEDBY_ENABLED", "lastModifiedBy"."USERNAME" AS "LASTMODIFIEDBY_USERNAME", "lastModifiedBy"."BRANCH_ID" AS "LASTMODIFIEDBY_BRANCH_ID", "lastModifiedBy"."PASSWORD" AS "LASTMODIFIEDBY_PASSWORD", "lastModifiedBy"."LASTNAME" AS "LASTMODIFIEDBY_LASTNAME", "lastModifiedBy"."USER_TYPE" AS "LASTMODIFIEDBY_USER_TYPE", "lastModifiedBy"."CLEAR_PSWD" AS "LASTMODIFIEDBY_CLEAR_PSWD", "lastModifiedBy"."FIRSTNAME" AS "LASTMODIFIEDBY_FIRSTNAME", "lastModifiedBy"."MIDDLENAME" AS "LASTMODIFIEDBY_MIDDLENAME", "lastModifiedBy"."CREATED_DATE" AS "LASTMODIFIEDBY_CREATED_DATE", "lastModifiedBy"."FAILED_LOGINS" AS "LASTMODIFIEDBY_FAILED_LOGINS", "lastModifiedBy"."MOBILE_NUMBER" AS "LASTMODIFIEDBY_MOBILE_NUMBER", "lastModifiedBy"."LAST_LOGIN_DATE" AS "LASTMODIFIEDBY_LAST_LOGIN_DATE", "lastModifiedBy"."ACCOUNT_NON_LOCKED" AS "LASTMODIFIEDBY_ACCOUNT_NON_LOCKED", "lastModifiedBy"."LAST_MODIFIED_DATE" AS "LASTMODIFIEDBY_LAST_MODIFIED_DATE", "lastModifiedBy"."MOBILE_COUNTRY_CODE" AS "LASTMODIFIEDBY_MOBILE_COUNTRY_CODE", "lastModifiedBy"."PROFILE_EXPIRY_DATE" AS "LASTMODIFIEDBY_PROFILE_EXPIRY_DATE", "lastModifiedBy"."ACCOUNT_NON_EXPIRED" AS "LASTMODIFIEDBY_ACCOUNT_NON_EXPIRED", "lastModifiedBy"."IS_SELF_SERVICE_USER" AS "LASTMODIFIEDBY_IS_SELF_SERVICE_USER", "lastModifiedBy"."PASSWORD_NEVER_EXPIRES" AS "LASTMODIFIEDBY_PASSWORD_NEVER_EXPIRES", "lastModifiedBy"."CREDENTIALS_NON_EXPIRED" AS "LASTMODIFIEDBY_CREDENTIALS_NON_EXPIRED", "lastModifiedBy"."FIRST_TIME_LOGIN_REMAINING" AS "LASTMODIFIEDBY_FIRST_TIME_LOGIN_REMAINING", "lastModifiedBy"."LAST_TIME_PASSWORD_UPDATED" AS "LASTMODIFIEDBY_LAST_TIME_PASSWORD_UPDATED", "createdBy_staff"."ID" AS "CREATEDBY_STAFF_ID", "createdBy_staff"."ACTIVE" AS "CREATEDBY_STAFF_ACTIVE", "createdBy_staff"."MOBILE_NO" AS "CREATEDBY_STAFF_MOBILE_NO", "createdBy_staff"."LASTNAME" AS "CREATEDBY_STAFF_LASTNAME", "createdBy_staff"."FIRSTNAME" AS "CREATEDBY_STAFF_FIRSTNAME", "createdBy_staff"."EXTERNAL_ID" AS "CREATEDBY_STAFF_EXTERNAL_ID", "createdBy_staff"."LOAN_OFFICER" AS "CREATEDBY_STAFF_LOAN_OFFICER", "createdBy_staff"."DISPLAY_NAME" AS "CREATEDBY_STAFF_DISPLAY_NAME", "createdBy_staff"."JOINING_DATE" AS "CREATEDBY_STAFF_JOINING_DATE", "createdBy_staff"."EMAIL_ADDRESS" AS "CREATEDBY_STAFF_EMAIL_ADDRESS", "createdBy_staff"."ORGANISATIONAL_ROLE_TYPE" AS "CREATEDBY_STAFF_ORGANISATIONAL_ROLE_TYPE", "createdBy_office"."ID" AS "CREATEDBY_OFFICE_ID", "createdBy_office"."NAME" AS "CREATEDBY_OFFICE_NAME", "createdBy_office"."HIERARCHY" AS "CREATEDBY_OFFICE_HIERARCHY", "createdBy_office"."EXTERNAL_ID" AS "CREATEDBY_OFFICE_EXTERNAL_ID", "createdBy_office"."OPENING_DATE" AS "CREATEDBY_OFFICE_OPENING_DATE", "createdBy_tellerId"."ID" AS "CREATEDBY_TELLERID_ID", "createdBy_tellerId"."DEL" AS "CREATEDBY_TELLERID_DEL", "createdBy_tellerId"."NAME" AS "CREATEDBY_TELLERID_NAME", "createdBy_tellerId"."VERSION" AS "CREATEDBY_TELLERID_VERSION", "createdBy_tellerId"."TELLER_CODE" AS "CREATEDBY_TELLERID_TELLER_CODE", "createdBy_tellerId"."DESCRIPTION" AS "CREATEDBY_TELLERID_DESCRIPTION", "createdBy_tellerId"."CREATED_DATE" AS "CREATEDBY_TELLERID_CREATED_DATE", "createdBy_tellerId"."LAST_MODIFIED_DATE" AS "CREATEDBY_TELLERID_LAST_MODIFIED_DATE", "createdBy_departmentId"."ID" AS "CREATEDBY_DEPARTMENTID_ID", "createdBy_departmentId"."DEL" AS "CREATEDBY_DEPARTMENTID_DEL", "createdBy_departmentId"."VERSION" AS "CREATEDBY_DEPARTMENTID_VERSION", "createdBy_departmentId"."CREATED_DATE" AS "CREATEDBY_DEPARTMENTID_CREATED_DATE", "createdBy_departmentId"."DEPARTMENT_NAME" AS "CREATEDBY_DEPARTMENTID_DEPARTMENT_NAME", "createdBy_departmentId"."DEPARTMENT_CODE" AS "CREATEDBY_DEPARTMENTID_DEPARTMENT_CODE", "createdBy_departmentId"."REFERENCE_NUMBER" AS "CREATEDBY_DEPARTMENTID_REFERENCE_NUMBER", "createdBy_departmentId"."LAST_MODIFIED_DATE" AS "CREATEDBY_DEPARTMENTID_LAST_MODIFIED_DATE", "lastModifiedBy_staff"."ID" AS "LASTMODIFIEDBY_STAFF_ID", "lastModifiedBy_staff"."ACTIVE" AS "LASTMODIFIEDBY_STAFF_ACTIVE", "lastModifiedBy_staff"."MOBILE_NO" AS "LASTMODIFIEDBY_STAFF_MOBILE_NO", "lastModifiedBy_staff"."LASTNAME" AS "LASTMODIFIEDBY_STAFF_LASTNAME", "lastModifiedBy_staff"."FIRSTNAME" AS "LASTMODIFIEDBY_STAFF_FIRSTNAME", "lastModifiedBy_staff"."EXTERNAL_ID" AS "LASTMODIFIEDBY_STAFF_EXTERNAL_ID", "lastModifiedBy_staff"."DISPLAY_NAME" AS "LASTMODIFIEDBY_STAFF_DISPLAY_NAME", "lastModifiedBy_staff"."LOAN_OFFICER" AS "LASTMODIFIEDBY_STAFF_LOAN_OFFICER", "lastModifiedBy_staff"."JOINING_DATE" AS "LASTMODIFIEDBY_STAFF_JOINING_DATE", "lastModifiedBy_staff"."EMAIL_ADDRESS" AS "LASTMODIFIEDBY_STAFF_EMAIL_ADDRESS", "lastModifiedBy_staff"."ORGANISATIONAL_ROLE_TYPE" AS "LASTMODIFIEDBY_STAFF_ORGANISATIONAL_ROLE_TYPE", "lastModifiedBy_office"."ID" AS "LASTMODIFIEDBY_OFFICE_ID", "lastModifiedBy_office"."NAME" AS "LASTMODIFIEDBY_OFFICE_NAME", "lastModifiedBy_office"."HIERARCHY" AS "LASTMODIFIEDBY_OFFICE_HIERARCHY", "lastModifiedBy_office"."EXTERNAL_ID" AS "LASTMODIFIEDBY_OFFICE_EXTERNAL_ID", "lastModifiedBy_office"."OPENING_DATE" AS "LASTMODIFIEDBY_OFFICE_OPENING_DATE", "lastModifiedBy_tellerId"."ID" AS "LASTMODIFIEDBY_TELLERID_ID", "lastModifiedBy_tellerId"."DEL" AS "LASTMODIFIEDBY_TELLERID_DEL", "lastModifiedBy_tellerId"."NAME" AS "LASTMODIFIEDBY_TELLERID_NAME", "lastModifiedBy_tellerId"."VERSION" AS "LASTMODIFIEDBY_TELLERID_VERSION", "lastModifiedBy_tellerId"."TELLER_CODE" AS "LASTMODIFIEDBY_TELLERID_TELLER_CODE", "lastModifiedBy_tellerId"."CREATED_DATE" AS "LASTMODIFIEDBY_TELLERID_CREATED_DATE", "lastModifiedBy_tellerId"."DESCRIPTION" AS "LASTMODIFIEDBY_TELLERID_DESCRIPTION", "lastModifiedBy_tellerId"."LAST_MODIFIED_DATE" AS "LASTMODIFIEDBY_TELLERID_LAST_MODIFIED_DATE", "lastModifiedBy_departmentId"."ID" AS "LASTMODIFIEDBY_DEPARTMENTID_ID", "lastModifiedBy_departmentId"."DEL" AS "LASTMODIFIEDBY_DEPARTMENTID_DEL", "lastModifiedBy_departmentId"."VERSION" AS "LASTMODIFIEDBY_DEPARTMENTID_VERSION", "lastModifiedBy_departmentId"."CREATED_DATE" AS "LASTMODIFIEDBY_DEPARTMENTID_CREATED_DATE", "lastModifiedBy_departmentId"."DEPARTMENT_CODE" AS "LASTMODIFIEDBY_DEPARTMENTID_DEPARTMENT_CODE", "lastModifiedBy_departmentId"."DEPARTMENT_NAME" AS "LASTMODIFIEDBY_DEPARTMENTID_DEPARTMENT_NAME", "lastModifiedBy_departmentId"."REFERENCE_NUMBER" AS "LASTMODIFIEDBY_DEPARTMENTID_REFERENCE_NUMBER", "lastModifiedBy_departmentId"."LAST_MODIFIED_DATE" AS "LASTMODIFIEDBY_DEPARTMENTID_LAST_MODIFIED_DATE", "createdBy_staff_image"."ID" AS "CREATEDBY_STAFF_IMAGE_ID", "createdBy_staff_image"."LOCATION" AS "CREATEDBY_STAFF_IMAGE_LOCATION", "createdBy_staff_image"."STORAGE_TYPE" AS "CREATEDBY_STAFF_IMAGE_STORAGE_TYPE", "createdBy_staff_office"."ID" AS "CREATEDBY_STAFF_OFFICE_ID", "createdBy_staff_office"."NAME" AS "CREATEDBY_STAFF_OFFICE_NAME", "createdBy_staff_office"."HIERARCHY" AS "CREATEDBY_STAFF_OFFICE_HIERARCHY", "createdBy_staff_office"."EXTERNAL_ID" AS "CREATEDBY_STAFF_OFFICE_EXTERNAL_ID", "createdBy_staff_office"."OPENING_DATE" AS "CREATEDBY_STAFF_OFFICE_OPENING_DATE", "createdBy_departmentId_branch"."ID" AS "CREATEDBY_DEPARTMENTID_BRANCH_ID", "createdBy_departmentId_branch"."NAME" AS "CREATEDBY_DEPARTMENTID_BRANCH_NAME", "createdBy_departmentId_branch"."HIERARCHY" AS "CREATEDBY_DEPARTMENTID_BRANCH_HIERARCHY", "createdBy_departmentId_branch"."EXTERNAL_ID" AS "CREATEDBY_DEPARTMENTID_BRANCH_EXTERNAL_ID", "createdBy_departmentId_branch"."OPENING_DATE" AS "CREATEDBY_DEPARTMENTID_BRANCH_OPENING_DATE", "createdBy_departmentId_sourcePlaceCode"."ID" AS "CREATEDBY_DEPARTMENTID_SOURCEPLACECODE_ID", "createdBy_departmentId_sourcePlaceCode"."LABEL" AS "CREATEDBY_DEPARTMENTID_SOURCEPLACECODE_LABEL", "createdBy_departmentId_sourcePlaceCode"."POSITION" AS "CREATEDBY_DEPARTMENTID_SOURCEPLACECODE_POSITION", "createdBy_departmentId_sourcePlaceCode"."IS_ACTIVE" AS "CREATEDBY_DEPARTMENTID_SOURCEPLACECODE_IS_ACTIVE", "createdBy_departmentId_sourcePlaceCode"."MANDATORY" AS "CREATEDBY_DEPARTMENTID_SOURCEPLACECODE_MANDATORY", "createdBy_departmentId_sourcePlaceCode"."DESCRIPTION" AS "CREATEDBY_DEPARTMENTID_SOURCEPLACECODE_DESCRIPTION", "lastModifiedBy_staff_image"."ID" AS "LASTMODIFIEDBY_STAFF_IMAGE_ID", "lastModifiedBy_staff_image"."LOCATION" AS "LASTMODIFIEDBY_STAFF_IMAGE_LOCATION", "lastModifiedBy_staff_image"."STORAGE_TYPE" AS "LASTMODIFIEDBY_STAFF_IMAGE_STORAGE_TYPE", "lastModifiedBy_staff_office"."ID" AS "LASTMODIFIEDBY_STAFF_OFFICE_ID", "lastModifiedBy_staff_office"."NAME" AS "LASTMODIFIEDBY_STAFF_OFFICE_NAME", "lastModifiedBy_staff_office"."HIERARCHY" AS "LASTMODIFIEDBY_STAFF_OFFICE_HIERARCHY", "lastModifiedBy_staff_office"."EXTERNAL_ID" AS "LASTMODIFIEDBY_STAFF_OFFICE_EXTERNAL_ID", "lastModifiedBy_staff_office"."OPENING_DATE" AS "LASTMODIFIEDBY_STAFF_OFFICE_OPENING_DATE", "lastModifiedBy_departmentId_branch"."ID" AS "LASTMODIFIEDBY_DEPARTMENTID_BRANCH_ID", "lastModifiedBy_departmentId_branch"."NAME" AS "LASTMODIFIEDBY_DEPARTMENTID_BRANCH_NAME", "lastModifiedBy_departmentId_branch"."HIERARCHY" AS "LASTMODIFIEDBY_DEPARTMENTID_BRANCH_HIERARCHY", "lastModifiedBy_departmentId_branch"."EXTERNAL_ID" AS "LASTMODIFIEDBY_DEPARTMENTID_BRANCH_EXTERNAL_ID", "lastModifiedBy_departmentId_branch"."OPENING_DATE" AS "LASTMODIFIEDBY_DEPARTMENTID_BRANCH_OPENING_DATE", "lastModifiedBy_departmentId_sourcePlaceCode"."ID" AS "LASTMODIFIEDBY_DEPARTMENTID_SOURCEPLACECODE_ID", "lastModifiedBy_departmentId_sourcePlaceCode"."LABEL" AS "LASTMODIFIEDBY_DEPARTMENTID_SOURCEPLACECODE_LABEL", "lastModifiedBy_departmentId_sourcePlaceCode"."POSITION" AS "LASTMODIFIEDBY_DEPARTMENTID_SOURCEPLACECODE_POSITION", "lastModifiedBy_departmentId_sourcePlaceCode"."IS_ACTIVE" AS "LASTMODIFIEDBY_DEPARTMENTID_SOURCEPLACECODE_IS_ACTIVE", "lastModifiedBy_departmentId_sourcePlaceCode"."MANDATORY" AS "LASTMODIFIEDBY_DEPARTMENTID_SOURCEPLACECODE_MANDATORY", "lastModifiedBy_departmentId_sourcePlaceCode"."DESCRIPTION" AS "LASTMODIFIEDBY_DEPARTMENTID_SOURCEPLACECODE_DESCRIPTION", "createdBy_departmentId_sourcePlaceCode_code"."ID" AS "CREATEDBY_DEPARTMENTID_SOURCEPLACECODE_CODE_ID", "createdBy_departmentId_sourcePlaceCode_code"."NAME" AS "CREATEDBY_DEPARTMENTID_SOURCEPLACECODE_CODE_NAME", "createdBy_departmentId_sourcePlaceCode_code"."SYSTEM_DEFINED" AS "CREATEDBY_DEPARTMENTID_SOURCEPLACECODE_CODE_SYSTEM_DEFINED", "lastModifiedBy_departmentId_sourcePlaceCode_code"."ID" AS "LASTMODIFIEDBY_DEPARTMENTID_SOURCEPLACECODE_CODE_ID", "lastModifiedBy_departmentId_sourcePlaceCode_code"."NAME" AS "LASTMODIFIEDBY_DEPARTMENTID_SOURCEPLACECODE_CODE_NAME", "lastModifiedBy_departmentId_sourcePlaceCode_code"."SYSTEM_DEFINED" AS "LASTMODIFIEDBY_DEPARTMENTID_SOURCEPLACECODE_CODE_SYSTEM_DEFINED" FROM "ROLE" LEFT OUTER JOIN "APP_USER" AS "createdBy" ON "createdBy"."ROLE" = "ROLE"."ID" LEFT OUTER JOIN "APP_USER" AS "lastModifiedBy" ON "lastModifiedBy"."ROLE" = "ROLE"."ID" LEFT OUTER JOIN "STAFF" AS "createdBy_staff" ON "createdBy_staff"."APP_USER" = "createdBy"."ID" LEFT OUTER JOIN "OFFICE" AS "createdBy_office" ON "createdBy_office"."APP_USER" = "createdBy"."ID" LEFT OUTER JOIN "TELLER" AS "createdBy_tellerId" ON "createdBy_tellerId"."APP_USER" = "createdBy"."ID" LEFT OUTER JOIN "DEPARTMENT" AS "createdBy_departmentId" ON "createdBy_departmentId"."APP_USER" = "createdBy"."ID" LEFT OUTER JOIN "STAFF" AS "lastModifiedBy_staff" ON "lastModifiedBy_staff"."APP_USER" = "lastModifiedBy"."ID" LEFT OUTER JOIN "OFFICE" AS "lastModifiedBy_office" ON "lastModifiedBy_office"."APP_USER" = "lastModifiedBy"."ID" LEFT OUTER JOIN "TELLER" AS "lastModifiedBy_tellerId" ON "lastModifiedBy_tellerId"."APP_USER" = "lastModifiedBy"."ID" LEFT OUTER JOIN "DEPARTMENT" AS "lastModifiedBy_departmentId" ON "lastModifiedBy_departmentId"."APP_USER" = "lastModifiedBy"."ID" LEFT OUTER JOIN "IMAGE" AS "createdBy_staff_image" ON "createdBy_staff_image"."STAFF" = "createdBy_staff"."ID" LEFT OUTER JOIN "OFFICE" AS "createdBy_staff_office" ON "createdBy_staff_office"."STAFF" = "createdBy_staff"."ID" LEFT OUTER JOIN "OFFICE" AS "createdBy_departmentId_branch" ON "createdBy_departmentId_branch"."DEPARTMENT" = "createdBy_departmentId"."ID" LEFT OUTER JOIN "CODE_VALUE" AS "createdBy_departmentId_sourcePlaceCode" ON "createdBy_departmentId_sourcePlaceCode"."DEPARTMENT" = "createdBy_departmentId"."ID" LEFT OUTER JOIN "IMAGE" AS "lastModifiedBy_staff_image" ON "lastModifiedBy_staff_image"."STAFF" = "lastModifiedBy_staff"."ID" LEFT OUTER JOIN "OFFICE" AS "lastModifiedBy_staff_office" ON "lastModifiedBy_staff_office"."STAFF" = "lastModifiedBy_staff"."ID" LEFT OUTER JOIN "OFFICE" AS "lastModifiedBy_departmentId_branch" ON "lastModifiedBy_departmentId_branch"."DEPARTMENT" = "lastModifiedBy_departmentId"."ID" LEFT OUTER JOIN "CODE_VALUE" AS "lastModifiedBy_departmentId_sourcePlaceCode" ON "lastModifiedBy_departmentId_sourcePlaceCode"."DEPARTMENT" = "lastModifiedBy_departmentId"."ID" LEFT OUTER JOIN "CODE" AS "createdBy_departmentId_sourcePlaceCode_code" ON "createdBy_departmentId_sourcePlaceCode_code"."CODE_VALUE" = "createdBy_departmentId_sourcePlaceCode"."ID" LEFT OUTER JOIN "CODE" AS "lastModifiedBy_departmentId_sourcePlaceCode_code" ON "lastModifiedBy_departmentId_sourcePlaceCode_code"."CODE_VALUE" = "lastModifiedBy_departmentId_sourcePlaceCode"."ID" WHERE "ROLE"."APP_USER" = ?]; nested exception is com.ibm.db2.jcc.am.SqlSyntaxErrorException: DB2 SQL Error: SQLCODE=-204, SQLSTATE=42704, SQLERRMC=DB2INST1.ROLE, DRIVER=4.21.29

General principles.
There is no concept of lazy loading in Spring Data JDBC.
This is possibly the most important design decision in Spring Data JDBC and it is crucial to understand it:
Spring Data JDBC will load a complete aggregate, including everything that is referenced by normal Java references. Things that should not or must not be part of the same aggregate must not be referenced by a java reference, but only by id. See Spring Data JDBC, References, and Aggregates for a more in detail discussion of this.
Projections in the way other Spring Data modules do them, by using an interface as the return value aren't currently supported, but you may use DTOs, i.e. dedicated classes that have a subset of the properties of the entity class, as a return value.
What is going on in your case.
AppUser seems to have a reference to a Role which gets loaded by a separate select statement, which is what you are seeing. This select is not controlled by the query in the annotation. Instead the AppUser instance gets initialised by the result from the specified query. Then Spring Data JDBC notes that there are further references and resolves those by the aforementioned SQL statement(s).
I have no idea why you get an exception. Possibly because the query is to long?
What you should do
Create a new class AppUserProjection containing only the fields in your query and us it as your return value. Since there is no reference to Role or other references, no further SQL statments will get executed.
Even better and more important though, I think your domain model is not suitable for use with Spring Data JDBC. AppUser and Role seem to be two different aggregates and therefore one MUST REFERENCE THE OTHER BY ID. This makes the lazy loading project go away immediately. To navigate from the AppUser to the Role you use the id to load the Role from a separate RoleRepository. This even allows you to implement any caching strategy you want.
Apart from references you may populate an entity from a SQL query that does not load all properties. All properties not reflected in the SQL will not be set on the entity and will therefore have their respective default value.
This is not recommended though, because it creates incomplete entities and any code in your entity class needs to handle possibly missing values, which complicates the code. Use dedicated DTOs instead, as described above.

Related

CriteriaAPI Query with Join by a string value

I have currently a query with a bunch of filters, which makes sense to use the Criteria API, unfortunately I have this query that uses a Join which uses a string value instead of a relationship. This is an example of the query:
SELECT ua.id,
COALESCE(uf.status, f.status) AS status,
r.name,
ua.companyname,
ua.firstname,
ua.lastname,
ua.usergroup,
ua.email,
ua.country,
ua.continent
FROM useraccount ua
JOIN userrole ur on ua.id = ur.userid
JOIN role r on ur.roleid = r.id and r.eventgroupid = 1
JOIN feature f on f.name = 'Locked'
LEFT JOIN userfeature uf on uf.featureid = f.id AND uf.userid = ua.id;
As you can see the problem of the query is that I want to use COALESCE operation to get a UserFeature status if present, if not use the default status from the Feature table.
The feature table is just a simple one with id, name and the status, it is only related to UserFeature and UserFeature at the same time is related to the UserAccount.
As you might guess the CriteriaAPi doesn't allows a Join<> by a regular string value. I have tried to get my mind around to get how can I change the select statement to be more aligned with what CriteriaAPI offers, but I haven't found anything on this.
I'm using PostgreSQL and Hibernate 5.4.32 (by using the spring starter jpa)

Load only some elements of a nested collection efficiently with LINQ

I have the following LINQ query (using EF Core 6 and MS SQL Server):
var resultSet = dbContext.Systems
.Include(system => system.Project)
.Include(system => system.Template.Type)
.Select(system => new
{
System = system,
TemplateText = system.Template.TemplateTexts.FirstOrDefault(templateText => templateText.Language == locale.LanguageIdentifier),
TypeText = system.Template.Type.TypeTexts.FirstOrDefault(typeText => typeText.Language == locale.LanguageIdentifier)
})
.FirstOrDefault(x => x.System.Id == request.Id);
The requirement is to retrieve the system matching the requested ID and load its project, template and template's type info. The template has multiple TemplateTexts (one for each translated language) but I only want to load the one matching the requested locale, same deal with the TypeTexts elements of the template's type.
The LINQ query above does that in one query and it gets converted to the following SQL query (I edited the SELECT statements to use * instead of the long list of columns generated):
SELECT [t1].*, [t2].*, [t5].*
FROM (
SELECT TOP(1) [p].*, [t].*, [t0].*
FROM [ParkerSystems] AS [p]
LEFT JOIN [Templates] AS [t] ON [p].[TemplateId] = [t].[Id]
LEFT JOIN [Types] AS [t0] ON [t].[TypeId] = [t0].[Id]
LEFT JOIN [Projects] AS [p0] ON [p].[Project_ProjectId] = [p0].[ProjectId]
WHERE [p].[SystemId] = #__request_Id_1
) AS [t1]
LEFT JOIN (
SELECT [t3].*
FROM (
SELECT [t4].*, ROW_NUMBER() OVER(PARTITION BY [t4].[ReferenceId] ORDER BY [t4].[Id]) AS [row]
FROM [TemplateTexts] AS [t4]
WHERE [t4].[Language] = #__locale_LanguageIdentifier_0
) AS [t3]
WHERE [t3].[row] <= 1
) AS [t2] ON [t1].[Id] = [t2].[ReferenceId]
LEFT JOIN (
SELECT [t6].*
FROM (
SELECT [t7].*, ROW_NUMBER() OVER(PARTITION BY [t7].[ReferenceId] ORDER BY [t7].[Id]) AS [row]
FROM [TypeTexts] AS [t7]
WHERE [t7].[Language] = #__locale_LanguageIdentifier_0
) AS [t6]
WHERE [t6].[row] <= 1
) AS [t5] ON [t1].[Id0] = [t5].[ReferenceId]
which is not bad, it's not a super complicated query, but I feel like my requirement can be solved with a much simpler SQL query:
SELECT *
FROM [Systems] AS [p]
JOIN [Templates] AS [t] ON [p].[TemplateId] = [t].[Id]
JOIN [TemplateTexts] AS [tt] ON [p].[TemplateId] = [tt].[ReferenceId]
JOIN [Types] AS [ty] ON [t].[TypeId] = [ty].[Id]
JOIN [TemplateTexts] AS [tyt] ON [ty].[Id] = [tyt].[ReferenceId]
WHERE [p].[SystemId] = #systemId and tt.[Language] = 2 and tyt.[Language] = 2
My question is: is there a different/simpler LINQ expression (either in Method syntax or Query syntax) that produces the same result (get all info in one go) because ideally I'd like to not have to have an anonymous object where the filtered sub-collections are aggregated. For even more brownie points, it'd be great if the generated SQL would be simpler/closer to what I think would be a simple query.
Is there a different/simpler LINQ expression (...) that produces the same result
Yes (maybe) and no.
No, because you're querying dbContext.Systems, therefore EF will return all systems that match your filter, also when they don't have TemplateTexts etc. That's why it has to generate outer joins. EF is not aware of your apparent intention to skip systems without these nested data or of any guarantee that these systems don't occur in the database. (Which you seem to assume, seeing the second query).
That accounts for the left joins to subqueries.
These subqueries are generated because of FirstOrDefault. In SQL it always requires some sort of subquery to get "first" records of one-to-many relationships. This ROW_NUMBER() OVER construction is actually quite efficient. Your second query doesn't have any notion of "first" records. It'll probably return different data.
Yes (maybe) because you also Include data. I'm not sure why. Some people seem to think Include is necessary to make subsequent projections (.Select) work, but it isn't. If that's your reason to use Includes then you can remove them and thus remove the first couple of joins.
OTOH you also Include system.Project which is not in the projection, so you seem to have added the Includes deliberately. And in this case they have effect, because the entire entity system is in the projection, otherwise EF would ignore them.
If you need the Includes then again, EF has to generate outer joins for the reason mentioned above.
EF decides to handle the Includes and projections separately, while hand-crafted SQL, aided by prior knowledge of the data could do that more efficiently. There's no way to affect that behavior though.
This LINQ query is close to your SQL, but I'm afraid of correctness of the result:
var resultSet =
(from system in dbContext.Systems
from templateText in system.Template.TemplateTexts
where templateText.Language == locale.LanguageIdentifier
from typeText in system.Template.Type.TypeTexts
where typeText.Language == locale.LanguageIdentifier
select new
{
System = system,
TemplateText = templateText
TypeText = typeText
})
.FirstOrDefault(x => x.System.Id == request.Id);

ORACLE - DECODE view predicate and apply on base table

I have a view defined as below
CREATE VIEW DQ_DB.DQM_RESULT_VIEW
AS SELECT
res.ACTIVE_FL AS ACTIVE_FL,
res.VERSION as VERSION,
res.rule_constituents_tx,
nvl(ruletable.rule_desc,'N/A') AS rule_ds,
nvl(res.effective_dt, TO_DATE('31-dec-9999','dd-mon-yyyy')) AS effective_dt,
nvl(res.rule_id,'N/A') AS rule_id,
res.audit_update_ts AS rule_processed_at,
res.load_dt,
res.vendor_group_key,
nvl(res.vendor_entity_key,'N/A') AS vendor_entity_key,
res.vendor_entity_producer_nm,
(SELECT category_value_tx FROM dq_db.category_lookup_view WHERE category_nm = 'RESULT_STATUS_NB' AND category_value_cd = res.result_status_nb ) AS result,
--catlkp.category_value_tx as result,
res.entity_type,
nvl(rgrp.grp_nm,'N/A') AS rule_category,
nvl(ruletable.rule_nm,'N/A') AS rule_nm,
feedsumm.feed_run_nm AS file_nm,
res.application_id AS application,
res.data_source_id AS datasource,
res.entity_nm,
res.rule_entity_effective_dt,
res.result_id,
dim.dimension_nm,
dim.sub_dimension_nm,
ruletable.execution_env AS execution_env,
ruletable.ops_action AS ops_action,
rulefunctiontable.func_nm AS rule_func_nm,
-- nvl2(res.primary_dco_sid,dq_db.get_dco_name(res.primary_dco_sid),null) AS dco_primary,
-- nvl2(res.delegate_dco_sid,dq_db.get_dco_name(res.delegate_dco_sid),null) AS dco_delegate,
res.primary_dco_sid AS dco_primary,
res.delegate_dco_sid AS dco_delegate,
ruletable.data_concept_id AS data_concept_id,
res.latest_result_fl as latest_result_fl,
res.batch_execution_ts as batch_execution_ts
FROM
dq_db.dqm_result res
--LEFT OUTER JOIN dq_db.category_lookup_view catlkp on (catlkp.category_nm = 'RESULT_STATUS_NB' AND catlkp.category_value_cd = res.result_status_nb)
LEFT OUTER JOIN dq_db.feed_run_summary feedsumm ON res.vendor_group_key = feedsumm.batch_id
LEFT OUTER JOIN dq_db.dqm_rule ruletable ON res.rule_id = ruletable.rule_id
LEFT OUTER JOIN dq_db.dqm_rule_grp rgrp ON ruletable.rule_grp_id = rgrp.rule_grp_id
LEFT OUTER JOIN dq_db.dqm_rule_function rulefunctiontable ON ruletable.func_id = rulefunctiontable.func_id
LEFT OUTER JOIN dq_db.dq_dimension_view dim ON dim.dimension_id = ruletable.dimension_id
result column of view is a lookup value generated from subquery condition which translates code as
below.
0|PASS 1|ALERT 2|ERROR
My web application adds few predicates to this view which are pushed to base tables. But one particular predicate on view shown below is not pushed due to inline nature of the predicate.
select * from dqm_result_view where result IN ('ALERT','ERROR')
Right now this query applies filter after view JOINs are executed as there is no way to push predicate to DQM_RESULT table.
What is need is.. if we get that result predicate then apply code 0,1,2 instead of applying result predicate at end so that data is filtered ahead of time for JOINs from DQM_RESULT base table and thus improve performance. Any idea on how to achieve this?

Performing two Left Outer Joins in a Single LINQ to CRM query

I'm attempting to perform two left outer joins in my CRM online 2015 Update 1 instance, but I am getting an error. This is what I have currently:
var query_join8 = from a in crmContext.AccountSet
join c in crmContext.ContactSet
on a.PrimaryContactId.Id equals c.ContactId
into gr
from c_joined in gr.DefaultIfEmpty()
join c in crmContext.ContactSet
on a.Name equals c.FullName
into gr2
from c2_joined in gr2.DefaultIfEmpty()
select new
{
contact_name = c_joined.FullName,
account_name = a.Name,
other_name = c2_joined.FullName
};
When I attempt to execute it, I get this error:
An exception of type 'System.NotSupportedException' occurred in
Microsoft.Xrm.Sdk.dll but was not handled in user code
Additional information: The method 'GroupJoin' cannot follow the
method 'SelectMany' or is not supported. Try writing the query in
terms of supported methods or call the 'AsEnumerable' or 'ToList'
method before calling unsupported methods.
If I comment out the second Join, it works fine:
var query_join8 = from a in crmContext.AccountSet
join c in crmContext.ContactSet
on a.PrimaryContactId.Id equals c.ContactId
into gr
from c_joined in gr.DefaultIfEmpty()
//join c in crmContext.ContactSet
//on a.Name equals c.FullName
//into gr2
//from c2_joined in gr2.DefaultIfEmpty()
select new
{
contact_name = c_joined.FullName,
account_name = a.Name,
//other_name = c2_joined.FullName
};
Microsoft Documentation:
Defining how to perform a Left Join: http://msdn.microsoft.com/en-us/library/gg509017.aspx#LeftJoin
Blog Describing that it is supported: http://blogs.msdn.com/b/crminthefield/archive/2013/01/14/crm-2011-sdk-query-limitations-by-api.aspx
The documentation on CRM 2015 still states outer joins are not supported. (MSDN: Use LINQ to construct a query) I know there is also an example on MSDN showing a left join (Sample: Complex LINQ queries), but I doubt if under the hood this is actually transformed into a single QueryExpression. So, I guess you are hitting the limits of the capabilities of Ling for CRM.

Child collection and one to one

My entity "TimeRecord" has a collection of "WayPoints" and two one-to-one properties "Location" and "WayData".
Each property can be null.
I need to export all Time Records with initialized properties for a specific User.
I actually had a working solution but then I started to use NHibernateProiler and first I noticed that this code results in a ridiculous number of query’s against db.
var query = (from timeRecord in Session.Query<TimeRecord>()
.Where(tr => tr.User.Id == userid)
select timeRecord);
Then I changed my code to:
var query = (from post in Session.Query<TimeRecord>()
.Fetch(x => x.Location)
.Fetch(x => x.WayData)
.FetchMany(x => x.WayPoints)
.Where(tr => tr.User.Id == userid)
select post);
Which lead me to the Cartesian product problem.
Right now I’m experimenting with this piece of code:
var sql1 = "from TimeRecord b left outer join fetch b.Location where b.User.Id=:User_id";
var sql2 = "from TimeRecord b left outer join fetch b.WayData where b.User.Id=:User_id";
var sql3 = "from TimeRecord b left inner join fetch b.WayPoints where b.User.Id=:User_id";
var result = Session.CreateMultiQuery()
.Add(Session.CreateQuery(sql1))
.Add(Session.CreateQuery(sql2))
.Add(Session.CreateQuery(sql3))
.SetParameter("User_id", userid)
.List();
But I can’t say if this is the correct approach or if this is even possible with nHibernate. Can someone help me with that?
The 1+N issue is a usual with the entity/collection mapping and ORM tools. But NHibernate has a very nice solution how to manage it properly. It is called:
19.1.5. Using batch fetching
This setting will allow:
To continue querying the root entity (TimeRecord in our case)
No fetching inside of the query (Session.Query<TimeRecord>()). That means we do have support for correct paging. (Take(), Skip() will be executed over the flat root table)
All the collections will be loaded with their own SELECT statements (could seem as disadvantage but se below)
There will be much more less SELECTs then 1+N. All of them will be batched. E.g. by 25 records
all the native mapping (lazy loading of collections) will still be in place...
The xml mapping example:
-- class level
<class name="Location" batch-size="25 ...
-- collection level
<batch name="Locations" batch-size="25" ...
I would suggest to apply that over all your collections/classes. With Fluent mapping it could be done also with conventions
The fluent mapping:
// class
public LocationMap()
{
Id(x => x....
...
BatchSize(25);
// collection
HasMany(x => x.Locations)
...
.BatchSize(25);

Resources