首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >我需要在playframework 1.x中挂接一个级联保存

我需要在playframework 1.x中挂接一个级联保存
EN

Stack Overflow用户
提问于 2012-11-17 09:06:33
回答 2查看 334关注 0票数 1

在playframework 1.x中,我需要弄清楚如何将级联保存挂接到特定的类扩展模型中。我需要钩子,这样我就可以执行一段代码,在持久化之前使用数据重新计算对象上的数据字段,这些数据最终来自级联到对象中的其他类的模型对象的数据字段。

由.save()启动的实际进程似乎对挂钩非常抵触。我无法挂接saveAndCascade(),创建一个setWillBeSaved()方法也没有提供挂接,尽管播放框架文档似乎建议它应该提供挂接。

我有一个解决方案,但它似乎是一个相当“糟糕”的解决方案,它涉及到一个黑客欺骗hibernate编写本不应该写的东西。

hack解决方案是向对象添加一个"hack“布尔值字段,并在每次加载、持久化或更新对象时切换该字段。这是为了让它永远不会干净。

这样做是因为到目前为止我所能找到的唯一的钩子是一个用@PrePersist和@PreUpdate注释的方法。问题是,如果hibernate不相信对象是脏的,它就不会调用带注释的方法。当级联到相关对象中的一个相关对象中的数据字段发生变化时,这就会产生问题,这应该会促使重新计算,从而使干净的对象变脏,但重新计算没有发生,因为hibernate认为该对象是干净的。

这是我使用的解决方案的一个简单版本(神圣的水桶添加了4个令人讨厌的空格)。持久化下面的任何一个对象都会导致对象a持久化正确的a值。

代码语言:javascript
运行
复制
@Entity
public class A extends Model
{
    @OneToMany(mappedBy="a", cascade = CascadeType.ALL)
    private List<B> bList = new ArrayList<B>();
    private Integer a = 0;
    private Boolean hack = true;

    //algorithm that only matters to the question so far as it uses data fields from B and C.
    public Integer getA()
    {
        Integer returnValue = 0;

        for(B b : bList)
        {
            returnValue = returnValue + b.getB();

            for(C c : b.getCList())
            {
                returnValue = returnValue + c.getC();
            }
        }

    return  returnValue;
    }

    public void setBList(List<B> bList)
    {
        this.bList = bList;
    }

    public List<B> getBList()
    {
        return bList;
    }

    //Hibernate will not call this method if it believes the object to be clean.
    @PrePersist
    @PreUpdate
    private void recalculateA()
    {
        hack = !hack; //remove the dirt and cross our fingers that hibernate won't write if the object is no longer dirty.
        a = getA(); //recalculate the value of A, reflecting the changes made in the objects cascading into A.
    }

    //Hack to put dirt on every clean object to force hibernate to call recalculateA whenever someone tries to save A.
    @PostPersist
    @PostUpdate
    @PostLoad
    private void hack()
    {
        hack = !hack;
    }

}

-

代码语言:javascript
运行
复制
@Entity
public class B extends Model
{
    @ManyToOne(cascade = CascadeType.ALL)
    private A a;

    @OneToMany(mappedBy = "b",  cascade = CascadeType.ALL)
    private List<C> cList = new ArrayList<C>();

    private Integer b = 0;

    public List<C> getCList()
    {
        return cList;
    }

    public void setCList(List<C> cList)
    {
        this.cList = cList;
    }

    public void setA(A a)
    {
        this.a = a;
    }

    public void setB(Integer b)
    {
        this.b = b;
    }

    public Integer getB()
    {
        return b;
    }

}

代码语言:javascript
运行
复制
@Entity
public class C extends Model
{
    @ManyToOne(cascade = CascadeType.ALL)
    private B b;

    private Integer c = 0;

    public C(Integer c)
    {
        this.c = c;
    }

    public Integer getC()
    {
        return c;
    }

    public void setC(Integer c)
    {
        this.c = c;
    }

    public void setB(B b)
    {
        this.b = b;
    }
}

我的“一定有更好的方法来做这件事”的感觉非常激动。

EN

回答 2

Stack Overflow用户

发布于 2012-11-19 14:49:34

您可以覆盖保存的根对象上的save方法,并从那里调用计算方法。

对我来说,将业务计算隐藏到持久化过程中并不是一件好事,因为您可以确保每次都会调用它,但您却将其隐藏在需要技术知识的过程中。

通过某种"calculateAndSave“方法显式调用此计算方法可以使其更清晰。

票数 0
EN

Stack Overflow用户

发布于 2012-11-20 14:43:51

另一种解决方案是强制hibernate通过getA方法获取a值

代码语言:javascript
运行
复制
@Entity
public class A extends Model
{
    @OneToMany(mappedBy="a", cascade = CascadeType.ALL)
    private List<B> bList = new ArrayList<B>();
    @Transient
    private Integer a = 0;
    private Boolean calculated = false;

    @Access(AccessType.PROPERTY)
    public Integer getA()
    {
        if (!calculated) {
            Integer returnValue = 0;

            for(B b : bList)
            {
                returnValue = returnValue + b.getB();

                for(C c : b.getCList())
                {
                    returnValue = returnValue + c.getC();
                }
            }

            a = returnValue;
            calculated = true;
        }
        return a;
    }

    public void setBList(List<B> bList)
    {
        this.bList = bList;
        calculated = false;
    }

    public List<B> getBList()
    {
        return bList;
    }
}

但这意味着您可以在每次计算源更改时使计算标志无效,当b对象的cList更改时,这可能会很困难。

如果您的计算量不是很大,您还可以避免使用calculated标志,并在每次调用getA时重做。这是最简单的解决方案,但性能不是最好的

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13426630

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档