Связь Grails «многие ко многим» не работает должным образом

Я новичок в Grails и столкнулся с трудной проблемой отношения «многие ко многим».

Вот упрощенные классы домена:

class Comment {
    String title
    String comment

    static hasMany = [commentGroups:CommentGroup]

    static constraints = {
        title blank:true
        comment blank:false, maxSize:800
    }

    static mapping = {
        commentGroups cascade: "all-delete-orphan"
    }

}

class CommentGroup {

    String groupTitle

    static hasMany = [comments:Comment]
    static belongsTo = Comment

    static constraints = {
        groupTitle blank:true, nullable:true
    }
}

Вот html-выдержка из формы, которая динамически создается с использованием JS. ПОЖАЛУЙСТА, ОБРАТИТЕ ВНИМАНИЕ, ЧТО ВСЕ ПРИВЕДЕННЫЙ КОД НЕ ЗАВЕРШЕН, ЭТО ТОЛЬКО ДЛЯ того, чтобы дать вам представление о том, что мне нужно для достижения:

<form class="m-b-d" role="form" name="comments" id="comments" method="post" action="/rootstofood/comment/save">



  <div class="form-group has-feedback col-sm-12">
    <label for="rating" class="control-label">Give us a star rating?</label>
    <div class="br-wrapper br-theme-bootstrap-stars">
      <select aria-describedby="Rating" name="rating" id="rating" class="form-control input-lg" style="display: none;">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
        <option value="4">4</option>
        <option value="5">5</option>
      </select>
      <div class="br-widget"><a href="#" data-rating-value="1" data-rating-text="1"><span></span></a><a href="#" data-rating-value="2" data-rating-text="2"><span></span></a><a href="#" data-rating-value="3" data-rating-text="3"><span></span></a><a href="#" data-rating-value="4"
        data-rating-text="4"><span></span></a><a href="#" data-rating-value="5" data-rating-text="5"><span></span></a>
        <div class="br-current-rating"></div>
      </div>
    </div>
  </div>

  <div class="form-group has-feedback col-sm-12">
    <label for="commentTitle" class="control-label sr-only">Any short comment header?</label>
    <input aria-describedby="Comment title" placeholder="Any short comment header?" value="" id="commentTitle" name="commentTitle" class="form-control input-lg" maxlength="200">
    <span aria-hidden="true" class="glyphicon glyphicon-ok form-control-feedback hidden"></span>
    <span class="sr-only" id="commentTitle">(success)</span>
  </div>

  <div class="form-group has-feedback col-sm-12">
    <label for="startComment" class="control-label sr-only">Start comment</label>
    <textarea rows="3" aria-describedby="Start comment" placeholder="Enter start comment" id="startComment" name="startComment" class="form-control input-lg vrequired" maxlength="400"></textarea>
    <span aria-hidden="true" class="glyphicon glyphicon-ok form-control-feedback hidden"></span>
    <span class="sr-only" id="startComment">(success)</span>
  </div>

  <!-- Children or staff comments area START -->

  <!-- ##### Dynamic area START #### -->
  <div class="col-sm-12" id="comment-groups">

    <div class="panel panel-default p-trbl" data-group-id="0" id="comment-group-0" data-remove-group-id="0">
      <div class="ovh">
        <div class="pull-left"><b>Comment Group: 0</b>
        </div><a class="danger pull-right remove-comment-group" data-remove-group-id="0" href="#"><span class="glyphicon glyphicon-remove-sign"></span> Remove</a>
      </div>
      <div class="panel-body">

        <div class="form-group has-feedback col-sm-12">
          <label for="title" class="control-label sr-only">Any short comment header?</label>
          <input aria-describedby="Comment Group title" placeholder="Any short comment group header?" value="" name="commentGroups[0].groupTitle" class="form-control input-lg" maxlength="200">
          <span aria-hidden="true" class="glyphicon glyphicon-ok form-control-feedback hidden"></span>
          <span class="sr-only" id="title">(success)</span>
        </div>

        <!-- Children or staff comments area START -->
        <div class="col-sm-12" data-comments-group-id="0" id="comments">

          <div class="panel panel-default p-trbl" data-comment-group-id="GROUP" id="comment-0_0">
            <div class="ovh">
              <div class="pull-left"><b>Staff/Pupil Group/Comment: 0</b>
              </div><a class="danger pull-right remove-comment" data-remove-comment-id="0_0" href="#"><span class="glyphicon glyphicon-remove-sign"></span> Remove</a>
            </div>
            <div class="panel-body">
              <div class="form-group has-feedback col-sm-12">
                <label for="startComment" class="control-label sr-only">Comment</label>
                <textarea id="commentGroups[0].comments[0].startComment" rows="3" aria-describedby="Comment" placeholder="Enter comment" name="commentGroups[0].comments[0].startComment" class="form-control input-lg vrequired" maxlength="400"></textarea>
                <span aria-hidden="true" class="glyphicon glyphicon-ok form-control-feedback hidden"></span>
                <span class="sr-only" id="comment">(success)</span>
              </div>
              <div class="form-group has-feedback col-sm-10">
                <label for="name" class="control-label sr-only">Name</label>
                <input type="text" aria-describedby="Name" placeholder="Name" name="commentGroups[0].comments[0].name" class="form-control input-lg vrequired" maxlength="30">
                <span aria-hidden="true" class="glyphicon glyphicon-ok form-control-feedback hidden"></span>
                <span class="sr-only" id="name">(success)</span>
              </div>
              <div class="form-group has-feedback col-sm-2">
                <label for="type" class="control-label sr-only">Comment from</label>
                <select aria-describedby="Type" name="commentGroups[0].comments[0].type" id="type" class="form-control input-lg">
                  <option value="Parent">Parent</option>
                  <option value="Pupil">Pupil</option>
                  <option value="Staff">Staff</option>
                  <option value="KS1">KS1</option>
                  <option value="KS2">KS2</option>
                  <option value="Other">Other</option>
                </select>
              </div>
            </div>
          </div>
        </div>
        <div class="form-group has-feedback col-sm-12">
          <a data-comment-group-id="0" class="add-comment success" href="#"><span class="glyphicon glyphicon-plus-sign"></span> Add another pupil or staff comment</a>
        </div>
        <!-- Children or staff comments area END -->

      </div>
    </div>
  </div>

  <div class="form-group has-feedback col-sm-12">
    <a class="add-group success" href="#"><span class="glyphicon glyphicon-plus-sign"></span> Add another comment group</a>
  </div>

  <!-- Children or staff comments area END -->

  <div class="form-group has-feedback col-sm-12">
    <label for="endComment" class="control-label sr-only">End comment</label>
    <textarea rows="3" aria-describedby="End comment" placeholder="Enter end comment" id="endComment" name="endComment" class="form-control input-lg" maxlength="400"></textarea>
    <span aria-hidden="true" class="glyphicon glyphicon-ok form-control-feedback hidden"></span>
    <span class="sr-only" id="endComment">(success)</span>
  </div>

  <div class="form-group has-feedback col-sm-2">
    <label for="title" class="control-label sr-only">Title</label>
    <select aria-describedby="Title" name="title" id="title" class="form-control input-lg">
      <option value="Mr">Mr</option>
      <option value="Mrs">Mrs</option>
      <option value="Ms">Ms</option>
      <option value="Miss">Miss</option>
      <option value="Mr &amp; Mrs">Mr &amp; Mrs</option>
    </select>
  </div>

  <div class="form-group has-feedback col-sm-10">
    <label for="firstName" class="control-label sr-only">Name</label>
    <input type="text" aria-describedby="Name" placeholder="Name" id="name" name="name" class="form-control input-lg vrequired" maxlength="60">
    <span aria-hidden="true" class="glyphicon glyphicon-ok form-control-feedback hidden"></span>
    <span class="sr-only" id="Name">(success)</span>
  </div>

  <div class="form-group has-feedback col-sm-12">
    <label for="jobTitle" class="control-label sr-only">Job title</label>
    <input type="text" aria-describedby="Job title" placeholder="Job title" id="jobTitle" name="jobTitle" class="form-control input-lg" maxlength="60">
    <span aria-hidden="true" class="glyphicon glyphicon-ok form-control-feedback hidden"></span>
    <span class="sr-only" id="jobTitle">(success)</span>
  </div>

  <div class="form-group has-feedback col-sm-12">
    <label for="organisation" class="control-label sr-only">Organisation</label>
    <input type="text" aria-describedby="Organisation" placeholder="Organisation" id="organisation" name="organisation" class="form-control input-lg" maxlength="60">
    <span aria-hidden="true" class="glyphicon glyphicon-ok form-control-feedback hidden"></span>
    <span class="sr-only" id="organisation">(success)</span>
  </div>

  <div class="form-group has-feedback col-sm-2">
    <label for="type" class="control-label sr-only">Type</label>
    <select aria-describedby="Type" name="type" id="type" class="form-control input-lg">
      <option value="Parent">Parent</option>
      <option value="Pupil">Pupil</option>
      <option value="Staff">Staff</option>
      <option value="KS1">KS1</option>
      <option value="KS2">KS2</option>
      <option value="Other">Other</option>
    </select>
  </div>



  <div class="col-md-12">
    <button class="btn btn-default btn-lg onWht" id="feedback" type="submit"><b>Submit Feedback <span class="glyphicon glyphicon-chevron-right"></span></b>
    </button>
  </div>

</form>

Вот мое незавершенное действие по сохранению контроллера, которое почти готово:

    def save() {
        def commentInstance = new Comment(params)

        if (!commentInstance.save(flush: true)) {
            render(view: "index", model: [commentInstance: commentInstance])
            return
        }
        render(view: "thankyou")
}

Итак, из кода у меня есть родительский домен «Комментарий», в котором много «Групповых комментариев», в котором много «Комментариев».

Когда я создаю свой проект, моя база данных дает мне следующие таблицы:

comment
comment_comment_groups
comment_group

Что меня удивило, так как я установил отношение «многие ко многим», поэтому ожидал:

comment
comment_comment_groups
comment_group_comments
comment_group

Я, вероятно, ожидаю, что Grails сделает здесь слишком много работы. Поэтому, когда я отправляю форму комментариев, база данных заполняется моим родительским «Комментарием» и даже доменами «CommentGroup», принадлежащими «Комментарию», но комментарии «CommentGroup» не сохраняются в базе данных.

Я понимаю, что здесь я наивен, но что я упускаю? Может ли кто-нибудь помочь, поскольку я искал повсюду и не мог найти подобный сценарий. Я знаю, что существует множество примеров отношений «многие ко многим», но ни один из них не охватывает мой сценарий.

А пока продолжу поиск.

Я предполагаю, что мне нужно создать более сложное действие «сохранить» в моем контроллере, вручную обрабатывая параметры, но было бы хорошо, если бы для этого существовал способ GORM.

С нетерпением жду ответа ... пожалуйста, будьте нежны со мной :-)

Заранее спасибо.


person AndyRED    schedule 11.10.2015    source источник


Ответы (1)


Удалить из каскада commentGroups класса домена комментариев: "all-delete-orphan" и добавить в сопоставление CommentGroup: comments cascade: "all-delete-orphan".

new Comment(params).save() сохранить группу комментариев со всеми комментариями, принадлежащими этой группе.

person swiatows    schedule 11.10.2015
comment
Спасибо за ваш ответ, но теперь я получаю следующее сообщение об ошибке: - person AndyRED; 12.10.2015
comment
... Ошибка | 2015-10-12 09:50:31,444 [http-bio-8080-exec-4] ERROR errors.GrailsExceptionResolver - AssertionFailure произошла при обработке запроса: [POST] /rootstofood/comment/save - параметры: ... нулевой идентификатор в Запись roottofood.Comment (не очищайте сеанс после возникновения исключения). Stacktrace следует: Сообщение: нулевой идентификатор в записи roottofood.Comment (не очищайте сеанс после возникновения исключения)... - person AndyRED; 12.10.2015
comment
Я думаю, что нулевой идентификатор в комментарии - это подсказка, но все еще не знаю, как это решить? - person AndyRED; 12.10.2015
comment
поэтому текущая транзакция становится недействительной, но затем вы пытаетесь продолжить другие операции в этом сеансе. Проверьте и подтвердите параметры перед сохранением комментария. - person swiatows; 12.10.2015