防止不必要的级联表更新 [英] Prevent unwanted cascaded table updates

查看:96
本文介绍了防止不必要的级联表更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am creating my first JPA based project. My application features several tables with foreign key relationships for integrity purposes. Many related tables are normalized lookup tables.

考虑在accountid上具有fk关系的表PersonAccount:

Consider the tables Person and Account, having a fk relationship on accountid:

+-Person----+               
| personid  |               +-Account---+
| accountid*|==============>| accountid |
| ...       |               | ...       |
+-----------+               +-----------+

在前端(JSF)中,我为包含所有帐户的selectOneMenu列表的新Person对象创建了一个表单,并将所选的 accountid 添加到新的人员,它已正确插入数据库中.

In the front end (JSF), I created a form for new Person objects containing a selectOneMenu list with all accounts, and the selected accountid is added to the new person which is inserted correctly into the database.

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

However, the Account table is also updated automatically and I cannot find a way to stop this from happening.

我的班级注释如下:

@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;

    ...

@Entity
@Table(name="usr_account")
@NamedQuery(name="UsrAccount.findAll", query="SELECT u FROM Account u")
public class Account implements Serializable 
{
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="account_id")
    private int accountId;

    //bi-directional one-to-one association to UsrPerson
    @OneToOne(mappedBy="usrAccount")
    private Person usrPerson;

    ...

前端调用以下方法,该方法仅使用EntityManager的merge()函数来持久保存新的Person对象:

The front end calls the below method which simply uses the merge() function of EntityManager to persist the new Person object:

public String savePerson()
{
    try
    {
        em.getTransaction().begin();
        person = em.merge( person );
        em.getTransaction().commit();
    }
    catch (Exception e)
    {
        ...

这将导致对Account表中的每个对象进行UPDATE调用 .

This leads to an UPDATE call for every object in the Account table.

更新

我从代码中删除了EntityManager.merge()调用,并且UPDATE语句仍然存在. JSF表单以某种方式导致支持它的Account对象的自动更新.以下几行来自JPA跟踪:

I removed the EntityManager.merge() call from my code and the UPDATE statements are still there. Somehow the JSF form leads to automatic updates of the Account objects backing it. The lines below are from the JPA trace:

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

这些语句在我commit()交易时执行.由于某种原因,查询和后续事务导致JPA相信selectOneMenu中的所有Account对象都已被修改;我该如何预防呢?首先一个接一个地分离它们吗?

These statements are executed when I commit() the transaction. For some reason the query and subsequent transaction leads JPA to believe all Account objects from the selectOneMenu are modified; how do I prevent this? Detach them first one-by-one?

更新2

我的persistence.xml如下:

My persistence.xml is as follows:

<?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>

同时,我在后备bean中查询了Account对象后,将其分离,如下所示:

Meanwhile, I have detached the Account objects after I query them in the backing bean, like this:

public List<Account> getUsrAccounts()
{
    List<Account> accts = em.createNamedQuery( "Account.findAll", Account.class ).getResultList();
    for (Account acct : accts)
        em.detach(acct);
    return accts;
}

然后,当我提交新的Person对象时,JPA仅更新链接到新的PersonAccount.即使那样也是不希望的,而且我感觉到我在某种程度上滥用了JPA.

Then when I commit the new Person object, only the Account that is linked to the new Person is updated by JPA. Even that is undesirable, and I get the feeling that I am misusing JPA in some way.

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

What is the normal way to use a non-editable lookup table with JPA?

推荐答案

在persistence.xml中未启用<property name="openjpa.RuntimeUnenhancedClasses" value="supported"/>.找出另一种增强策略.

Do not have <property name="openjpa.RuntimeUnenhancedClasses" value="supported"/> enabled in your persistence.xml. Figure out another enhancement strategy.

这篇关于防止不必要的级联表更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆