And*_*ios 5 java sql hibernate jpa
我有一个JPA 2 Web应用程序(Struts 2,Hibernate 4仅作为JPA实现).
当前的要求是将(非id)数字顺序字段(仅对某些行填充)添加到现有实体.根据特定条件插入新行时,我需要将新字段设置为its highest value + 1
或NULL
.
例如:
ID NEW_FIELD DESCRIPTION
--------------------------------
1 1 bla bla
2 bla bla <--- unmatched: not needed here
3 bla bla <--- unmatched: not needed here
4 2 bla bla
5 3 bla bla
6 4 bla bla
7 bla bla <--- unmatched: not needed here
8 5 bla bla
9 bla bla <--- unmatched: not needed here
10 6 bla bla
Run Code Online (Sandbox Code Playgroud)
在旧的SQL中,它将是这样的:
INSERT INTO myTable (
id,
new_field,
description
) VALUES (
myIdSequence.nextVal,
(CASE myCondition
WHEN true
THEN myNewFieldSequence.nextVal
ELSE NULL
END),
'Lorem Ipsum and so on....'
)
Run Code Online (Sandbox Code Playgroud)
但我不知道如何用JPA 2实现它.
我知道我可以定义回调方法,但是Eval 2.0 Eval的JSR-000317持久性规范不鼓励其中的一些特定操作:
3.5实体监听器和回调方法
- 生命周期回调可以调用JNDI,JDBC,JMS和企业bean.
- 通常,可移植应用程序的生命周期方法不应调用EntityManager或Query操作,访问其他实体实例或修改同一持久性上下文中的关系.[43]阿生命周期回调方法可以修改在其上调用实体的非关系状态.[43] 这样的操作的语义可以在以后的本说明书中的释放标准化.
总结一下,是JDBC(!)和EJB,不是EntityManager和其他实体.
我正在努力实现@anttix答案中描述的解决方案,但我遇到了一些问题,所以请在我错的地方纠正我.
表
MyTable
-------------------------
ID number (PK)
NEW_FIELD number
DESCRIPTION text
Run Code Online (Sandbox Code Playgroud)
主要实体
@Entity
@Table(name="MyTable")
public class MyEntity implements Serializable {
@Id
@SequenceGenerator(name="seq_id", sequenceName="seq_id", allocationSize=1)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq_id")
private Long id;
@OneToOne(cascade= CascadeType.PERSIST)
private FooSequence newField;
private String description
/* Getters and Setters */
}
Run Code Online (Sandbox Code Playgroud)
子实体
@Entity
public class FooSequence {
@Id
@SequenceGenerator(name="seq_foo", sequenceName="seq_foo", allocationSize=1)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq_foo")
private Long value;
/* Getter and Setter */
}
Run Code Online (Sandbox Code Playgroud)
DAO
myEntity.setNewField(new FooSequence());
entityManager.persist(myEntity);
Run Code Online (Sandbox Code Playgroud)
例外
引起:javax.transaction.RollbackException:ARJUNA016053:无法提交事务.
[...]
引起:javax.persistence.PersistenceException:org.hibernate.exception.SQLGrammarException:错误:关系"new_field"不存在
[...]
引起:org.hibernate.exception.SQLGrammarException:错误:关系"new_field"不存在
[...]
引起:org.postgresql.util.PSQLException:错误:关系"new_field"不存在
我究竟做错了什么 ?我对JPA 2很新,我从未使用过与物理表无关的实体......这种方法对我来说是全新的.
我想我需要把@Column
定义的地方:JPA怎么可能知道newField
列(通过映射ImprovedNamingStrategy到new_field
数据库上)通过获取value
的财产FooSequence
实体?
缺少一些拼图.
编辑
正如评论中所说,这是persistence.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="MyService" transaction-type="JTA">
<jta-data-source>java:jboss/datasources/myDS</jta-data-source>
<properties>
<property name="hibernate.dialect"
value="org.hibernate.dialect.PostgreSQLDialect" />
<property name="hibernate.ejb.naming_strategy"
value="org.hibernate.cfg.ImprovedNamingStrategy"/>
<property name="hibernate.query.substitutions"
value="true 'Y', false 'N'"/>
<property name="hibernate.show_sql" value="true" />
<property name="format_sql" value="true" />
<property name="use_sql_comments" value="true" />
</properties>
</persistence-unit>
</persistence>
Run Code Online (Sandbox Code Playgroud)
一种可能的解决方案是使用具有自己的表的单独实体,该实体将仅封装新字段并与该实体进行 OneToOne 映射。仅当遇到需要附加序列号的对象时,您才会实例化新实体。然后,您可以使用任何生成器策略来填充它。
@Entity
public class FooSequence {
@Id
@GeneratedValue(...)
private Long value;
}
@Entity
public class Whatever {
@OneToOne(...)
private FooSequnce newColumn;
}
Run Code Online (Sandbox Code Playgroud)
看:
一个 gradle 1.11 可运行的 SSCCE(使用 Spring Boot):
src/main/java/JpaMultikeyDemo.java
import java.util.List;
import javax.persistence.*;
import lombok.Data;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;
@Configuration
@EnableTransactionManagement
@EnableAutoConfiguration
public class JpaMultikeyDemo {
@Entity @Data
public static class FooSequence {
@Id @GeneratedValue private Long value;
}
@Entity @Data
public static class FooEntity {
@Id @GeneratedValue private Long id;
@OneToOne private FooSequence sequence;
}
@PersistenceContext
EntityManager em;
@Transactional
public void runInserts() {
// Create ten objects, half with a sequence value
for(int i = 0; i < 10; i++) {
FooEntity e1 = new FooEntity();
if(i % 2 == 0) {
FooSequence s1 = new FooSequence();
em.persist(s1);
e1.setSequence(s1);
}
em.persist(e1);
}
}
public void showAll() {
String q = "SELECT e FROM JpaMultikeyDemo$FooEntity e";
for(FooEntity e: em.createQuery(q, FooEntity.class).getResultList())
System.out.println(e);
}
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(JpaMultikeyDemo.class);
context.getBean(JpaMultikeyDemo.class).runInserts();
context.getBean(JpaMultikeyDemo.class).showAll();
context.close();
}
}
Run Code Online (Sandbox Code Playgroud)
构建.gradle
apply plugin: 'java'
defaultTasks 'execute'
repositories {
mavenCentral()
maven { url "http://repo.spring.io/libs-milestone" }
}
dependencies {
compile "org.springframework.boot:spring-boot-starter-data-jpa:1.0.0.RC5"
compile "org.projectlombok:lombok:1.12.6"
compile "com.h2database:h2:1.3.175"
}
task execute(type:JavaExec) {
main = "JpaMultikeyDemo"
classpath = sourceSets.main.runtimeClasspath
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
25346 次 |
最近记录: |