java - JPA: left join without @OneToMany annotations -
i have onetomany relationship in db don't want hibernate manages directly.
this relationships translations, dto represents translated registry:
@entity @table(name = "my_table") public class mytable { @id @column(name = "id", nullable = false, unique = true) private integer id; @transient private string lang; @transient private string text; // getters , setters ... } @entity @table(name = "my_table_translation") public class mytabletranslation { @id @column(name = "id", nullable = false, unique = false) private integer id; @id @column(name = "lang", nullable = false, unique = false, length = 2) private string lang; @column(name = "text", nullable = false, unique = false, length = 200) private string text; // getters , setters ... }
i want have specific findall(string lang) method lang parameter, , use specification criteria build query. that:
public void findall(string language) { list<mytable> list = repository.findall(new specification<mytable>() { @override public predicate topredicate(root<mytable> root, criteriaquery<?> query, criteriabuilder cb) { // there return ...; } }); }
the fact don't know how that, because can't use join clause, have not attribute in model represents relationship.
i tried use select...from...left join query sql notation,
select t1, t2 mytable t1 left join mytabletranslation t2 on t1.id = t2.id
and works, not desired. resulting list of objects, list of 2 object per item: 1 mytable object, , other mytabletranslation related object. need parse list , programatically build objects using propertyutils class apache commons library.
it not clean think... know how make easy, without using sql notation?
marc, can following make work , not need complicated join clauses or predicate right now. simple implementation in embedded h2
database , junit
testing sufficient proof of concept (poc) below
note:
- i using
spring + plain jpa hibernate
implementation poc. - i using
spring
recommended way of managing transaction. - com.mycompany.h2.jpa package contains entity classes.
- take @ mytable.sql has similar structure needs.
mytable.java
@entity @table(name = "my_table") public class mytable implements serializable { private static final long serialversionuid = 1l; @id @generatedvalue(strategy=generationtype.identity) @column(name = "id", nullable = false, unique = true) @joincolumn(referencedcolumnname="id", insertable=true, updatable=false) private long id; @column(name = "lang", unique=true) private string lang; @column(name = "text") private string text; @onetomany(fetch = fetchtype.lazy) @joincolumn(name="id", insertable=true, updatable=true, referencedcolumnname="id") private list<mytabletranslation> translations = new arraylist<mytabletranslation>(); ... // getters , setters, tostring() }
mytabletranslation.java
@entity @table(name = "my_table_translation") public class mytabletranslation implements serializable { private static final long serialversionuid = 11l; @id @column(name = "id") private long id; @id @column(name = "speaker") string speaker; ... // getters , setters, tostring() }
testh2databaseconfiguration.java
@configuration @enabletransactionmanagement public class testh2databaseconfiguration { final static logger log = loggerfactory.getlogger(testh2databaseconfiguration.class); @bean @qualifier("datasource") public datasource h2datasource() { return new embeddeddatabasebuilder().settype(embeddeddatabasetype.h2).addscript("classpath:mytable.sql").build(); } @bean public entitymanagerfactory entitymanagerfactory() { hibernatejpavendoradapter jpavendoradapter = new hibernatejpavendoradapter(); jpavendoradapter.setgenerateddl(true); localcontainerentitymanagerfactorybean factorybean = new localcontainerentitymanagerfactorybean(); factorybean.setdatasource(h2datasource()); factorybean.setjpavendoradapter(jpavendoradapter); factorybean.setpackagestoscan("com.mycompany.h2.jpa"); factorybean.setpersistenceunitname("my_table"); properties prop = new properties(); prop.put("hibernate.dialect", "org.hibernate.dialect.h2dialect"); prop.put("hibernate.show_sql", "true"); prop.put("hibernate.hbm2ddl.auto", "none"); factorybean.setjpaproperties(prop); factorybean.afterpropertiesset(); return factorybean.getobject(); } @bean public platformtransactionmanager transactionmanager() { jpatransactionmanager txmanager = new jpatransactionmanager(); txmanager.setentitymanagerfactory(entitymanagerfactory()); return txmanager; } @bean public mytabledao mytabledao() { return new mytabledaojpaimpl(); } @bean public mytableserviceimpl mytableservice() { mytableserviceimpl mytableservice = new mytableserviceimpl(); mytableservice.setmytabledao(mytabledao()); return mytableservice; } }
mytableservice.java
public interface mytableservice { public mytable savemytabletranslation(mytable mytable); public list<mytable> getallmytables(); public mytable getmytable(long entityid); public mytable getmytable(string lang); }
mytableserviceimpl.java
@transactional public class mytableserviceimpl implements mytableservice { final static logger log = loggerfactory.getlogger(mytableserviceimpl.class); private mytabledao mytabledao; public void setmytabledao(mytabledao mytabledao) { this.mytabledao = mytabledao; } public mytable savemytabletranslation(mytable mytable) { return mytabledao.savemytabletranslation(mytable); } public list<mytable> getallmytables() { return mytabledao.getallmytables(); } public mytable getmytable(long entityid) { return mytabledao.getmytable(entityid); } public mytable getmytable(string lang) { return mytabledao.getmytable(lang); } }
mytabledao.java
public interface mytabledao { public mytable savemytabletranslation(mytable mytable); public list<mytable> getallmytables(); public mytable getmytable(long entityid); public mytable getmytable(string lang); }
mytabledaojpaimpl.java
public class mytabledaojpaimpl implements mytabledao { final static logger log = loggerfactory.getlogger(mytabledaojpaimpl.class); @persistencecontext private entitymanager entitymanager; public mytable savemytabletranslation(mytable mytable) { entitymanager.persist(mytable); return mytable; } @suppresswarnings("unchecked") public list<mytable> getallmytables() { return (list<mytable>) entitymanager.createquery("from mytable").getresultlist(); } public mytable getmytable(long entityid) { return (mytable) entitymanager.createquery("from mytable m m.id = :id ").setparameter("id", entityid).getsingleresult(); } public mytable getmytable(string lang) { return (mytable) entitymanager.createquery("from mytable m m.lang = :lang ").setparameter("lang", lang).getsingleresult(); } }
mytabletest.java (a junit test class)
@runwith(springjunit4classrunner.class) @contextconfiguration(classes = { testh2databaseconfiguration.class }, loader = annotationconfigcontextloader.class) public class mytabletest extends abstracttransactionaljunit4springcontexttests { final static logger log = loggerfactory.getlogger(mytabletest.class); @autowired @qualifier("mytableservice") mytableservice mytableservice; @test public void test() throws parseexception { mytable parent = new mytable(); parent.setlang("italian"); parent.settext("fast..."); mytabletranslation child = new mytabletranslation(); child.setspeaker("liotta"); parent = mytableservice.savemytabletranslation(parent); log.debug("parent id : " + parent.getid()); mytable spanishtables= mytableservice.getmytable("spanish"); list<mytabletranslation> spanishtranslations = spanishtables.gettranslations(); log.debug("spanishtranslations size : " + spanishtranslations.size()); (mytabletranslation mytabletranslation : spanishtranslations) { log.debug("mytabletranslation -> : " + mytabletranslation); } } }
mytable.sql
create table if not exists my_table ( id identity primary key, lang varchar unique, text varchar ); delete my_table; insert my_table values (1, 'spanish', 'beautiful...'); insert my_table values (2, 'english', 'great...'); insert my_table values (3, 'french', 'romantic...'); create table if not exists my_table_translation ( id integer, speaker varchar ); delete my_table_translation; insert my_table_translation values (1, 'eduardo'); insert my_table_translation values (1, 'diego'); insert my_table_translation values (2, 'george'); insert my_table_translation values (3, 'pierre');
Comments
Post a Comment