Grails v3.3.9 GORM дефект - один ко многим с mappedBy, обновления могут быть выполнены для сбоя - PullRequest
0 голосов
/ 31 января 2019

Grails v3.3.9 - влияет на live / dev и интеграционный тест

Мой сценарий состоит в том, что у меня был интеграционный тест, который продолжал давать сбой при создании записи, созданной вручную, и одной, найденной в БД, но работает, если вы связываетедве записи, созданные вручную в тесте.

Я пробовал тысячу твиков и убедился, что GORM делал то, что было сказано в документах.

Я сократил код и что-то построилболее простой, который выглядит структурно как мой реальный материал, но основан на модели Аэропорт / Полеты в руководстве пользователя GORM (см. раздел 5.1.2 в руководстве пользователя )

Объявите абстрактный базовый класс следующим образом

Airport.groovy

abstract class Airport{

    String name
    Collection<? extends Flight> outboundFlights = []
    Collection<? extends Flight>  inboundFlights = []

    static hasMany = [outboundFlights:Flight, inboundFlights:Flight]

    static mappedBy = [outboundFlights: 'departureAirport', inboundFlights: 'arrivalAirport']

    static constraints = {
        outboundFlights nullable:true
        inboundFlights nullable:true
    }

    static mapping = {
        tablePerHierarchy false  //multiple tables+joins
    }
}

Объявите конкретный класс, расширяющий этот класс, который вы можете использовать:

UkAirport.groovy

class UkAirport extends Airport {

    String shortCode = "dont know"

    static constraints = {
    }
}

Объявите объект Flight с двумя свойствами одного и того же типа

class Flight<A extends Airport> {

    String flightCode = "unassigned"

    A departureAirport
    A arrivalAirport

    //setup belongs to
    static belongsTo = [departureAirport:Airport, arrivalAirport:Airport]

    static constraints = {
    }
}

Теперь вот интеграционный тест;есть пара вещей, на которые стоит обратить внимание.

1) Я предварительно создаю UkAirport в настройке (для него не заявлено ни одного рейса) 2) Я создаю два ручных UkAirports в настоящем тесте - Gatwick и Stansted и сохраняю эти 3) Iустановить два рейса - один из Гатвика в Станстед и рейс 2 из Гатвика в предварительно спасенный Манчестер, который я нахожу, выполняя UkAirport.get ()

Вот странная вещь.Если я проведу этот тест, как показано здесь, - он пройдет, потому что я утверждаю, что в Манчестер не существует никаких рейсов (assert manchester.inboundFlights.size() == 0).

Однако, если вы прокомментируете это утверждение, и повторите тест,потерпит неудачу, и он объявит, что manchester.inboundFlights.size() равно 2 -

То же самое, если я использую отладчик - если остановиться и посмотреть на Манчестер до того, как я выполню flight2.save (), тест будет работать -если вы установите точку останова после flight2.save (), то manchester.inboundFlights покажет 2 записи, что неверно.

class AirportIntegrationSpec extends Specification {

    def setup() {

        Airport manchester = new UkAirport (name:"Manchester", shortCode:"MAN")
        manchester.save(failOnError:true)

    }

    def cleanup() {
    }

    void "two airports and one flight "() {

        given :

        Airport gatwick = new UkAirport (name:"Gatwick", shortCode:"LGW")
        Airport stansted = new UkAirport (name:"Stansted", shortCode:"STN")
        Airport manchester = UkAirport.get(1L)
        assert manchester.shortCode == "MAN"

        gatwick.save ()
        stansted.save ()

        when:
        Flight flight = new Flight<UkAirport>(flightCode:"F123-LGW-STN")
        gatwick.addToOutboundFlights(flight)
        stansted.addToInboundFlights(flight)
        flight.save (failOnError:true)
        assert gatwick.outboundFlights.size() == 1
        assert gatwick.inboundFlights.size() == 0
        assert stansted.outboundFlights.size() == 0
        assert stansted.inboundFlights.size() == 1


        // -all ok until we get to here  - if you evaluate manchester before you use it - test works
        //if you comment out and use before you evaluate it fails !
        assert manchester.inboundFlights.size() == 0  //comment out makes test fail !
        Flight flight2 = new Flight<UkAirport>(flightCode:"F789-LGW-MAN")
        gatwick.addToOutboundFlights(flight2)
        manchester.addToInboundFlights(flight2)
        flight2.save (failOnError:true)
        assert gatwick.outboundFlights.size() == 2
        assert manchester.inboundFlights.size() == 1



        then :""
        flight.id == 1
        flight2.id == 2
        gatwick.inboundFlights.size() == 0
        gatwick.outboundFlights.size() == 2
        stansted.outboundFlights.size() == 0
        stansted.inboundFlights.size() == 1
        flight.departureAirport.name == "Gatwick"
        flight.arrivalAirport.name == "Stansted"

        flight2.departureAirport.name == "Gatwick"
        flight2.arrivalAirport.name == "Manchester"


    }
}

Может ли кто-нибудь подтвердить, что это действительно дефект, и я его исправлю (временное обходное решение в коде - это доступ к сущности, выбранной из БД, - прежде чем вы затем построите какие-либо отношения вокругэто).

Мой проект Github здесь и интеграционный тест для всех это здесь .

Это мой предыдущий связанный стекВопрос переполнения - который я обновлю, так как он сводится к вышеприведенному.

...