问题描述
我在数据库中有一个OneToMany关系,但我不希望Hibernate直接管理它。
这种关系是翻译,但DTO表示翻译本身注册表:
@Entity
@Table(name =my_table)
public class MyTable {
@Id
@Column(name =id,nullable = false,unique = true)
private Integer id;
@Transient
私人字符串lang;
@Transient
private String text;
// getters and 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 and setters
...
}
我想要一个具有lang参数的特定findAll(String lang)方法,并使用规范标准构建查询。类似的东西:
public void findAll(String language){
List< MyTable> (根据< MyTable>根,CriteriaQuery?查询,CriteriaBuilder cb){
/ / something there
return ...;
}
});
$ / code>
事实是我不知道该怎么做,因为我不能使用JOIN子句,因为我在模型中没有表示关系的属性。
我尝试使用SELECT ... FROM ... LEFT使用SQL表示法加入查询,
SELECT t1,t2 FROM MyTable t1 LEFT JOIN MyTableTranslation t2 ON t1.id = t2.id
它可以工作,但不是按需要的。得到的对象列表是每个项目2个对象的列表:一个是 MyTable 对象,另一个是与MyTableTranslation相关的对象。我需要解析列表并以编程方式使用Apache Commons库中的PropertyUtils类来构建对象。
这不是干净的,我认为...是否有人知道如何制作它很容易,而不使用SQL符号?
Marc,您可以执行以下操作,使其不需要复杂的连接子句或谓词。嵌入 H2
数据库和 JUnit
测试的简单实现对于概念证明( POC
注意:
- 我为 POC 使用
Spring + Plain JPA和Hibernate
实现。
- 我使用
Spring
管理事务的推荐方式。 - com.mycompany.h2.jpa包中包含实体类。
- 查看与您的需求具有相似结构的 mytable.sql 。
MyTable.java
@Entity
@Table(name =my_table)
public class MyTable实现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长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 and setters,toString()
}
MyTableTranslation.java
@Entity
@Table(name = my_table_translation)
public class MyTableTranslation实现Serializable {
private static final long serialVersionUID = 11L;
@Id
@Column(name =id)
私人长ID;
@Id
@Column(名称=扬声器)
弦乐扬声器;
...
// getters and setters,toString()
}
TestH2DatabaseConfiguration.java
@Configuration
@EnableTransactionManagement
public class TestH2DatabaseConfiguration {
final static Logger log = LoggerFactory.getLogger(TestH2DatabaseConfiguration.class);
@Bean
@Qualifier(dataSource)
public DataSource h2DataSource(){
返回新的EmbeddedDatabaseBuilder()。setType(EmbeddedDatabaseType.H2).addScript( 类路径:mytable.sql)建立();
$Be
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);
属性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();
返回factoryBean.getObject();
$ b $Bean
public PlatformTransactionManager transactionManager(){
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory());
返回txManager;
}
@Bean
public MyTableDAO myTableDAO(){
return new MyTableDAOJPAImpl();
$ Be $ b $ public MyTableServiceImpl myTableService(){
MyTableServiceImpl myTableService = new MyTableServiceImpl();
myTableService.setMyTableDAO(myTableDAO());
返回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 );
私人MyTableDAO myTableDAO;
public void setMyTableDAO(MyTableDAO myTableDAO){
this.myTableDAO = myTableDAO;
}
public MyTable saveMyTableTranslation(MyTable myTable){
return myTableDAO.saveMyTableTranslation(myTable);
}
公共列表< 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
私人EntityManager entityManager;
MyTable saveMyTableTranslation(MyTable myTable){
entityManager.persist(myTable);
返回myTable;
}
@SuppressWarnings(unchecked)
public List< MyTable> getAllMyTables(){
return(List< MyTable>)entityManager.createQuery(FROM MyTable)。getResultList();
$ b $ public MyTable getMyTable(long entityId){
return(MyTable)entityManager.createQuery(FROM MyTable m WHERE m.id =:id).setParameter( id,entityId).getSingleResult();
$ b $ public MyTable getMyTable(String lang){
return(MyTable)entityManager.createQuery(FROM MyTable m WHERE m.lang =:lang).setParameter( lang,lang).getSingleResult();
}
}
MyTableTest.java (一个JUnit测试类)
$ pre $ @ $ $ $ $ @ $
@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);
列表< 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
);
从my_table中删除;
INSERT INTO my_table VALUES(1,'Spanish','Beautiful ...');
INSERT INTO my_table VALUES(2,'English','Great ...');
INSERT INTO my_table VALUES(3,'French','Romantic ...');
CREATE TABLE IF NOT EXISTS my_table_translation(
id INTEGER,
speaker VARCHAR
);
从my_table_translation中删除;
INSERT INTO my_table_translation值(1,'Eduardo');
INSERT INTO my_table_translation VALUES(1,'Diego');
INSERT INTO my_table_translation VALUES(2,'George');
INSERT INTO my_table_translation VALUES(3,'Pierre');
I have a OneToMany relationship in my DB but I don't want that Hibernate manages it directly.
This relationships are translations, but a DTO represents itself a 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 and 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 and setters
...
}
I want to have an specific findAll(String lang) method with a lang parameter, and use an Specification Criteria to build the query. Something like 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) {
// something there
return ...;
}
});
}
The fact is that I don't know how to do that, because I can't use JOIN clause, as I have not an attribute in the model that represents the relationship.
I tried to use the SELECT...FROM...LEFT JOIN query with SQL notation,
SELECT t1, t2 FROM MyTable t1 LEFT JOIN MyTableTranslation t2 ON t1.id = t2.id
and it works, but not as desired. The resulting list of objects, is a list of 2 object per item: one is the MyTable object, and the other is the MyTableTranslation related object. I need to parse the list and programatically build the objects using PropertyUtils class from Apache Commons library.
It is not clean I think... Does anybody know how to make it easy, without using SQL notation?
Marc, you can do the following to make it work and you do not need complicated join clauses or predicate right now. A simple implementation in embedded H2
database and JUnit
testing will be sufficient for proof of concept (POC) as below
NOTE:
- I am using
Spring + Plain JPA with Hibernate
implementation for POC. - I am using the
Spring
recommended way of managing transaction. - com.mycompany.h2.jpa package contains the entity classes.
- Take a look at the mytable.sql which has similar structure to your 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 and 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 and 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 WHERE m.id = :id ").setParameter("id", entityId).getSingleResult();
}
public MyTable getMyTable(String lang) {
return (MyTable) entityManager.createQuery("FROM MyTable m WHERE 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());
for (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 from my_table;
INSERT INTO my_table VALUES (1, 'Spanish', 'Beautiful...');
INSERT INTO my_table VALUES (2, 'English', 'Great...');
INSERT INTO my_table VALUES (3, 'French', 'Romantic...');
CREATE TABLE IF NOT EXISTS my_table_translation (
id INTEGER,
speaker VARCHAR
);
delete from my_table_translation;
INSERT INTO my_table_translation VALUES (1, 'Eduardo');
INSERT INTO my_table_translation VALUES (1, 'Diego');
INSERT INTO my_table_translation VALUES (2, 'George');
INSERT INTO my_table_translation VALUES (3, 'Pierre');
这篇关于JPA:没有@OneToMany注释而离开连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!