使用Eclipselink DescriptorCustomizer进行软删除级联

时间:2012-10-22 20:54:20

标签: java jpa eclipselink

亲爱的同事们,我带着以下人员来找你:

我正在使用EclipseLink作为我的应用程序的ORM,并尝试在我的一个实体(文章)上实现Soft Delete,并在删除具有OneToMany关系的Catagory时级联删除这些文章。

当我删除文章时,一切都按预期工作,但当我删除一个有n条文章的类别时,我会得到一个例外。我正在使用DescriptorCustomizer来完成软删除。

DescriptorCustomizer(参见 org.eclipse.persistence.config.DescriptorCustomizer ),具有以下实现:

public class ArticleCustomizer implements DescriptorCustomizer {

    @Override
    public void customize(ClassDescriptor classDescriptor) throws Exception {
       classDescriptor.getQueryManager().setDeleteSQLString("UPDATE article SET ACTIVE = '0' WHERE id = #id");
    }
}

我要保存的实体:

AbstractItem

@Entity
@Table(name = "item")
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class AbstractItem extends BaseEntity {
    @ManyToOne
protected Category category;
}

@Entity
@DiscriminatorValue("article")
@Customizer(value=ArticleCustomizer.class)
public class Article extends AbstractItem {

}

分类

@Entity
@Customizer(value=CategoryCustomizer.class)
public class Category extends BaseEntity {

    @OneToMany(cascade = CascadeType.REMOVE)
    @JoinTable(name = "category_items", joinColumns = @JoinColumn(name = "category_id"), inverseJoinColumns = @JoinColumn(name = "item_id"))
    protected List<AbstractItem> items = new ArrayList<AbstractItem>();

    @OneToMany(cascade = CascadeType.REMOVE)
    @JoinTable(name = "category_subcategories", joinColumns = @JoinColumn(name = "category_id"), inverseJoinColumns = @JoinColumn(name = "parent_category_id"))
    protected List<Category> categories = new ArrayList<Category>();
}

当我尝试级联删除具有n条文章的类别时的错误:

Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'ACTIVE' in 'field list'
Error Code: 1054
Call: UPDATE article SET ACTIVE = '0' WHERE id = ?
bind => [null]

我可以看到id被绑定为null,但是我不明白为什么。有人可以指导我朝正确的方向发展吗?

  1. Eclipselink版本:2.4.0
  2. Spring:3.1.2RELEASE
  3. 谢谢!

2 个答案:

答案 0 :(得分:3)

我很抱歉你的时间已经过去了。解决方案就在我面前:

classDescriptor.getQueryManager().setDeleteSQLString("UPDATE item SET ACTIVE = '0' WHERE id = #ID");

自定义程序的正确表应该是 ITEM 而不是 ARTICLE 。奇怪的是,它适用于单个文章删除,并不适用于级联。

第二个问题是:

#id instead of #ID

它区分大小写。

感谢您的帮助!

答案 1 :(得分:0)

每当一个类实现DescriptorCustomizer时,我建议将其编码包装在:

public static class MyCustomizer implements DescriptorCustomizer {
    @Override
    public void customize(ClassDescriptor descriptor) throws Exception {
        try {
           ...
           ... your functionality 
           ...
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }
}

原因是DescriptorCustomizer导致无声失败, 当日志记录设置低于FINER时(这非常详细)。然后异常不会传播到“外部”,你也不会注意到它们,也不能找出失败的原因。

或者,您可以将EMF属性PersistenceUnitProperties.LOGGING_LEVEL级别设置为SessionLog.FINER_LABEL