我在通过 Play Framework 持久化数据时遇到问题。也许不可能达到那个结果,但如果它能奏效那就太好了。
简单:我有一个复杂的模型(带地址的商店),我想立即更改带地址的商店并以相同的方式存储它们(shop.save())。但是错误 detached entity passed to persist
发生了。
更新历史 05.11
05.11
- 使用属性
mappedBy="shop"
更新模型商店 - 更新指向 google 用户组的链接
- 使用属性
09.11
- 找到解决方法,但不是通用的
16.11
- 更新示例 html 表单,感谢@Pavel
- 将解决方法(更新 09.11)更新为通用方法,感谢@mericano1
- 21.11
- 我放弃了寻找解决方案并等待 play 2.0...
日期:
我尽量减少问题:
型号:
@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
interssting 部分是地址列表,我有 ID 和地址的位置,结果会像这样:?shop.shopname=foo&shop.addresses[0].id=1&shop。地址[0].location=bar
。
现在是数据的 Controller 部分:
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();
对象商店充满了所有数据,一切看起来都很好,但是当 hibernate 尝试保留数据时,发生错误 detached entity passed to persist
:(
我尝试更改获取模式、级联类型,我也尝试过:
Shop shop1 = shop.merge();
shop1.save();
不幸的是,没有任何效果,要么发生错误,要么没有地址数据被存储。 有没有办法以这种方式存储数据?
如果有什么不清楚的地方请写信给我,我很乐意提供尽可能多的信息。
更新 1 我也把问题放在了google user group
更新 2 + 3 在用户组的帮助下(感谢 bryan w.)和 mericano1 的回答,我找到了一个通用的解决方法。
首先,您必须从 shop.class 中的属性 addresses
中删除 cascade=CascadeType.ALL
。然后您必须更改 shops.class 中的方法 save
。
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();
}
存储数据的通用方法如下所示:
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 中添加了一个 Links 列表,但我不会更新其他代码片段,因此如果出现编译错误请注意。
最佳答案
当您在 Hibernate 中更新一个复杂的实例时,您需要确保它来自数据库(首先获取它,然后更新同一个实例)以避免这种“分离实例”问题。
我通常更喜欢始终先获取,然后仅更新我期望从 UI 中获取的特定字段。
您可以使用
使您的代码更通用一些(T)Model.Manager.factoryFor(relation.getClass()).findById(relation.id);
关于java - 错误 : detached entity passed to persist - try to persist complex data (Play-Framework),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7986970/