I’ve this class
@javax.persistence.Entity
@Table(name = "OD_STOCK")
@Inheritance(strategy = InheritanceType.JOINED)
@PrimaryKeyJoinColumn(name = "OD_STOCKID")
@XmlRootElement(name = "Stock")
public class Stock extends Entity {
@ManyToOne(fetch = FetchType.LAZY)
@NotFound(action = NotFoundAction.IGNORE)
@JoinColumnsOrFormulas({@JoinColumnOrFormula(formula = @JoinFormula(value = "STOCKGROUPCODE", referencedColumnName = "GD_CODEID")),
@JoinColumnOrFormula(formula = @JoinFormula(referencedColumnName = "GD_CODETYPE", value = "'STOCKGROUP'"))})
private StockGroup stockGroup;
}
But when i load the Stock the stockGroup is always loaded… lazy loaded is not working.
I see in the SQL log this SELECT to load the stockGroup
select
stockgroup0_.GD_CODEID as GD_CODEI2_52_0_,
stockgroup0_.GD_CODETYPE as GD_CODET1_52_0_,
stockgroup0_.DBUSERINS as DBUSERIN3_52_0_,
stockgroup0_.DBUSERUPD as DBUSERUP4_52_0_,
stockgroup0_.AU_USERIDINS as AU_USERI5_52_0_,
stockgroup0_.AU_USERIDUPD as AU_USERI6_52_0_,
stockgroup0_.INSERTDATE as INSERTDA7_52_0_,
stockgroup0_.MODIFYDATE as MODIFYDA8_52_0_,
stockgroup0_.VERSION as VERSION9_52_0_,
stockgroup0_.GD_CODE as GD_CODE10_52_0_,
stockgroup0_.ISACTIVE as ISACTIV11_52_0_,
stockgroup0_.PRINTORDER as PRINTOR12_52_0_,
stockgroup0_.XMLGD_CODE as XMLGD_C13_52_0_
from
GD_CODE stockgroup0_
where
stockgroup0_.GD_CODEID=?
and stockgroup0_.GD_CODETYPE=?
and stockgroup0_.GD_CODETYPE='STOCKGROUP'
And worse when GD_CODEID is NULL in OD_STOCK the SELECT for load the object is done, when the SELECT is uneccessary as the GD_CODEID is NULL
The GD_CODEID is bind to NULL when GD_CODEID is NULL…
Why ? What can i do ?
vlad
July 6, 2018, 2:43pm
2
You don’t need @JoinColumnsOrFormulas
here. Use @JoinColumns
instead as explained in this article :
@ManyToOne(fetch = FetchType.LAZY)
//Relying on @NotFound is relational database code smell
//@NotFound(action = NotFoundAction.IGNORE)
@JoinColumns({
@JoinColumn(
name = "STOCKGROUPCODE",
referencedColumnName = "GD_CODEID"),
@JoinColumn(
name = "STOCKGROUP",
referencedColumnName = "GD_CODETYPE")
})
private StockGroup stockGroup;
If it does not work, send us a Pull Request with a replicating test case as explained in this post .
No, i can’t in table OD_STOCK there is no column GD_CODETYPE (or STOCKGROUP), just GD_CODEID. But the PK in the other table are both columns.
STOCKGROUP is the value that should have GD_CODETYPE in the referenced table GD_CODE
I can’t change the DB structure.
vlad
July 6, 2018, 4:57pm
4
I just did exactly what you mapped previously. If your code worked, it should work with my change as well.
You mean name in @JoinColumn can be a value instead of a columnName of the Table?? I will try on Monday and give feedback! Thanks
vlad
July 6, 2018, 5:15pm
6
No, it must be a column name, not a value. In that case use JoinColumnOrFormula.
Create a replicating test case and send it as a Pull Request so we can better understand why lazy loading would not work.
I’m trying to send a pull request with the test, but i’m getting 403 Forbidden
13:54:43.403: [hibernate-orm] git -c core.quotepath=false -c log.showSignature=false push --progress --porcelain origin refs/heads/HHH-12770:HHH-12770 --set-upstream
fatal: HttpRequestException encountered.
An error occurred while sending the request.
remote: Permission to hibernate/hibernate-orm.git denied to ferguardiola.
fatal: unable to access 'https://github.com/hibernate/hibernate-orm/': The requested URL returned error: 403
Here is the tets i’m trying to upload
package org.hibernate;
import org.hibernate.annotations.JoinColumnOrFormula;
import org.hibernate.annotations.JoinColumnsOrFormulas;
import org.hibernate.annotations.JoinFormula;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.TestForIssue;
import org.junit.Before;
import org.junit.Test;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import java.util.List;
import java.util.Map;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertEquals;
@TestForIssue(jiraKey = "HHH-12770")
public class HHH12770 extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Stock.class,
Code.class,
};
}
@Override
protected void addConfigOptions(Map options) {
options.put(
AvailableSettings.SHOW_SQL,
Boolean.TRUE
);
}
@Before
public void setUp() {
doInJPA( this::entityManagerFactory, entityManager -> {
Code codeA1 = new Code();
codeA1.setId((long)1);
codeA1.setCopeType(CodeType.TYPE_A);
entityManager.persist(codeA1);
Code codeA2 = new Code();
codeA2.setId((long)2);
codeA2.setCopeType(CodeType.TYPE_A);
entityManager.persist(codeA2);
Code codeB1 = new Code();
codeB1.setId((long)1);
codeB1.setCopeType(CodeType.TYPE_B);
entityManager.persist(codeB1);
Code codeB2 = new Code();
codeB2.setId((long)2);
codeB2.setCopeType(CodeType.TYPE_B);
entityManager.persist(codeB2);
Stock stock1 = new Stock();
stock1.setId((long)1);
stock1.setCode(codeA1);
entityManager.persist(stock1);
Stock stock2 = new Stock();
stock2.setId((long)2);
entityManager.persist(stock2);
Stock stock3 = new Stock();
stock3.setId((long)2);
stock3.setCode(codeB1);
entityManager.persist(stock3);
});
}
@Test
public void testSelectAll() {
doInJPA( this::entityManagerFactory, entityManager -> {
List<Stock> stocks = entityManager.createQuery(
" SELECT s FROM Stock s " )
.getResultList();
assertEquals(3, stocks.size());
});
}
@Entity(name = "Stock")
public static class Stock {
@Id
@GeneratedValue
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumnsOrFormulas({@JoinColumnOrFormula(column = @JoinColumn(name = "ID", referencedColumnName = "ID")),
@JoinColumnOrFormula(formula = @JoinFormula(referencedColumnName = "TYPE", value = "'TYPE_A'"))})
private Code code;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Code getCode() {
return code;
}
public void setCode(Code code) {
this.code = code;
}
}
@Entity(name = "Code")
public static class Code {
@Id
@Column(name = "ID")
private Long id;
@Id
@Enumerated
@Column(name = "TYPE")
private CodeType copeType;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public CodeType getCopeType() {
return copeType;
}
public void setCopeType(CodeType copeType) {
this.copeType = copeType;
}
}
public enum CodeType {
TYPE_A, TYPE_B;
}
}
Here is the JIRA related: https://hibernate.atlassian.net/browse/HHH-12770
The problem is that code from Stock is not load in a lazy way
vlad
July 9, 2018, 12:10pm
8
You need to fork the repository first. Then add your changes and send the PR.
Hi Again,
Well after debugging the hibernate-core i found that if it’s marked the relation as @NotFound (action = NotFoundAction.IGNORE) then is loaded EAGER always. I don’t kwno the reason. But if i remove the @NotFoundAction.IGNORE then relation is loaded LAZY.
Thanks!
vlad
July 9, 2018, 4:10pm
11
You should open a Jira issue. Maybe there’s a way to allows NotFoundAction.IGNORE
associations to be loaded lazily as well.