Playframework 2和manytoone形式绑定

时间:2014-09-30 20:57:11

标签: java spring playframework-2.0 many-to-one

我正在关注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;
}

在控制器中我有以下内容:

    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");
    }

我得到的例外是

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对象,但其中的所有值都为null。然后我逐步介绍了bindToRequest方法,我发现对于嵌套绑定,即)projectionSet.id,spring绑定器在setPropertyValue方法中的org.springframework.beans.BeanWrapperImpl类中引发异常

private void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {

,特别是,当PropertyValue的resolvedDescriptor为null时,它会抛出NotWriteablePropertyException。

我是Spring的新手,它是绑定库。我不知道如何才能让这个属性得到妥善解决。有什么想法吗?

1 个答案:

答案 0 :(得分:1)

尝试为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,尤其是最后一节,用于定义自定义对象的映射。