java / Spring Hibernate没有更新实体

时间:2014-08-02 00:32:57

标签: java spring hibernate jpa persistence

我已经在SO和许多其他网站上阅读并重读了所有内容,但似乎无法弄清楚为什么我更新的对象没有更新。

我正在做的基本概述:

  1. 服务层要求DAO提供一些

  2. 从DB(DAO / @Repository)返回 People 的ArrayList

  3. 服务层操纵对象并将其添加到新的arraylist

  4. 服务层将新列表传递回DAO以进行更新

  5. 没有更新

  6. 如果我在我的对象中抛出一条日志消息有新的值,那么这些孩子就会正确补充水分。我在代码中没有错误,只是没有提交我的更改。

    以下是一些代码:

    PersonDAO 注释为@Repository

    public void updatePeople(List<Person> people) {
        log.info("Updating " + people.size() + " people");
        try {
            Transaction tx = getCurrentSession().beginTransaction();
            for (Person person : people){
                getCurrentSession().saveOrUpdate(person);
            }
            getCurrentSession().flush();
            tx.commit();
            getCurrentSession().close();
    
        } catch (Exception e){
            log.error("Exception Updating all people " + e.toString());
            e.printStackTrace();
        }
    
    }
    
    public List<Person> getAssociatesByStoreId(String storeId) {
        try {
    
            List<Person> usersInStore = (List<Person>) getCurrentSession()
                    .createCriteria(Person.class).createCriteria("store")
                    .add(Restrictions.eq("storeId", storeId)).list();
    
            return usersInStore;
        } catch (Exception e) {
            log.error("exception in getAssociatesByStoreId ", e);
        }
        return null;
    }
    

    PersonService 注释为@Service - 相关方法

    /* I put the people into a map to do some other logic on them */
    for (Person person : personDAO.getAllPeople()){
                personMap.put(person.getEmployeeId() + "-" + person.getStore().getStoreId(), person);
    }
    
    /*    
     I iterate a list creating new Person objects (based on some random stuff), 
     including saving any children entities (managementcodes and stores) that need to be created
     After I have created a new Person I attempt to find it in the map from above.  
     If I find it pull it out of the map and put it into an array list 
     that is eventually passed back into the DAO
    */
    

    注明为@Entity

    private int personid;
    private String firstName;
    private String lastName;
    private Store store;
    private ManagementCode managementCode;
    
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name = "personid", unique = true, nullable = false)
    public int getPersonid() {
        return this.personid;
    }
    
        /*a bunch of getters and setters*/
    @ManyToOne(fetch = FetchType.LAZY, optional = true, cascade = {CascadeType.MERGE, CascadeType.PERSIST})
    @org.hibernate.annotations.Cascade( {org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.PERSIST})
    @LazyCollection(LazyCollectionOption.EXTRA)
    @JoinColumn(name = "managementlevel", nullable = true)
    public ManagementCode getManagementCode() {
        return this.managementCode;
    }
    
    @ManyToOne(fetch = FetchType.LAZY, optional = true, cascade = {CascadeType.MERGE, CascadeType.PERSIST})
    //  @org.hibernate.annotations.Cascade( {org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.PERSIST})
    @JoinColumn(name = "storeid", nullable = false)
    public Store getStore() {
        return this.store;
    }
    

    商店注释为实体(管理代码相同)

    /*fields + getters and setter */
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "store", cascade = {CascadeType.MERGE, CascadeType.PERSIST})
    @LazyCollection(LazyCollectionOption.EXTRA)
    @JsonIgnore 
    public Set<Person> getPersons() {
        return this.persons;
    }
    

    编辑我在上面添加了两组Cascade类型的注释但仍然没有运气

    编辑2 更新了以显示主键定义 在我踢小狗之前,请有人帮助我。 感谢

3 个答案:

答案 0 :(得分:1)

可能是您需要在ManyToOne注释上使用“cascade = {CascadeType.MERGE,CascadeType.PERSIST}”。默认行为不会将任何内容级联到关联的对象。

 /**
 * (Optional) The operations that must be cascaded to
 * the target of the association.
 *
 * <p> By default no operations are cascaded.
 */
CascadeType[] cascade() default {};

例如

@ManyToOne(optional = true, cascade = {CascadeType.MERGE, CascadeType.PERSIST}, fetch = EAGER)

更新: 如果您使用的是Spring托管事务管理器并且可以自由使用注释驱动的事务划分,则可以尝试使用spring @Transactional注释,而不是手动启动事务和提交/刷新。

我有以下设置:

<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

<tx:annotation-driven transaction-manager="transactionManager"/>

<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
    <property name="persistenceUnitName" value="persistenceUnit"/>
    <property name="dataSource" ref="local-dataSource"/>
    <property name="packagesToScan" value="X"/>
    <property name="persistenceXmlLocation" value="classpath:persistence.xml"/>
</bean>

DAO课程:

@Repository
public class EventRepository {

@PersistenceContext
EntityManager entityManager;


@Transactional
public void persist(Event event) {
    entityManager.persist(event);
}
}

答案 1 :(得分:1)

JPA有三种主要类型的实体对象:

  1. 管。这些是由JPA-provider缓存的对象,因此JPA提供程序会跟踪它们的状态,并在事务提交时提交对它们所做的任何更改。这些是查询时获得的对象。他们有一个数据库ID。
  2. 新。这些是尚未保留在数据库中的实体对象。 JPA提供商对它们一无所知。他们没有数据库ID。
  3. 分离。这些是以前管理的对象,但不再是。通常,返回到事务外部的方法的对象。这些对象具有数据库ID,但它们不是缓存的一部分,因此JPA提供程序不知道它们。
  4. 为了保持实体与另一个实体之间的关系,引用的实体必须进行管理。有多种方法可以实现这一目标。

    1. 级联。从实体A到实体B的级联意味着当您在代码中对实体A执行级联操作时,JPA提供程序将对实体B执行相同的操作。如果向关系添加CascadeType.MERGE,让实体A引用一个分离的实体B,然后在实体A上执行merge()将首先到实体B上的merge(),使其得到管理。然后,当存储实体A时,它具有对托管B的引用,并且该关系是持久的。 (如果您还想继续引用尚未包含在数据库中的对象,请同时添加CascadeType.PERSIST。)
    2. 确保您只引用托管对象。在事务内部,加载引用的对象(托管对象)并在存储之前用托管对象替换引用。
    3. 加宽您的交易。这样,引用的对象永远不会分离。

答案 2 :(得分:0)

首先,确保在那些ManyToOne注释上使用拟合CascadeType。

其次,entityManager / session中的合并操作不会通过引用保持对象相等。这意味着,在执行合并的更新情况下,检查是否返回了不同的对象。您应该始终使用保存操作的返回值。