我正在遵循 Play 框架示例计算机数据库应用程序中的示例,并具有以下模型
public class Simulation implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long id;
@ManyToOne
@JoinColumn(name="projection_set_id")
public ProjectionSet projectionSet;
}
public class ProjectionSet {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long id;
}
在表单中,我有以下表单助手
@helper.select(
simulationForm("projectionSet.id"),
options(ProjectionSet.options),
'_label -> "Team Context",
'_showConstraints -> false
)
选项定义为
public static Map<String,String> options() {
List<ProjectionSet> projectionSets = ProjectionSet.findAll();
LinkedHashMap<String,String> options = new LinkedHashMap<String,String>();
for(ProjectionSet set: projectionSets) {
options.put(set.id.toString(), set.forDate.toString());
}
return options;
}
在 Controller 中我有以下内容:
Form<Simulation> filledForm = simulationForm.bindFromRequest();
Logger.debug("form = " + filledForm.toString());
if(filledForm.hasErrors()) {
final User user = BaseController.currentUser();
return badRequest(newSimulation.render(user, filledForm));
} else {
Map<String, String> formData = filledForm.data();
Simulation created = filledForm.get();
created.create();
return redirect("/simulations");
}
我遇到的异常(exception)是
Caused by: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing: models.simulations.Simulation.projectionSet -> models.baseball.ProjectionSet
at org.hibernate.engine.spi.CascadingAction$8.noCascade(CascadingAction.java:380) ~ [hibernate-core-4.2.7.Final.jar:4.2.7.Final]
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:176) ~[hibernate-core-4.2.7.Final.jar:4.2.7.Final]
at org.hibernate.event.internal.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:162) ~[hibernate-core-4.2.7.Final.jar:4.2.7.Final]
at org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:153) ~[hibernate-core-4.2.7.Final.jar:4.2.7.Final]
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:89) ~[hibernate-core-4.2.7.Final.jar:4.2.7.Final]
放置断点后,出现的问题是我从bindToRequest 获得的Simulation 类有一个ProjectionSet 对象,但其中的所有值均为空。然后我逐步执行了bindToRequest方法,我发现对于嵌套绑定(bind),即projectionSet.id,spring Binder 在setPropertyValue方法中的org.springframework.beans.BeanWrapperImpl类中抛出异常
private void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
特别是,当 PropertyValue 的resolvedDescriptor 为 null 时,它会抛出 NotWriteablePropertyException。
我对 Spring 及其绑定(bind)库非常陌生。我不确定我能做些什么来让这个属性得到正确的解决。有什么想法吗?
最佳答案
尝试为 ProjectionSet
类注册格式化程序。这样 Form.bindFromRequest()
知道如何将提交表单中的 id 转换为实际对象。我更喜欢在应用程序级别定义格式化程序,因此我将它们放在 Global 中对象。
public class Global extends GlobalSettings {
static {
play.data.format.Formatters.register(ProjectionSet.class,
new Formatters.SimpleFormatter<ProjectionSet>() {
@Override
public ProjectionSet parse(String id, Locale locale) throws ParseException {
ProjectionSet pSet = null;
try {
long tmpId = Long.parseLong(id);
pSet = ProjectionSet.finder.byId(tmpId);
} catch (NumberFormatException ignored) {
//unexpected id
}
return pSet;
}
@Override
public String print(ProjectionSet pSet , Locale locale) {
return pSet.id + "";
}
});
}
}
查看this page有关表单处理的更多信息,尤其是定义自定义对象的映射的最后一部分。
关于java - Playframework 2 和 Manytoone 表单绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26129994/