Reputation: 11
I have the following model entities:
@Entity
@Table(name="ABONADO_IMEI")
public class SubscriberImei {
private SubscriberImeiId id;
private Terminal terminal;
private String state;
private Date date;
@EmbeddedId
public SubscriberImeiId getId() {
return id;
}
public void setId(SubscriberImeiId id) {
this.id = id;
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="ID_TERMINAL", nullable=false)
public Terminal getTerminal() {
return terminal;
}
public void setTerminal(Terminal terminal) {
this.terminal = terminal;
}
@Column(name="Estado")
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
@Column(name="Fecha")
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
@Entity()
public class Terminal {
private long id;
private String code;
private String brand;
private String model;
private String services;
private Set<SubscriberImei> subscriberImei;
public Terminal(){
}
@Id
@SequenceGenerator(name="SEQ_TERMINAL_ID", sequenceName="SEQ_TERMINAL_ID",allocationSize=1)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "SEQ_TERMINAL_ID")
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
@Column(name="Codigo")
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Column(name="Marca")
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
@Column(name="Modelo")
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
@Column(name="Servicios")
public String getServices() {
return services;
}
public void setServices(String services) {
this.services = services;
}
@OneToMany(fetch=FetchType.LAZY , mappedBy="terminal")
public Set<SubscriberImei> getSubscriberImei() {
return subscriberImei;
}
public void setSubscriberImei(Set<SubscriberImei> terminals) {
this.subscriberImei = terminals;
}
}
And I'm using the following JPARepository to access it:
public interface SubscriberImeiDao extends JpaRepository<SubscriberImei, SubscriberImeiId>{
@Query("select u from SubscriberImei u where u.id.snb = ?1 and u.state = ?2")
SubscriberImei findBySnbAndState(String snb, String state);
}
I need to return the result of findBySnbAndState. This is my code:
@Transactional
public SubscriberImei imeiQuery(String countryId, String snb) {
SubscriberImei subs = null;
try{
this.validateRegion(countryId, snb);
subs = this.getSubscriberDao().findBySnbAndState(snb,"A");
subs.getTerminal().getBrand();
if( subs != null)
log.info("Subscriber found {}", subs);
else
log.info("Subcriber not found!");
} catch (Exception ex) {
log.error("Unknown Exception -- ", ex);
}
return subs;
}
and I'm getting the mentioned exception at line subs.getTerminal().getBrand(). With this line I'm forcing the lazy relationship to be followed (as was suggested in some other questions). I've also added the following line to my context:
<tx:annotation-driven mode="aspectj"/>
Changing the FetchType to Eager makes it work, but I don't want to do this because is not necessary to always follow the relationship. What am I missing? What am I doing wrong?
Thanks
This is the complete exception stacktrace
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:165)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:286)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
at ar.com.redmondsoftware.imeitracking.model.Terminal_$$_jvste48_0.getBrand(Terminal_$$_jvste48_0.java)
at ar.com.redmondsoftware.imeitrackingbusinesslogic.service.impl.ImeiQueryImpl.imeiQuery(ImeiQueryImpl.java:24)
at ar.com.redmondsoftware.imeitracking.QueryImei.testQueryImei(QueryImei.java:34)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Upvotes: 1
Views: 1144
Reputation: 2983
If you don't want it to eager fetch all the time, you could make a different query that does the eager fetch when needed:
@Query("SELECT u FROM SubscriberImei u LEFT JOIN FETCH u.terminal WHERE u.id.snb = ?1 and u.state = ?2")
SubscriberImei findBySnbAndStateWithTerminal(String snb, String state);
This query is almost always preferred since it will load your data with one query rather than two.
Upvotes: 1