Grails Gorm: объект ссылается на несохраненный временный экземпляр - PullRequest
5 голосов
/ 27 января 2011

При сохранении экземпляра Trip в Grails я получаю следующее исключение:

2011-01-26 22: 37: 42,801 [http-8090-5] ОШИБКА ошибок.GrailsExceptionResolver - объект ссылается на несохраненный временный экземпляр - сохраните переходный процесс перед промывкой: Гребец org.hibernate.TransientObjectException: объект ссылается на несохраненный переходный процесс instance - сохранить временный экземпляр до промывки: гребец

Концепция проста: для прогулки на лодке вам нужны гребцы, рулевой (также гребец) и лодка:

Поездка выглядит (сокращенно):

class Trip {
    Boat boat;
    Rower coxwain;

    static belongsTo = [Rower,Boat]
    static hasMany = [rowers:Rower]
}

и Гребец (укороченный)

class Rower { 
    String firstname;
    String name;
    Rower reference;

    static hasMany = [trips:Trip];
    static mappedBy = [trips:"rowers"]
}

Отключение сохраняется в контроллере как:

def save = {
        def trip = new Trip(params)

        // adding Rowers to Trip
        if (params.rower instanceof String) {
            def r = Rower.get(params?.rower)

            if (r != null) {
                trip.addToRowers(r)
            }
        } else {
            params?.rower?.each{
                rowerid ->
                def r = Rower.get(rowerid)
                log.info("rowerid (asList): " + rowerid)
                if (r != null) {
                    trip.addToRowers(r)
                }
            }
        } 

        // saving the new Trip -> EXCEPTION IN NEXT LINE
        if(!trip.hasErrors() && trip.save(flush:true)) {
          // ...
        }
        // ...
}

Я думаю, что установил правильные отношения между доменами. Гребец не изменяется, пока он добавляется в Поездку. Почему Grails хочет это сохранить? почему это временный экземпляр?

Ответы [ 7 ]

7 голосов
/ 13 февраля 2011

К сожалению, это проблема того, как GORM обрабатывает вещи, или, более конкретно, того, как он ожидает, что вы имеете дело с переходными процессами. Если вы сначала не сохраните содержащиеся в базе данных классы (в данном случае Rowers), вы получите это исключение каждый раз.

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

Хотелось бы, чтобы были лучшие новости. Не то чтобы это сложно, но это раздражает сложными иерархиями.

1 голос
/ 07 июля 2011

Просто быстрая заметка для любого, кто имеет дело с единичными или несколькими параметрами с одинаковым именем, с помощью помощника params.list("parameterName") вы всегда можете вернуть список

    ...

    // adding Rowers to Trip
    if (params.rower instanceof String) {
        def r = Rower.get(params?.rower)

        if (r != null) {
            trip.addToRowers(r)
        }
    } else {
        params?.rower?.each{
            rowerid ->
            def r = Rower.get(rowerid)
            log.info("rowerid (asList): " + rowerid)
            if (r != null) {
                trip.addToRowers(r)
            }
        }
    } 

    ...

может стать немного лучше

    ...

    // adding Rowers to Trip
    for(rower in params.list("rower") {
        def r = Rower.get(rower) 
        if(r) trip.addToRowers(r)
    } 

    ...

вы можете найти его скрытым под 6.1.12. Преобразователи простого типа

1 голос
/ 29 января 2011

Проблема была как-то иначе. это здесь:

def trip = new Trip(params)

, который ссылается на coxwain (класса Rower), который не установлен (возвращается id = -1). Это создает новый Rower вместо «нулевого» значения. И это «несохраненный временный экземпляр». Если я сначала проверю действительный экземпляр, то он будет работать: -)

Спасибо за помощь!

0 голосов
/ 14 июня 2018

Предположим, что вы используете Trip is hasMany отношения с Rower

class Trip {
      static hasMany = [rowers:Rower]
      ...
    }

class Rower{
      static belongsTo =[trips:Trip]
      ...
   }

На самом деле, он ищет новую сессию. Поэтому нам нужно остановить / откатить текущую транзакцию, тогда эта ошибка не возникнет, для этого Попробуйте это,

  def row = new Row()
  row.save()

ПРИМЕЧАНИЕ: это сохранение не повлияет на вашу базу данных. Это просто для отката транзакции.

0 голосов
/ 29 сентября 2017

Во многих случаях вы можете решить эту проблему, применив настройку cascade к своей коллекции:

static mapping = {
    rowers cascade: 'all-delete-orphan'
}

https://docs.grails.org/latest/ref/Database%20Mapping/cascade.html

0 голосов
/ 27 января 2011

Сначала я подумал, что это связано с каскадным сохранением и принадлежностью, как описано в Справочнике по Grails , раздел 5.2.1.3 и Gorm Gotchas part 2 .Однако, поскольку Гребцы уже в БД, я думаю, что это должно работать.Модель предметной области сложна для меня, вам нужно упростить ее и запустить несколько тестов с помощью консоли Grails (запустите консоль grails в каталоге вашего проекта).Сначала создайте базовое множество «многие ко многим» между Trip и Rower и заставьте его выполнить нужный код.Затем добавляйте другие части по крупицам, как, например, ссылка на себя.Я не уверен, что часть mappedBy необходима вообще.

0 голосов
/ 27 января 2011

Я думаю, что вы должны сохранить поездку, прежде чем добавить ровер в поездку. Также нет смысла проверять, есть ли ошибки в поездке, прежде чем проверять и / или сохранять ее.

Попробуйте это:

if(trip.validate() && trip.save(flush:true)) {
    if (r != null) {
       trip.addToRowers(r)
    }  
}
...