2

私が達成しようとしているのは、このサンプルアプリだけです:〜\ play-2.1.0 \ samples \ java \ forms

更新された最新のコード:

私のようにquestion.scala.html見えます:

@(questionForm: Form[Question])

@import helper._
@import helper.twitterBootstrap._



@answerField(field: Field, className: String = "answer") = {

<div class="twipsies well @className">
    <table>
        <tr>
            <td> @checkbox(field("addRight"),'_label -> "Add")</td>
            <td> @checkbox(field("editRight"),'_label -> "Edit")</td>
            <td> @checkbox(field("delRight"),'_label -> "Delete")</td>
            <td> @checkbox(field("viewRight"),'_label -> "View")</td>
        </tr>
    </table>
</div>

}


@if(questionForm.hasErrors) {
    <div class="alert-message error">
        <p><strong>Oops</strong> Please fix all errors</p>
    </div>
}

@helper.form(action = routes.Questions.submit, 'id -> "form") {

    <fieldset>

        @inputText(
            questionForm("name"),
            '_label -> "Name of a Right"
        )

        @inputText(
            questionForm("namex"),
            '_label -> "Name of a Right"
        )

        <div class="answers">

            @repeat(questionForm("answers"), min = 0) { answer =>
                @answerField(answer)
            }



            @**
            * Keep an hidden block that will be used as template for Javascript copy code
            * answer_template is only css style to make it hidden (look main.css and declare your own answer_template at bottom)
            **@
            @answerField(
                questionForm("answers"),
                className = "answer_template"
            )

            <div class="clearfix">
                <div class="input">
                    <a class="addAnswer btn success">Add </a>
                </div>
            </div>

        </div>
    </fieldset>

    <div class="actions">
        <input type="submit" class="btn primary" value="Insert">
    </div>

}

<script type="text/javascript" charset="utf-8">

        $('.removeAnswer').on('click', function(e) {
        var answers = $(this).parents('.answers');
        $(this).parents('.answer').remove();
        renumber(answers);
        });

        $('.addAnswer').on('click', function(e) {
        var answers = $(this).parents('.answers');
        var template = $('.answer_template', answers);
        template.before('<div class="clearfix answer">' + template.html() + '</div>');
        renumber(answers);
        });

        $('#form').submit(function() {
        $('.answer_template').remove()
        });

        // -- renumber fields
        // This is probably not the easiest way to do it. A jQuery plugin would help.

        var renumber = function(answers) {
        $('.answer').each(function(i) {
        $('input', this).each(function() {
        $(this).attr('name', $(this).attr('name').replace(/answers\[.+?\]/g, 'answers[' + i + ']'))
        });
        });
        }

</script>

...。

質問モデル:

package models;

import play.data.validation.Constraints;
import play.db.ebean.Model;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import java.util.ArrayList;
import java.util.List;


@Entity
public class Question extends Model {

@Id
public Long id;

@Constraints.Required
public String name;


@OneToMany(cascade = CascadeType.PERSIST, mappedBy = "question")
public List<Answer> answers;

public Question() {

}

public Question(String name) {
    this.name = name;

}
}

回答モデル:

@Entity
public  class Answer extends Model {

@Id
public Long id;

public boolean addRight;
public boolean editRight;
public boolean delRight;
public boolean viewRight;

@ManyToOne
public Question question;

public Answer() {
}

public Answer(boolean addRight,boolean editRight,boolean delRight,boolean viewRight, 
Question question) {
    this.addRight = addRight;
    this.editRight = editRight;
    this.delRight = delRight;
    this.viewRight = viewRight;
    this.question = question;
}
}

そして最後にコントローラーの保存部分:

  public static Result submit() {
    Form<Question> filledForm = questionForm.bindFromRequest();

    if(filledForm.hasErrors()) {
        User user = User.findByUserName("samuel");
        return badRequest(question.render(filledForm));
    }
    else {
        // If we dont have any errors, we should be around here :)
        Question question = filledForm.get();
        // Since Answer needs reference to Question and with new Question
        // it cant get it loaded from DB we need to do little dirty trick here
        // in order to save new question id instantly to answers foreign_key
        // as question_id, otherwise it will be null
        System.out.println("-->" + question.answers.size() );
        if(question.answers != null) {
            ArrayList<Answer> answersCopy = new ArrayList<Answer>();
            Logger.trace("Size of Anwsers : " +answersCopy.size());
            for(Answer answer : question.answers) {
                answersCopy.add(new                  
   Answer(answer.addRight,answer.editRight,answer.delRight,answer.viewRight,question));
                System.out.println("##" + answer.addRight);
            }
            question.answers = answersCopy;
        }
        question.save();
        return ok("Nice, all saved!");

    }
}

上記のコードでは、例外は発生しませんが、..質問の部分では、Anwserを残しておく必要があります。

ありがとう

4

1 に答える 1

2

JPA を使用して動作するようになったと思います。JPA で作成するか、Ebean だけで作成するかは少しわかりませんでしたが、あなたや他の人は Ebean にも移植できると思います。(ご要望があればお作りすることも可能です(^^;)

JPAで試したことは次のとおりです。

  • ターミナル (または cmd) を開き、というプロジェクトに移動します。play-2.1.0/samples/java/forms
  • 次に(念のため)次のコマンドを実行します。play clean .. play compile .. play eclipse
  • Eclipseに移動してそこにインポートします(右クリックしてエクスプローラーをパッケージ化->既存のプロジェクト..)
  • 次の行を開いてconf/application.conf追加 (またはコメント解除) します。
db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"
db.default.jndiName=DefaultDS
jpa.default=defaultPersistenceUnit
  • とのフォルダ構造をconf/evolutions/default作成conf/META-INF
  • persistence.xml次の内容で名前が付けられたファイルを追加します。

http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0">

<persistence-unit name="defaultPersistenceUnit" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <non-jta-data-source>DefaultDS</non-jta-data-source>
    <properties>
        <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
    </properties>
</persistence-unit>
 </persistence>
  • Answer モデルと Question モデルのテーブルを作成し、次の内容のファイル1.sqlを作成します。evolutions/default
# --- !Ups

create table question (
  id                        bigint not null,
  name                      varchar(255),
  constraint pk_question primary key (id))
;

create table answer (
  id                        bigint not null,
  name                      varchar(255),
  question_id               bigint,
  constraint pk_answer primary key (id))
;

create sequence answer_seq start with 1000;
create sequence question_seq start with 1000;

alter table answer add constraint fk_answer_question_1 foreign key (question_id) references question (id) on delete restrict on update restrict;

# --- !Downs

SET REFERENTIAL_INTEGRITY FALSE;

drop table if exists question;
drop table if exists answer;

SET REFERENTIAL_INTEGRITY TRUE;

drop sequence if exists question_seq;
drop sequence if exists answer_seq;
  • 次のモデルを変更または追加します。
package models;

import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.ManyToOne; 

import play.data.validation.Constraints.Required;

@Entity 
@SequenceGenerator(name = "answer_seq", sequenceName = "answer_seq")
public class Answer {

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "answer_seq")
public Long id;

@Required
public String name;

@ManyToOne
public Question question;

public Answer() { 
}

public Answer(String name, Question question) {   
      this.name = name;
      this.question = question;
}

}

...

package models;

import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import play.data.validation.Constraints.Required;
import play.db.jpa.*;

@Entity
@SequenceGenerator(name = "question_seq", sequenceName = "question_seq")
public class Question {

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "question_seq")
public Long id;

@Required
public String name;

@Valid
@OneToMany(cascade = CascadeType.PERSIST, mappedBy = "question")
public List<Answer> answers;

public Question() {

}

public Question(String name) {
      this.name = name;
}

public void save() {

      JPA.em().persist(this);

      List<Question> allQuestions = JPA.em().createQuery("from Question order by name").getResultList();

      System.out.println("Number of questions: " + allQuestions.size());

      for(Question q : allQuestions) {

             System.out.println("Question --- id: " + q.id + ", name: " + q.name);

                if(q.answers != null) {

                   for(Answer a : q.answers) {
                           System.out.println("Answer --- id: " + a.id + ", name: " + a.name + " question_id: " + a.question.id);
                   }
             }
      }

}

}
  • さて、モデルがOKになったので、routesファイルから始めて、これをテストするために静止コントローラーとビューを作成しましょう:
# Question
GET     /questions                  controllers.Questions.blank()
POST    /questions                  controllers.Questions.submit()
  • 次に、次のコントローラーを追加します。
package controllers;

import static play.data.Form.form;
import java.util.ArrayList;
import models.Answer;
import models.Question;
import play.data.Form;
import play.db.jpa.Transactional;
import play.mvc.Controller;
import play.mvc.Result;
import views.html.question.*;

public class Questions extends Controller {

/**
* Defines a form wrapping the Question class.
*/ 
final static Form<Question> questionForm = form(Question.class);

/**
* Display a blank form.
*/ 
public static Result blank() {
    return ok(form.render(questionForm));
}

@Transactional
public static Result submit() {

Form<Question> filledForm = questionForm.bindFromRequest();

if(filledForm.hasErrors()) {
     return badRequest(form.render(filledForm));
} else {

// If we dont have any errors, we should be around here :)
Question question = filledForm.get();

// Since Answer needs reference to Question and with new Question
// it cant get it loaded from DB we need to do little dirty trick here
// in order to save new question id instantly to answers foreign_key
// as question_id, otherwise it will be null
if(question.answers != null) {
     ArrayList<Answer> answersCopy = new ArrayList<Answer>();
     for(Answer answer : question.answers) {
     answersCopy.add(new Answer(answer.name, question));
}
question.answers = answersCopy;
}
question.save();

// You can also use this test code to save data
// Question question = new Question("What is your favorite color?");
// question.answers = new ArrayList<Answer>();
// question.answers.add(new Answer("Blue", question));
// question.answers.add(new Answer("Red", question));
// question.save();

return ok("Nice, all saved!");

}
}

}
  • わかりました、まだ1つのビューがあります。views.question名前を付けて作成しますform.scala.html(ところで、アプリケーションがすでに連絡先に使用している同様のコードを再利用しましたが、モデルで動作するようにしました。)
@(questionForm: Form[Question])

@import helper._ 
@import helper.twitterBootstrap._

@title = {
     Add a new question 
}

@answerField(field: Field, className: String = "answer") = {
    @input(field, '_label -> "Answer", '_class -> className) { (id, name, value, _) =>
    <input type="text" name="@name" value="@value"> 
    <a class="removeAnswer btn danger">Remove</a>
} 
}

@main(title, nav = "question") {

@if(questionForm.hasErrors) {
    <div class="alert-message error">
        <p><strong>Oops</strong> Please fix all errors</p>
    </div>
}

@helper.form(action = routes.Questions.submit, 'id -> "form") {

<fieldset>
<legend>Fill a question with answers</legend>

@inputText(
    questionForm("name"), 
    '_label -> "Name of a question"
)

<div class="answers">

@repeat(questionForm("answers"), min = 0) { answer =>
     @answerField(answer("name"))
}

@**
* Keep an hidden block that will be used as template for Javascript copy code
* answer_template is only css style to make it hidden (look main.css and declare your own answer_template at bottom)
**@
@answerField(
    questionForm("answers[x].name"),
    className = "answer_template"
)

<div class="clearfix">
<div class="input">
    <a class="addAnswer btn success">Add answer</a>
</div>
</div>

</div>
</fieldset>

<div class="actions">
<input type="submit" class="btn primary" value="Insert">
<a href="@routes.Application.index" class="btn">Cancel</a>
</div>

}

<script type="text/javascript" charset="utf-8">

$('.removeAnswer').live('click', function(e) {
    var answers = $(this).parents('.answers');
    $(this).parents('.answer').remove();
    renumber(answers);
});

$('.addAnswer').live('click', function(e) {
    var answers = $(this).parents('.answers');
    var template = $('.answer_template', answers);
    template.before('<div class="clearfix answer">' + template.html() + '</div>');
    renumber(answers);
});

$('#form').submit(function() {
    $('.answer_template').remove()
});

// -- renumber fields
// This is probably not the easiest way to do it. A jQuery plugin would help.

var renumber = function(answers) {
$('.answer').each(function(i) {
    $('input', this).each(function() {
         $(this).attr('name', $(this).attr('name').replace(/answers\[.+?\]/g, 'answers[' + i + ']'))
         });
    });
}

</script>
}
  • 最終調整として、main.css ファイルの最後の行を確認して、編集を忘れないようにします。
.phone_template, .profile_template, .answer_template {
     display: none;
}
  • これを追加main.scala.htmlします:
<li class="@("active".when(nav == "question"))">
   <a href="@routes.Questions.blank()">Questions</a>
</li>
  • まだ行っていない場合は、ブラウザーに移動し、進化が実行されることを確認し、質問ビューに移動して、さまざまな質問と値でフォームを送信してみてください。

Play のターミナル ウィンドウに結果が表示されるはずです (下にある私のものと同様)。その場合、新しい質問をいくつかの回答で正常に保存した場合は、好きなように繰り返すことができます。新しい ID は常に生成されるため、機能するはずです。 . フォームに編集なども含めたい場合は、プレイ サンプル フォルダー (computer-database-jpa) 内で JPA がどのように使用されているかを確認することをお勧めします。後で github に投稿するかもしれません。おやすみなさい。

Number of questions: 1
Question --- id: 50000, name: What is your favorite color?
Answer --- id: 50000, name: Blue question_id: 50000
Answer --- id: 50001, name: Red question_id: 50000
于 2013-03-11T19:52:31.840 に答える