当前位置: 首页 > 面试题库 >

JPA-以编程方式通过序列增加数字字段

钱星辰
2023-03-14
问题内容

我有一个JPA 2 Web应用程序(Struts 2,Hibernate 4仅作为JPA实现)。

当前的要求是向现有实体添加仅填充某些行的(非id)数字顺序字段。根据特定条件插入新行时,我需要将新字段设置为its highest value + 1NULL

例如:

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

在良好的旧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....'
)

但是我不知道如何使用JPA 2实现它。

我知道我可以定义回调方法,但是Eval
2.0的JSR-000317持久性规范Eval
不鼓励从其内部进行一些特定的操作:

3.5实体侦听器和回调方法
-生命周期回调可以调用JNDI,JDBC,JMS和企业Bean。
-通常,可移植应用程序的生命周期方法 不应调用EntityManager或Query操作,访问其他实体实例或在同一持久性上下文内修改关系
。[43]生命周期回调方法可以修改在其上被调用的实体的非关系状态。

[43] 这种操作的语义可能会在本规范的未来版本中标准化。

总结一下,对JDBC(!)和EJB是,对于EntityManager和其他实体,否。

我正在尝试实现@anttix的答案中描述的解决方案,但是我遇到了一些问题,因此请在错误之处纠正我。

MyTable
-------------------------
ID            number (PK)
NEW_FIELD     number
DESCRIPTION   text

主要实体

@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 */
}

子实体

@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 */
}

myEntity.setNewField(new FooSequence());
entityManager.persist(myEntity);

例外

原因: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>

问题答案:

一种可能的解决方案是使用一个单独的实体及其自己的表,该表将仅封装新字段并与该实体具有OneToOne映射。然后,仅当遇到需要附加序列号的对象时,才实例化新实体。然后,您可以使用任何生成器策略来填充它。

@Entity
public class FooSequence {
    @Id
    @GeneratedValue(...)
    private Long value;
}

@Entity 
public class Whatever {
    @OneToOne(...)
    private FooSequnce newColumn;
}

看到:

  • hibernateJPA序列(非ID)
  • https://forum.hibernate.org/viewtopic.php?p=2405140

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();
    }
}

build.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
}

另请参阅:http :
//docs.spring.io/spring-boot/docs/current-
SNAPSHOT/reference/htmlsingle/#boot-features-configure-
datasource



 类似资料:
  • 我有一个名为的类,其中有一个字符串数组: 我的当前活动代码: 在中出现错误。单击时,如何将文本更改为字符串之一?

  • 我有一个JPA(Hibernate)项目,其中包含从XML orm.XML和Beans创建的实体,我有一个EntityManager和update、persist、remove、findById、findAll方法,但我需要添加一个过滤器监听器来检查保存、还原等之前和之后的Beans(我需要将一些值设置为null以返回客户机) 问候。

  • 是否可以像使用WordPress用户一样通过编程方式创建客户。显然,WooCommerce用户共享一些相同的WordPress用户字段,还有其他内容需要设置,如账单/邮政地址。 以前有人做到过吗?我在他们网站上的WooCommerce API/函数列表中找不到任何内容。 编辑:刚刚找到这个:http://docs.woothemes.com/wc-apidocs/function-wc_creat

  • 问题内容: 尝试启动并通过电话。没有。通过我的应用中的此代码进行Skype: Skype已启动,但无法捕获该数字。 问题答案: 此代码对我有用,可以在两个Skype用户之间发起呼叫: 要找到这个(和其他),请使用打开。查看AndroidManifest.xml,您将看到他们所知道的所有意图过滤器。如果要触发这些意图过滤器之一,则需要制定一个与之匹配的意图。这是上面的代码匹配的意图过滤器: 您可以从

  • 我正在尝试在Android上添加Wifi网络,我想知道如何连接到不广播其SSID的Wifi网络(它是否有空SSID或带有\0s的清晰SSID)。 这是我目前用于广播其SSID的Wifi网络的内容:

  • 问题内容: 使用Hibernate,您可以将类加载为: 有没有一种方法可以以符合JPA 2.0的方式以编程方式加载Entity类来做同样的事情? 这个问题的原因是因为我想 动态 加载我的类,因此不必以编程方式加载。 问题答案: 在Spring的帮助下,我以符合JPA的方式进行了此操作。 我的“ persistence.xml”看起来是空的,元素中没有列出任何实体。 然后,我编写了一个实现Persi