OneToMany mapping generates the wrong hibernate SQL during findById/findAll - java

I cannot get the below OneToMany mappings to work properly, even though they are supposedly validated (by hibernate.ddl-auto=validate). I can insert all entities in the application with no problems, but while doing a findAll or findById, the queries Hibernate generates for me are wrong and result in exceptions. This is very likely due to a problem with my OneToMany mappings, or lack of a ManyToOne mapping but I don't see how to make it work.
Currently, the following tables exist in my postgres12 database:
CREATE TABLE battlegroups (
id uuid,
gameworld_id uuid,
name varchar(255),
PRIMARY KEY(id)
);
CREATE TABLE battlegroup_players (
id uuid,
battlegroup_id uuid,
player_id integer,
name varchar(255),
tribe varchar(255),
PRIMARY KEY (id)
);
CREATE TABLE battlegroup_player_villages(
battlegroup_id uuid,
player_id integer,
village_id integer,
x integer,
y integer,
village_name varchar(255),
tribe varchar(255),
PRIMARY KEY(battlegroup_id, player_id, village_id, x, y)
);
These are mapped to the following entities in Kotlin:
#Entity
#Table(name = "battlegroups")
class BattlegroupEntity(
#Id
val id: UUID,
#Column(name = "gameworld_id")
val gameworldId: UUID,
val name: String? = "",
#OneToMany(mappedBy = "battlegroupId", cascade = [CascadeType.ALL],fetch = FetchType.EAGER)
private val players: MutableList<BattlegroupPlayerEntity>)
#Entity
#Table(name = "battlegroup_players")
class BattlegroupPlayerEntity(#Id
val id: UUID,
#Column(name = "battlegroup_id")
val battlegroupId: UUID,
#Column(name = "player_id")
val playerId: Int,
val name: String,
#Enumerated(EnumType.STRING)
val tribe: Tribe,
#OneToMany(mappedBy= "id.playerId" , cascade = [CascadeType.ALL], fetch = FetchType.EAGER)
val battlegroupPlayerVillages: MutableList<BattlegroupPlayerVillageEntity>)
#Entity
#Table(name = "battlegroup_player_villages")
class BattlegroupPlayerVillageEntity(
#EmbeddedId
val id: BattlegroupPlayerVillageId,
#Column(name ="village_name")
val villageName: String,
#Enumerated(EnumType.STRING)
val tribe: Tribe)
#Embeddable
data class BattlegroupPlayerVillageId(
#Column(name = "battlegroup_id")
val battlegroupId: UUID,
#Column(name = "player_id")
val playerId: Int,
#Column(name = "village_id")
val villageId: Int,
val x: Int,
val y: Int
): Serializable
This is the SQL hibernate generates when I do a findAll/findById on a battlegroup:
select
battlegrou0_.id as id1_2_0_,
battlegrou0_.gameworld_id as gameworl2_2_0_,
battlegrou0_.name as name3_2_0_,
players1_.battlegroup_id as battlegr2_1_1_,
players1_.id as id1_1_1_,
players1_.id as id1_1_2_,
players1_.battlegroup_id as battlegr2_1_2_,
players1_.name as name3_1_2_,
players1_.player_id as player_i4_1_2_,
players1_.tribe as tribe5_1_2_,
battlegrou2_.player_id as player_i2_0_3_,
battlegrou2_.battlegroup_id as battlegr1_0_3_,
battlegrou2_.village_id as village_3_0_3_,
battlegrou2_.x as x4_0_3_,
battlegrou2_.y as y5_0_3_,
battlegrou2_.battlegroup_id as battlegr1_0_4_,
battlegrou2_.player_id as player_i2_0_4_,
battlegrou2_.village_id as village_3_0_4_,
battlegrou2_.x as x4_0_4_,
battlegrou2_.y as y5_0_4_,
battlegrou2_.tribe as tribe6_0_4_,
battlegrou2_.village_name as village_7_0_4_
from
battlegroups battlegrou0_
left outer join
battlegroup_players players1_
on battlegrou0_.id=players1_.battlegroup_id
left outer join
battlegroup_player_villages battlegrou2_
on players1_.id=battlegrou2_.player_id -- ERROR: comparing integer to uuid
where
battlegrou0_.id=?
This results in an exception:
PSQLException: ERROR: operator does not exist: integer = uuid
Which makes perfect sense, since it is comparing the battlegroup_players id, which is a uuid, to the battlegroup_player_villages player_id, which is an integer. It should instead be comparing/joining on the battlegroup_player's player_id to the battlegroup_player_village's player_id.
If I change the sql to reflect that and manually execute the above query with the error line replaced:
on players1_.player_id=battlegrou2_.player_id
I get exactly the results I want. How can I change the OneToMany mappings so that it does exactly that?
Is it possible to do this without having a BattlegroupPlayerEntity object in my BattlegroupPlayerVillageEntity class?
Bonus points if you can get the left outer joins to become regular inner joins.
EDIT:
I tried the current answer, had to slightly adjust my embedded id because my code could not compile otherwise, should be the same thing:
#Embeddable
data class BattlegroupPlayerVillageId(
#Column(name = "battlegroup_id")
val battlegroupId: UUID,
#Column(name = "village_id")
val villageId: Int,
val x: Int,
val y: Int
): Serializable {
#ManyToOne
#JoinColumn(name = "player_id")
var player: BattlegroupPlayerEntity? = null
}
Using this still results in a comparison between int and uuid, for some reason.
Schema-validation: wrong column type encountered in column [player_id] in table [battlegroup_player_villages]; found [int4 (Types#INTEGER)], but expecting [uuid (Types#OTHER)]
Interestingly, if I try to put a referencedColumnName = "player_id" in there, I get a stackoverflow error instead.

I did some digging and found some issues with the mapping as well as classes, I will try to explain as much as possible.
WARNING!!! TL;DR
I will use Java for code, I hope that should not be a problem converting to kotlin.
There are some issues with classes also(hint: Serializable), so classes must implements Serializable.
Used lombok to reduce the boilerplate
Here is the changed BattleGroupPlayer entity:
#Entity
#Getter
#NoArgsConstructor
#Table(name = "battle_group")
public class BattleGroup implements Serializable {
private static final long serialVersionUID = 6396336405158170608L;
#Id
private UUID id;
private String name;
#OneToMany(mappedBy = "battleGroupId", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private List<BattleGroupPlayer> players = new ArrayList();
public BattleGroup(UUID id, String name) {
this.id = id;
this.name = name;
}
public void addPlayer(BattleGroupPlayer player) {
players.add(player);
}
}
and BattleGroupVillage and BattleGroupVillageId entity
#AllArgsConstructor
#Entity
#Getter
#NoArgsConstructor
#Table(name = "battle_group_village")
public class BattleGroupVillage implements Serializable {
private static final long serialVersionUID = -4928557296423893476L;
#EmbeddedId
private BattleGroupVillageId id;
private String name;
}
#Embeddable
#EqualsAndHashCode
#Getter
#NoArgsConstructor
public class BattleGroupVillageId implements Serializable {
private static final long serialVersionUID = -6375405007868923427L;
#Column(name = "battle_group_id")
private UUID battleGroupId;
#Column(name = "player_id")
private Integer playerId;
#Column(name = "village_id")
private Integer villageId;
public BattleGroupVillageId(UUID battleGroupId, Integer playerId, Integer villageId) {
this.battleGroupId = battleGroupId;
this.villageId = villageId;
this.playerId = playerId;
}
}
Now, Serializable needs to be implemented in every class as we have used #EmbeddedId which requires the container class to be Serializable as well, hence every parent class must implement serializable, otherwise it would give error.
Now, we can solve the problem using #JoinColumn annotation like below:
#OneToMany(cascade = CasacadeType.ALL, fetch =EAGER)
#JoinColumn(name = "player_id", referencedColumnName = "player_id")
private List<BattleGroupVillage> villages = new ArrayList<>();
name -> field in child table and referenceColumnName -> field in parent table.
This will join the column player_id column in both entities.
SELECT
battlegrou0_.id AS id1_0_0_,
battlegrou0_.name AS name2_0_0_,
players1_.battle_group_id AS battle_g2_1_1_,
players1_.id AS id1_1_1_,
players1_.id AS id1_1_2_,
players1_.battle_group_id AS battle_g2_1_2_,
players1_.player_id AS player_i3_1_2_,
villages2_.player_id AS player_i4_2_3_,
villages2_.battle_group_id AS battle_g1_2_3_,
villages2_.village_id AS village_2_2_3_,
villages2_.battle_group_id AS battle_g1_2_4_,
villages2_.player_id AS player_i4_2_4_,
villages2_.village_id AS village_2_2_4_,
villages2_.name AS name3_2_4_
FROM
battle_group battlegrou0_
LEFT OUTER JOIN
battle_group_player players1_ ON battlegrou0_.id = players1_.battle_group_id
LEFT OUTER JOIN
battle_group_village villages2_ ON players1_.player_id = villages2_.player_id
WHERE
battlegrou0_.id = 1;
But this would give 2 players if you check the BattleGroup#getPlayers() method, below is the test case to verify.
UUID battleGroupId = UUID.randomUUID();
doInTransaction( em -> {
BattleGroupPlayer player = new BattleGroupPlayer(UUID.randomUUID(), battleGroupId, 1);
BattleGroupVillageId villageId1 = new BattleGroupVillageId(
battleGroupId,
1,
1
);
BattleGroupVillageId villageId2 = new BattleGroupVillageId(
battleGroupId,
1,
2
);
BattleGroupVillage village1 = new BattleGroupVillage(villageId1, "Village 1");
BattleGroupVillage village2 = new BattleGroupVillage(villageId2, "Village 2");
player.addVillage(village1);
player.addVillage(village2);
BattleGroup battleGroup = new BattleGroup(battleGroupId, "Takeshi Castle");
battleGroup.addPlayer(player);
em.persist(battleGroup);
});
doInTransaction( em -> {
BattleGroup battleGroup = em.find(BattleGroup.class, battleGroupId);
assertNotNull(battleGroup);
assertEquals(2, battleGroup.getPlayers().size());
BattleGroupPlayer player = battleGroup.getPlayers().get(0);
assertEquals(2, player.getVillages().size());
});
If your use case was to get the single player from BattleGroup then you would have to use FETCH.LAZY, which is btw good for performance as well.
Why LAZY works?
Because LAZY loading will issue separate select statement when you really access them. EAGER will load whole graph, wherever you have it. It means, it will try to load all relationship mapped with this type, hence it will perform outer join (which may result in 2 rows for players as your criteria is unique because of villageId, which you cannot know before querying).
If you have more than 1 such fields i.e want join on battleGroupId as well, you would need this
#JoinColumns({
#JoinColumn(name = "player_id", referencedColumnName = "player_id"),
#JoinColumn(name = "battle_group_id", referencedColumnName = "battle_group_id")
}
)
NOTE: Used h2 in memory db for test case

Related

Spring Data/Hibernate/JPA join by non-primary keys

There are two related entities Account and AccountInfo. These entities connected by non-primary keys (number_ff, number_ff2). I see that Hibernate fetching three entities(Account, AccountInfo, AccountInfo) by one sql query. But I see that hibernate do additional query to database as well. Why does hibernate do additional call(query2)? How to avoid it?
Also I tried to use JPQL query. It works the same way (2 sql queries).
Database schema(postgres):
CREATE TABLE public.accounts (
user_id serial PRIMARY KEY,
number_ff varchar NULL,
username varchar(50) NULL,
number_ff2 varchar NULL,
CONSTRAINT accounts_pkey PRIMARY KEY (user_id)
);
CREATE TABLE public.account_info (
account_info_id serial4 NOT NULL,
number_ff varchar NULL,
info varchar(1000) NULL,
CONSTRAINT account_info_pkey PRIMARY KEY (account_info_id)
);
Hibernate enitity 1:
#Entity
#Table(name = "accounts")
#Getter
#Setter
#EqualsAndHashCode
public class Account implements Serializable {
#Id
private Long userId;
#Column(name = "number_ff")
private String numberFf;
#Column(name = "number_ff2")
private String numberFf2;
private String username;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "number_ff", referencedColumnName = "number_ff", insertable = false, updatable = false, unique = true)
private AccountInfo accountInfos;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "number_ff2", referencedColumnName = "number_ff", insertable = false, updatable = false, unique = true)
private AccountInfo accountInfo2s;
}
Entity 2:
#Entity
#Table(name = "account_info")
#Getter
#Setter
public class AccountInfo implements Serializable {
#Id
private Long accountInfoId;
#NaturalId
#Column(name = "number_ff")
private String numberFf;
private String info;
}
Service:
#Service
public class ServiceInfo {
#Autowired
private AccountRepository accountRepository;
#PostConstruct
public void init() {
Optional<Account> account = accountRepository.findById(1L);
System.out.println(account);
}
}
SQL queries: Query 1 (Query that retrieves all the necessary data)
select
account0_.user_id as user_id1_1_0_,
account0_.number_ff2 as number_f3_1_0_,
account0_.number_ff as number_f2_1_0_,
account0_.username as username4_1_0_,
accountinf1_.account_info_id as account_1_0_1_,
accountinf1_.info as info2_0_1_,
accountinf1_.number_ff as number_f3_0_1_,
accountinf2_.account_info_id as account_1_0_2_,
accountinf2_.info as info2_0_2_,
accountinf2_.number_ff as number_f3_0_2_
from
accounts account0_
left outer join account_info accountinf1_ on
account0_.number_ff2 = accountinf1_.number_ff
left outer join account_info accountinf2_ on
account0_.number_ff = accountinf2_.number_ff
where
account0_.user_id =?
Query 2: (Additional query, why does it do it?)
select
accountinf0_.account_info_id as account_1_0_0_,
accountinf0_.info as info2_0_0_,
accountinf0_.number_ff as number_f3_0_0_
from
account_info accountinf0_
where
accountinf0_.number_ff =?
I think second call is redundant. Why does hibernate do additional call (query 2)? How to avoid it? It looks like bug for me.
Please see small project on GitHub: github link

Jpa mapping table not deleting at constraint error

I would like to know why spring jpa isn't deleting the rows that are causing a constraint error or a way to make it possible to edit my Account entity with new roles.
The following entities are involved in the action i'm trying to perform.
#Entity
#Table(name = "account")
class AccountEntity(uuid: UUID? = null,
#Column(nullable = false) val email: String,
#Column(nullable = false) val password: String,
#OneToMany(
mappedBy = "accountUuid",
cascade = [CascadeType.ALL],
fetch = FetchType.LAZY
) val accountRolesEntity: List<AccountRolesEntity>) : BaseEntity(uuid)
#Entity
#Table(name = "account_roles")
class AccountRolesEntity(uuid: UUID? = null,
#Column(nullable = false) val accountUuid: UUID,
#OneToOne val role: RoleEntity) : BaseEntity(uuid)
#Entity
#Table(name = "role")
class RoleEntity(uuid: UUID? = null,
#Column(nullable = false) val name: String ) : BaseEntity(uuid)
So i'm trying to update the roles of a specific account.
For example:
If X has roles 'viewer' and 'editor' and suppose i want to change it to viewer only.
I do the following steps:
Request account entity from database
set new accountRolesEntity (received from controller) to account
Call the jpa repository save method
Method in Service class:
fun updateExistingAccount(account: AccountDTO, adjustedRoles: List<RoleDTO>): AccountDTO {
val mappedRoles: List<AccountRolesEntity> = adjustedRoles.map { accountRolesMapper.map(account.uuid, it) }
val accountEntity = accountMapper.map(account, mappedRoles)
return accountMapper.map(accountRepository.save(accountEntity))
}
The error i'm getting is: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "account_roles_account_uuid_role_uuid_key"
This is because i have a constrain in my database to make sure that an account may not have duplicate roles. The create table statement is as following:
CREATE TABLE account_roles (
uuid UUID PRIMARY KEY,
account_uuid UUID NOT NULL REFERENCES account(uuid),
role_uuid UUID NOT NULL REFERENCES role(uuid),
UNIQUE (account_uuid, role_uuid)
);
There is a fix for this by performing all the actions 1 by 1: Delete first and then make new inserts. But there should be a better way for this.
actually "AccountRolesEntity" is not an entity, it's a table which keeps the relationships of two entity by keeping ids of that entities into the table.
so for the first step, you should have something like this,
#JoinTable(name = "account_role",
joinColumns = #JoinColumn(name = "account")
, inverseJoinColumns = #JoinColumn(name = "role"))
#OneToMany(mappedBy = "accountUuid",
cascade = [CascadeType.ALL],
fetch = FetchType.LAZY)
val accountRolesEntity: List<AccountRolesEntity>) :BaseEntity(uuid)
and I think your problem depends on your cascades and your class diagram so check them again.

Fetch join causes N+1 queries or throws org.hibernate.QueryException

I am trying to fetch with one query list of objects and its associations, unfortuantely, either I cause N+1 requests to database, or get hit with exception "org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list".
Please let me walk you through my case.
Below is my Data Model:
#Table(name = "first_table")
public class FirstObject {
#Id
#Column(nullable = false, name = "first_id")
private Long id;
#Column(nullable = false, name = "first_param")
private String param1;
#ManyToOne
#JoinColumn(nullable = false, name = "second_id")
private SecondObject second;
...other columns...
}
#Table(name = "second_table")
public class SecondObject {
#Id
#Column(nullable = false, name = "second_id")
private Long id;
#Column(nullable = false, name = "second_param")
private Long param2;
#ManyToOne
#JoinColumn(nullable = false, name = "third_id")
private ThirdObject third;
...other columns...
}
#Table(name = "third_table")
public class ThirdObject {
#Id
#Column(nullable = false, name = "third_id")
private Long id;
...other columns...
}
It is true to database relations, also exactly how I want it on FE.
All I am trying to achieve is to fetch all the associations with one query, giving 2 conditions:
ConditionBuilder condition = new ConditionBuilder()
.and(FirstObject.second.param2.eq(some_number))
.and(FirstObject.param1.eq(some_string));
return from(FirstObject)
.join(FirstObject.second).fetchJoin()
.join(FirstObject.second.third).fetchJoin()
.where(condition.generate())
.fetch();
Unfortunately this code throws exception:
org.hibernate.QueryException: query specified join fetching, but the
owner of the fetched association was not present in the select list
I can make it work, but with N+1 queries, but it is acceptable only for development phase, as will cause performance issue.
...
.join(FirstObject.second).fetchJoin()
.join(FirstObject.second.third)
...
same here:
...
.join(FirstObject.second)
.join(FirstObject.second.third)
...
What I am trying to figure out is how to make hibernate to create one simple query like that:
select
*
from
first_table table1
inner join
second_table table2
on table1.second_id=table2.second_id
inner join
third_table table3
on table2.third_id=table3.third_id
where
table1.first_param="some_string"
table2.second_param=some_number
All the help is very much appreciated, I've been fighting this for some time now, and really counting on community. Thank you very much.
You should be mapping both sides of the entity relationship:
for instance, in FirstObject you have this:
#ManyToOne
#JoinColumn(nullable = false, name = "second_id")
private SecondObject second;
So in SecondObject you should have this:
#OneToMany(mappedBy = "second") // this is the name of the field in the class that defines the join relationship
Collection<FirstObject> firstObjects;
In ThirdObject you should have this:
#OneToMany(mappedBy = "third") // this is the name of the field in the class that defines the join relationship
Collection<SecondObject> secondObjects;

Hibernate generates wrong query for optional bi-directional OneToOne with JoinTable

I have two entities :
RawDeviceMessage which represents a raw message from a device
TagDetail which represents the message after being parsed
A TagDetail may or may not be associated with a RawDeviceMessage, because it may be created directly without a raw message to parse. Thus, I have a optional bi-directional OneToOne relation between RawDeviceMessage and TagDetail.
In the database I have the following tables :
raw_device_message (id + other columns)
tag_detail (id + other columns)
tag_detail_has_raw_device_message (tag_detail_id , raw_device_message_id) : this table is a JoinTable with the proper SQL constraints and foreign keys to enforce the OneToOne relation at the database level.
I have mapped my Java classes like that :
RawDeviceMessage
#Entity
#Table(name = "raw_device_message")
public class RawDeviceMessage implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", unique = true, updatable = false, nullable = false)
private Long id;
#OneToOne(mappedBy = "rawDeviceMessage", fetch = FetchType.LAZY)
private TagDetail tagDetail;
public RawDeviceMessage(){}
public Long getId(){...}
public void setId(final Long id){...}
public TagDetail getTagDetail(){...}
public RawDeviceMessage setTagDetail(TagDetail tagDetail){...}
}
TagDetail
#Entity
#Table(name = "tag_detail")
public class TagDetail implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", unique = true, updatable = false, nullable = false)
private Long id;
#OneToOne(fetch = FetchType.EAGER, cascade = { CascadeType.REFRESH, CascadeType.MERGE })
#JoinTable(
name="tag_detail_has_raw_device_message",
joinColumns=#JoinColumn(name="tag_detail_id"),
inverseJoinColumns=#JoinColumn(name="raw_device_message_id"))
private RawDeviceMessage rawDeviceMessage;
public TagDetail() {}
public Long getId(){...}
public void setId(final Long id){...}
public RawDeviceMessage getRawDeviceMessage(){...}
public void setRawDeviceMessage(RawDeviceMessage rawDeviceMessage){...}
}
The issue
My issue is that when performing a find all on the RawDeviceMessage resource, Hibernate generates the wrong SQL query :
SELECT rawdevicem0_.id AS id1_15_,
rawdevicem0_2_.tag_detail_id AS tag_deta0_37_,
FROM raw_device_message rawdevicem0_
LEFT OUTER JOIN tag_detail_has_raw_device_message rawdevicem0_2_ ON rawdevicem0_.id=rawdevicem0_2_.tag_detail_id
CROSS JOIN tag_detail tagdetail1_
LEFT OUTER JOIN tag_detail_has_raw_device_message tagdetail1_1_ ON tagdetail1_.id=tagdetail1_1_.tag_detail_id
WHERE rawdevicem0_2_.tag_detail_id=tagdetail1_.id
ORDER BY rawdevicem0_.id ASC
As you can see, in the first LEFT OUTER JOIN, the join condition is rawdevicem0_.id=rawdevicem0_2_.tag_detail_id
It tries to join raw_device_message.id with tag_detail_has_raw_device_message.tag_detail_id , which makes no sense and messes up with all the results.
Instead the join condition should be, rawdevicem0_.id=rawdevicem0_2_.raw_device_message_id
This condition would correctly join raw_device_message.id with tag_detail_has_raw_device_message.raw_device_message_id
I have shortened the query generated by hibernate to remove all unrelated fields, but in the generated query there is nowhere the column raw_device_message_id, so there is definitely something wrong.
Is it an hibernate bug or am I doing my mapping wrong ?
If the purpose of tag_detail_has_raw_device_message table is only to link the two tables, then you can drop it. You can have One-to-One with just the two tables.
More details here -
Setting up a One To ManyJoins Against a Bridge Table using JPA
However if you want to have an intermediate mapping table, because it has some additional info for that relationship, then more details here.
http://what-when-how.com/hibernate/advanced-entity-association-mappings-hibernate/

Mapping result of aggregate query based on JOINs, to Hibernate property

I need get result of aggregate function to entity property. I try to use Hibernate's #Formula anotation, but she has obviously problem with JOINs. Is there any other way how to get result of these query into object properity?
Simplified datamodel
#Entity
#Table(name = "quasar_auditor")
class Auditor(){
#Id
private Long id;
// ...
}
#Entity
#Table(name = "quasar_nando_code")
class NandoCode{
#Id
private Long id;
#ManyToOne
#JoinColumn(name = "parent_id")
private NandoCode parent;
#OneToMany(mappedBy = "parent")
private Set<NandoCode> children;
// ...
}
#Entity
#Table(name = "quasar_auditor_has_nando_code")
class AuditorNandoCode{
#Id
private Long id;
private Auditor auditor;
#ManyToOne(cascade = CascadeType.DETACH)
#JoinColumn(name = "nando_code_id")
private NandoCode nandoCode;
private int categorySpecificTraining;
// ERROR: missing FROM-clause entry for table "nandocode"
#Formula(value = "(select COALESCE(sum(anc.category_specific_training),0) from quasar_auditor_has_nando_code anc "+
"inner join quasar_nando_code nc ON anc.nando_code_id=nc.id "+
"where nc.parent_id = nandoCode.id and anc.auditor_id = auditor.id)")
private int childrenCategorySpecificTraining;
// getter/setters...
}
Values nandoCode.id and auditor.id are properties of this object;
Thanks for advices
First of all, there's no such thing as nanoCode.id nor auditor.id in this query scope.
If you are trying to access AuditorNandoCode.auditor.id inside #Formula in AuditorNandoCode's annotation you should just use column name - in this case, probably, auditor_id.
So, try this annotation:
#Formula(value = "(select COALESCE(sum(anc.category_specific_training),0) from quasar_auditor_has_nando_code anc "+
"inner join quasar_nando_code nc ON anc.nando_code_id=nc.id "+
"where nc.parent_id = nandoCode_id and anc.auditor_id = auditor_id)")

Categories