错误:分离的实体传递给持久化 - 尝试持久化复杂数据(播放框架) [英] Error: detached entity passed to persist - try to persist complex data (Play-Framework)

查看:22
本文介绍了错误:分离的实体传递给持久化 - 尝试持久化复杂数据(播放框架)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在通过 play-framework 保存数据时遇到问题.也许不可能达到那个结果,但如果它有效就真的很好.

I have a problem with persisting data via play-framework. Maybe it's not possible to achive that result, but it would be really nice if it would work.

简单:我有一个复杂的模型(带有地址的商店),我想立即更改带有地址的商店并以相同的方式存储它们(shop.save()).但是发生了detached entity传递给persist的错误.

Simple: I have a complex Model (Shop with Addresses) and I want to change the shop with addresses at once and store them in the same way (shop.save()). But the error detached entity passed to persistoccurs.

Udate 历史05.11

  • 05.11

  • 05.11

  • 使用属性mappedBy="shop"
  • 更新模型商店
  • 更新谷歌用户组链接

09.11

  • 找到一种解决方法,但它不是通用的

16.11

  • 更新示例 html 表单,感谢@Pavel
  • 将解决方法(更新 09.11)更新为通用方法,感谢@mericano1
  • 我放弃了寻找解决方案并等待 play 2.0...

日期:我试图将问题减少到最低限度:
型号:

Dateil: I try to cut down the problem to a minimum:
Model:

@Entity
public class Shop extends Model {

    @Required(message = "Shopname is required")
    public String shopname;

    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="shop")
    public List<Address> addresses;

}


@Entity
public class Address extends Model {

    @Required
    public String location;

    @ManyToOne
    public Shop shop;
}

现在是我的前端代码:

#{extends 'main.html' /}

#{form @save(shop?.id)}

    <input type="hidden" name="shop.id" value="${shop?.id}"/>

    #{field 'shop.shopname'}
        <label for="shopName">Shop name:</label>
        <input type="text" name="${field.name}" 
            value="${shop?.shopname}" class="${field.errorClass}" />
    #{/field}

    <legend>Addressen</legend>
    #{list items: shop.addresses, as: "address"}
        <input type="hidden" name="shop.addresses[${address_index - 1}].id" value="${address.id}"/>
        <label>Location</label>
        <input name="shop.addresses[${address_index - 1}].location" type="text" value="${address.location}"/>
    #{/list}

     <input type="submit" class="btn primary" value="Save changes" />
#{/form}

我只有商店本身的 ID 和要通过 POST 交付的商店名称,例如:?shop.shopname=foo

I have just the Id from the Shop itself and the shopname to deliver via POST like: ?shop.shopname=foo

中间部分是地址列表,我有地址的 ID 和位置,结果将类似于:?shop.shopname=foo&shop.addresses[0].id=1&shop.addresses[0].location=bar.

The interssting part is the list of addresses and there I have the Id and the location from the address and the result would be somthin like: ?shop.shopname=foo&shop.addresses[0].id=1&shop.addresses[0].location=bar.

现在是数据的控制器部分:

public class Shops extends CRUD {

public static void form(Long id) {

    if (id != null) {
        Shop shop = Shop.findById(id);
        render(shop);
    }
    render();
}

public static void save(Long id, Shop shop) {

    // set owner manually (dont edit from FE)
    User user = User.find("byEmail", Security.connected()).first();
    shop.owner = user;

    // Validate
    validation.valid(shop);
    if (validation.hasErrors()) 
        render("@form", shop);

    shop.save();
    index();
}

现在问题:当我更改地址数据时,代码到达shop.save(); 对象商店充满了所有数据,一切看起来都很好,但是当休眠尝试持久化数据时,会发生错误分离实体传递给持久化 :(

Now the problem: When i change the address data the code reaches the shop.save(); the object shop is filled with all data and everything looks fine, but when hibernate tryes to persist the data, the error detached entity passed to persist occurs :(

我尝试更改获取模式、级联类型,我也尝试过:

I tried to change the fetch mode, the cascadetype and i also tried:

Shop shop1 = shop.merge();
shop1.save();

不幸的是没有任何效果,要么发生错误,要么不会存储地址数据.有没有办法以这种方式存储数据?

Unfortunately nothing worked, either the error occurs, or no address data will be stored. Is there a way to store the data in that way?

如果有什么不清楚的请写信给我,我很乐意提供尽可能多的信息.

If there is somthing not clear please write to me, I would be glad to give as much information as possible.

更新 1我也把问题放在 google 用户组

更新 2 + 3在用户组的帮助下(感谢 bryan w.)和来自 mericano1 的回答,我找到了一个通用的解决方法.

Update 2 + 3 With the help of the user group (thanks to bryan w.) and an Answer from mericano1 here I found a generic workaround.

首先,您必须从 shop.class 中的属性 addresses 中删除 cascade=CascadeType.ALL.然后您必须更改shops.class 中的save 方法.

First you have to remove cascade=CascadeType.ALL from attribute addresses in shop.class. Then you have to change the method save within shops.class.

public static void save(Long id, Shop shop) {

    // set owner manually (dont edit from FE)
    User user = User.find("byEmail", Security.connected()).first();
    shop.owner = user;

    // store complex data within shop
    storeData(shop.addresses, "shop.addresses");
    storeData(shop.links, "shop.links");

    // Validate
    validation.valid(shop);
    if (validation.hasErrors()) 
        render("@form", shop);

    shop.save();
    index();
}

存储数据的通用方法如下所示:

the generic method to store the data looks like that:

private static <T extends Model> void  storeData(List<T> list, String parameterName) {
    for(int i=0; i<list.size(); i++) {
        T relation = list.get(i);

        if (relation == null)
            continue;

        if (relation.id != null) {
            relation = (T)Model.Manager.factoryFor(relation.getClass()).findById(relation.id);
            StringBuffer buf = new StringBuffer(parameterName);
            buf.append('[').append(i).append(']');
            Binder.bind(relation, buf.toString(), request.params.all());
        }

        // try to set bidiritional relation (you need an interface or smth)
        //relation.shop = shop;
        relation.save();
    }
}

我在 Shop.class 中添加了一个 链接 列表,但我不会更新其他代码片段,因此如果出现编译错误,请注意.

I added in Shop.class a list of Links, but I won't update the other code snippets, so be warned if compiling errors occur.

推荐答案

当你在 Hibernate 中更新一个复杂的实例时,你需要确保它来自数据库(先获取它,然后更新同一个实例)以避免这种情况分离实例"问题.

When you update a complex instance in Hibernate you need to make sure it is coming from the database (fetch it first, then update that same instance) to avoid this 'detached instance' problem.

我通常更喜欢总是先获取,然后才更新我期望从 UI 中获得的特定字段.

I generally prefer to always fetch first and then only update specific fields I'm expecting from the UI.

您可以使用

(T)Model.Manager.factoryFor(relation.getClass()).findById(relation.id);

这篇关于错误:分离的实体传递给持久化 - 尝试持久化复杂数据(播放框架)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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