Jpa 防止不必要的级联表更新

Jpa 防止不必要的级联表更新,jpa,sql-update,cascade,openjpa,one-to-one,Jpa,Sql Update,Cascade,Openjpa,One To One,我正在创建我的第一个基于JPA的项目。出于完整性目的,我的应用程序提供了几个具有外键关系的表。许多相关的表都是规范化的查找表 考虑表Person和Account,它们在accountid上具有fk关系: +-Person----+ | personid | +-Account---+ | accountid*|==============>| accountid | | ... | | ..

我正在创建我的第一个基于JPA的项目。出于完整性目的,我的应用程序提供了几个具有外键关系的表。许多相关的表都是规范化的查找表

考虑表
Person
Account
,它们在
accountid
上具有fk关系:

+-Person----+               
| personid  |               +-Account---+
| accountid*|==============>| accountid |
| ...       |               | ...       |
+-----------+               +-----------+
在前端(JSF)中,我为新的
Person
对象创建了一个表单,其中包含一个包含所有帐户的
selectOneMenu
列表,所选的accountid被添加到新的Person中,并正确插入到数据库中

但是,
帐户
表也会自动更新,我无法找到阻止这种情况发生的方法

我的课程注释如下:

@Entity
@Table(name="usr_person")
@NamedQuery(name="Person.findAll", query="SELECT u FROM Person u")
public class Person implements Serializable 
{
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="person_id")
    private int personId;

    //bi-directional one-to-one association to UsrAccount
    @OneToOne
    @JoinColumn(name="account_id",insertable=true,updatable=true)
    private Account usrAccount;

    ...
<?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="matco">
        <class>matco.model.Changelog</class>
        <class>matco.model.Item</class>
        <class>matco.model.ItemAssignment</class>
        <class>matco.model.ItemMaintenance</class>
        <class>matco.model.LstType</class>
        <class>matco.model.LstColor</class>
        <class>matco.model.LstCondition</class>
        <class>matco.model.LstSize</class>
        <class>matco.model.Team</class>
        <class>matco.model.Account</class>
        <class>matco.model.Person</class>
        <class>matco.model.CatBrand</class>
        <class>matco.model.CatItem</class>
        <class>matco.model.CatPrice</class>
        <class>matco.model.CatSupplier</class>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/matco" />
            <property name="javax.persistence.jdbc.user" value="****" />
            <property name="javax.persistence.jdbc.password" value="****" />
            <!-- TODO remove this in favor of enhancement -->
            <property name="openjpa.RuntimeUnenhancedClasses" value="supported"/>
            <property name="openjpa.Log" value="DefaultLevel=WARN, Runtime=INFO, Tool=INFO, SCHEMA=TRACE, SQL=TRACE"/>
            <property name="openjpa.ConnectionFactoryProperties" value="PrintParameters=true" />
        </properties>
    </persistence-unit>
</persistence>
前端调用以下方法,该方法仅使用
EntityManager
的merge()函数来持久化新的
Person
对象:

public String savePerson()
{
    try
    {
        em.getTransaction().begin();
        person = em.merge( person );
        em.getTransaction().commit();
    }
    catch (Exception e)
    {
        ...
这将导致对
帐户
表中的每个对象进行
更新
调用


更新

我从代码中删除了
EntityManager.merge()
调用,更新语句仍然存在。不知何故,JSF表单会自动更新支持它的
帐户
对象。以下行来自JPA跟踪:

17448 <snip> openjpa.jdbc.SQL - <t 1905431636, conn 233456683> executing prepstmnt 1172878998 UPDATE usr_account SET loginname = ?, password = ?, privileges = ? WHERE account_id = ? [params=(String) mvreijn, (String) ba5edce0be3a9b8f6ac9b84c72935192b2289b3a341ad432021256c7144b59f4, (int) 90, (int) 1]
17449 <snip> openjpa.jdbc.SQL - <t 1905431636, conn 233456683> [1 ms] spent
17449 <snip> openjpa.jdbc.SQL - <t 1905431636, conn 233456683> executing prepstmnt 386904456 UPDATE usr_account SET loginname = ?, password = ?, privileges = ? WHERE account_id = ? [params=(String) afolmer, (String) ba5edce0be3a9b8f6ac9b84c72935192b2289b3a341ad432021256c7144b59f4, (int) 90, (int) 2]
17450 <snip> openjpa.jdbc.SQL - <t 1905431636, conn 233456683> [1 ms] spent
17450 <snip> openjpa.jdbc.SQL - <t 1905431636, conn 233456683> executing prepstmnt 1322606395 UPDATE usr_account SET loginname = ?, password = ?, privileges = ? WHERE account_id = ? [params=(String) annuska, (String) ba5edce0be3a9b8f6ac9b84c72935192b2289b3a341ad432021256c7144b59f4, (int) 80, (int) 3]
17451 <snip> openjpa.jdbc.SQL - <t 1905431636, conn 233456683> [1 ms] spent
同时,在后台bean中查询
Account
对象之后,我已经分离了它们,如下所示:

public List<Account> getUsrAccounts()
{
    List<Account> accts = em.createNamedQuery( "Account.findAll", Account.class ).getResultList();
    for (Account acct : accts)
        em.detach(acct);
    return accts;
}
public List getUsrAccounts()
{
List accts=em.createNamedQuery(“Account.findAll”,Account.class).getResultList();
对于(科目:accts)
em.detach(acct);
返回账户;
}
然后,当我提交新的
Person
对象时,JPA只更新链接到新的
Person
帐户。甚至这也是不可取的,我觉得我在某种程度上滥用了JPA


在JPA中使用不可编辑的查找表的正常方式是什么?

尝试添加到@OneTONE映射
cascade=CascadeType.REFRESH)

这将指示您的ORM框架仅在刷新时级联(在读取实体时),并且在尝试仅保存其中一个实体时不级联更新。

在persistence.xml中未启用
。找出另一个增强策略。

很公平。我发现很难找到正在执行的
UPDATE
语句的源代码;我的代码在
EntityManager.merge(Person)
中进行的唯一调用不应该触及
Account
对象的完整列表。Jsf本身从不发出更新语句。始终是jpa层,它依次查找修改/新创建的对象。这些最有可能是您创建/修改的(直接或从ui)。这种begaviour更容易调试和测试,如果您创建unittests,它会变得更容易;然而,我无法理解为什么JSF表单post会触发JPA函数。如何跟踪/排除事件链?谢谢,我尝试了您的建议,但整个
帐户
表仍在
个人
表的
插入
上更新。查看我的编辑以了解实际的跟踪行。看来您的JPA框架可能被配置为自动提交,您在应用程序中使用的是哪个ORM引擎?你能发布它的全局配置吗?与persistence.xml文件类似?我发布了
persistence.xml
,请参阅更新2。还可以尝试以下更改:@JoinColumn(name=“account\u id”,nullable=false)->以允许在持久保存个人时插入account中的空值。还有:@OneToOne(mappedBy=“usrAccount”,可选=true)。还可以尝试使用cascade={}->empty,我想你的意思是
nullable=true
。是的,我应该补充这一点,以防止无意中的错误,谢谢。我知道它不应该保持这种方式-因此我自己的TODO提醒。增强能解决我的问题吗?RuntimeUnhancedClass中有一些讨厌的bug。。。这就是我要开始的地方。我已经在我的项目中添加了增强功能,这和根管工作一样令人愉快。但它解决了这个问题!不再更新未触及的表。非常感谢。(顺便说一下,OpenJPA项目可能会考虑从版本1.2.1到2。x更新Eclipse增强插件,而Hoto页面包含几个遗漏)。
public List<Account> getUsrAccounts()
{
    List<Account> accts = em.createNamedQuery( "Account.findAll", Account.class ).getResultList();
    for (Account acct : accts)
        em.detach(acct);
    return accts;
}