ebean: @OneToOne with @JoinColumn to non primary key throws `Data conversion error`
import com.avaje.ebean.EbeanServer;
import com.avaje.ebean.EbeanServerFactory;
import com.avaje.ebean.config.DataSourceConfig;
import com.avaje.ebean.config.ServerConfig;
import com.google.common.collect.Lists;
import org.avaje.agentloader.AgentLoader;
import org.h2.Driver;
import org.junit.Before;
import org.junit.Test;
import javax.persistence.*;
import java.io.IOException;
import java.lang.instrument.IllegalClassFormatException;
/**
* @author icode
*/
public class EbeanTest {
EbeanServer server;
@Before
public void init() {
AgentLoader.loadAgentFromClasspath("avaje-ebeanorm-agent", "debug=5");
final ServerConfig config = new ServerConfig();
config.setClasses(Lists.<Class<?>>newArrayList(RoadShowMsg.class, Company.class));
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setUrl("jdbc:h2:file:./db");
dataSourceConfig.setDriver(Driver.class.getName());
dataSourceConfig.setUsername("sa");
dataSourceConfig.setPassword("");
config.setDataSourceConfig(dataSourceConfig);
config.setName("default");
config.setDdlGenerate(true);
config.setDdlRun(true);
config.setDefaultServer(true);
server = EbeanServerFactory.create(config);
}
@Test
public void JsonTest() throws IOException, IllegalClassFormatException, ClassNotFoundException {
RoadShowMsg msg = new RoadShowMsg();
Company company = new Company();
company.setCorpId("corp_id_1000000");
msg.setCompany(company);
server.save(msg);
server.find(RoadShowMsg.class, 1);
}
@MappedSuperclass
public static abstract class Model {
@Id
@GeneratedValue
public Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
@Entity
public static class RoadShowMsg extends Model {
@OneToOne(cascade = CascadeType.ALL, optional = false)
@JoinColumn(name = "corp_id", nullable = false, referencedColumnName = "corp_id")
public Company company;
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
}
@Entity
public static class Company extends Model {
@Column(length = 50, unique = true)
public String corpId;
public String getCorpId() {
return corpId;
}
public void setCorpId(String corpId) {
this.corpId = corpId;
}
}
}
console:
javax.persistence.PersistenceException: Error loading on EbeanTest$RoadShowMsg.company
at com.avaje.ebeaninternal.server.query.SqlBeanLoad.load(SqlBeanLoad.java:85)
at com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne.load(BeanPropertyAssocOne.java:615)
at com.avaje.ebeaninternal.server.query.SqlTreeNodeBean.load(SqlTreeNodeBean.java:268)
at com.avaje.ebeaninternal.server.query.CQuery.readNextBean(CQuery.java:431)
at com.avaje.ebeaninternal.server.query.CQuery.hasNext(CQuery.java:512)
at com.avaje.ebeaninternal.server.query.CQuery.readBean(CQuery.java:494)
at com.avaje.ebeaninternal.server.query.CQueryEngine.find(CQueryEngine.java:356)
at com.avaje.ebeaninternal.server.query.DefaultOrmQueryEngine.findId(DefaultOrmQueryEngine.java:129)
at com.avaje.ebeaninternal.server.core.OrmQueryRequest.findId(OrmQueryRequest.java:251)
at com.avaje.ebeaninternal.server.core.DefaultServer.findId(DefaultServer.java:1190)
at com.avaje.ebeaninternal.server.core.DefaultServer.find(DefaultServer.java:1048)
at com.avaje.ebeaninternal.server.core.DefaultServer.find(DefaultServer.java:1035)
at EbeanTest.JsonTest(EbeanTest.java:48)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
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.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
Caused by: org.h2.jdbc.JdbcSQLException: Data conversion error converting "corp_id_1000000" [22018-187]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
at org.h2.message.DbException.get(DbException.java:168)
at org.h2.value.Value.convertTo(Value.java:902)
at org.h2.value.Value.getLong(Value.java:443)
at org.h2.jdbc.JdbcResultSet.getLong(JdbcResultSet.java:650)
at com.avaje.ebeaninternal.server.type.RsetDataReader.getLong(RsetDataReader.java:121)
at com.avaje.ebeaninternal.server.type.ScalarTypeLong.read(ScalarTypeLong.java:34)
at com.avaje.ebeaninternal.server.type.ScalarTypeLong.read(ScalarTypeLong.java:17)
at com.avaje.ebeaninternal.server.deploy.BeanProperty.read(BeanProperty.java:581)
at com.avaje.ebeaninternal.server.deploy.id.IdBinderSimple.read(IdBinderSimple.java:177)
at com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne$Reference.read(BeanPropertyAssocOne.java:749)
at com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne.read(BeanPropertyAssocOne.java:574)
at com.avaje.ebeaninternal.server.query.SqlBeanLoad.load(SqlBeanLoad.java:74)
... 34 more
Caused by: java.lang.NumberFormatException: For input string: "corp_id_1000000"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Long.parseLong(Long.java:589)
at java.lang.Long.parseLong(Long.java:631)
at org.h2.value.Value.convertTo(Value.java:854)
... 44 more
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Comments: 17 (14 by maintainers)
Commits related to this issue
- #529 - @OneToOne with @JoinColumn to non primary key throws `Data conversion error` — committed to ebean-orm/ebean by rbygrave 8 years ago
JPA Spec 11.1.21 Support for referenced columns that are not primary key columns of the referenced table is optional. Applications that use such mappings will not be portable.
So this is optional for JPA providers.
Also note: http://stackoverflow.com/questions/5818373/does-the-jpa-specification-allow-references-to-non-primary-key-columns
Now in terms of Ebean ORM internals … the issue here in trying to support a JoinColumn to a non-primary key is in 2 main areas:
To support unique non-null columns equally with primary key we need to translate between the unique column and the primary key value for both of those features (the persistence context check and the further lazy loading).
That has the potential to be “not good implementation” without introducing some level of compromise (separate treatment in persistence context for example).
Ultimately this this mapping option (if supported) there are now 2 active values used to identify each Company instance (the @Id and corpId) and that translates into a combination of extra complexity, performance costs or compromising functionality.