Tob*_*now 10 java hibernate playframework
我有一个问题,通过播放框架持久化数据.也许不可能取得这样的结果,但如果它能起作用那将是非常好的.
简单:我有一个复杂的模型(Shop with Addresses),我想立即用地址更改商店并以相同的方式存储它们(shop.save()).但是错误detached entity passed to persist
发生了.
Udate历史 05.11
05.11
mappedBy="shop"
09.11
16.11
Dateil:我尝试将问题减少到最低限度:
型号:
@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;
}
Run Code Online (Sandbox Code Playgroud)
@Entity
public class Address extends Model {
@Required
public String location;
@ManyToOne
public Shop shop;
}
Run Code Online (Sandbox Code Playgroud)
现在我的前端代码:
#{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}
Run Code Online (Sandbox Code Playgroud)
我只有商店本身的ID和通过POST提供的商店名称: ?shop.shopname=foo
interssting部分是地址列表,我在那里有Id和地址的位置,结果将像somthin一样:?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();
}
Run Code Online (Sandbox Code Playgroud)
现在问题:当我更改地址数据代码到达shop.save();
对象商店充满了所有数据,一切看起来很好,但当hibernate试图持久化数据时,出现错误detached entity passed to persist
:(
我试图改变获取模式,cascadetype,我也试过:
Shop shop1 = shop.merge();
shop1.save();
Run Code Online (Sandbox Code Playgroud)
不幸的是,没有任何工作,或者发生错误,或者不存储地址数据.有没有办法以这种方式存储数据?
如果有什么不清楚请写信给我,我很乐意尽可能多地提供信息.
更新1 我也将问题放在谷歌用户组
更新2 + 3 在用户组的帮助下(感谢bryan w.)和mericano1的答案,我找到了一个通用的解决方法.
首先,您必须cascade=CascadeType.ALL
从addresses
shop.class中的属性中删除.然后你必须save
在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();
}
Run Code Online (Sandbox Code Playgroud)
存储数据的通用方法如下所示:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
我在Shop.class中添加了一个链接列表,但我不会更新其他代码片段,因此如果发生编译错误则会收到警告.
当您在Hibernate中更新复杂实例时,您需要确保它来自数据库(首先获取它,然后更新同一个实例)以避免这个"分离实例"问题.
我通常更喜欢始终先获取,然后只更新我期望从UI中获取的特定字段.
您可以使用更加通用的代码
(T)Model.Manager.factoryFor(relation.getClass()).findById(relation.id);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
5737 次 |
最近记录: |