Почему я получаю сообщение об ошибке при обращении к данным в приложении Micronaut Gorm? - PullRequest
0 голосов
/ 29 января 2019

У меня есть простое приложение в Mironaut с тремя объектами: клиент, контакт и кредиты.Клиент имеет отношения 1 ко многим с Контактом и Кредитами.Я тестирую с Grails / Gorm, и он отлично работает.

У меня есть класс DataLoader, который хорошо работает и создает все сущности с их связями.

/ ****** Contact.groovy ******* /

package com.gnc.demo.domain

import grails.gorm.annotation.Entity

@Entity
class Contact {
    Long id
    Long version

    Customer customer
    static belongsTo = Customer


    String email
    String phone
    String cellPhone
    String address
}

/ ****** Customer.groovy ******* /

package com.gnc.demo.domain
import grails.gorm.annotation.Entity

@Entity
class Customer {
    Long id
    Long version
    String driverId
    String name
    String lastName

    static hasMany = [contacts: Contact, loans: Loan]
    static constraints = {
        contacts nullable: true
        loans nullable: true
    }

    static mapping = {
       contacts lazy: false
        loans lazy: false
    }
}

/ ******Loan.groovy ******* /

package com.gnc.demo.domain

import grails.gorm.annotation.Entity

@Entity
class Loan {
    Long id
    Long version

    Customer customer
    static belongsTo = Customer

    BigDecimal ammount
    long term
    BigDecimal rate

}

/ ******* CustomerController.groovy ******* /

 package com.gnc.demo.controllers


 import com.gnc.demo.domain.Customer

 import com.gnc.demo.services.ContactService
 import com.gnc.demo.services.CustomerService
 import com.gnc.demo.services.LoanService
 import io.micronaut.http.annotation.Controller
 import io.micronaut.http.annotation.Get

 import org.slf4j.Logger
 import org.slf4j.LoggerFactory


 @Controller("/customer")
 class CustomerController {
     private static final Logger LOG = LoggerFactory.getLogger(CustomerController.class);


     final CustomerService customerService
     final LoanService loanService
     final ContactService contactService

     CustomerController(CustomerService customerService, LoanService loanService, ContactService contactService) {
         this.customerService = customerService
         this.loanService = loanService
         this.contactService = contactService
     }

     @Get("/")
     String index() {
         return "Hola ! " + new Date()
     }

     @Get("/all/{offset}/{max}")
     List<Customer> getCustomers(String offset, String max) {
         List<Customer> customers = customerService.findAll([offset: offset, max: max])
         try {
             customers.each { customer ->
                 // LOG.info(">>> Loans   :" +customer.loans.size())
                 customer.contacts = []
                 customer.loans = []
             }
         } catch (Exception e) {
             LOG.info(">>> Error :" + e)
         }


         return customers
     }

     @Get("/{id}")
     Customer getCustomers(String id) {
         Customer customer = customerService.get(id)
         customer?.contacts = []
         customer?.loans = []

         customer?.contacts = contactService.findAllByCustomer(customer)
         customer?.loans = loanService.findAllByCustomer(customer)
         return customer

     }
 }

Всекод доступен в: https://github.com/gnpitty/com-gnc-demo

Но когда я тестирую в Micronaut с моим браузером: http://localhost:9020/customer/10

, я получаю эту ошибку:

{"message":"Internal Server Error: Error encoding object 
[com.gnc.demo.domain.Customer : 10] to JSON: could not initialize proxy - no
Session (through reference chain: com.gnc.demo.domain.Customer[\"contacts\"]-
>java.util.LinkedHashSet[0]->com.gnc.demo.domain.Contact[\"customer\"]-
>com.gnc.demo.domain.Customer_$$_jvst110_0[\"driverId\"])"}

1 Ответ

0 голосов
/ 14 февраля 2019

Как сказано в одном комментарии, вы должны убедиться, что при чтении записи используются @Transactional или withTransaction {}.

Кроме того, если вы хотите сослаться на прокси-элементы (например, ссылку на клиента), вынеобходимо заставить элемент прокси быть прочитанным.Я знаю о двух способах: 1) выполнить выборку на них или 2) явно разрешить прокси.

Я выбрал вариант 2), так как не хотел принудительно вызывать выборку, когда она не нужна.Я использую это только в контроллерах, где я возвращаю объект домена в кодировке JSON.Обычно это только в моих методах REST API.

Пример:

Loan.withTransaction {
  def loan = Loan.findByXYZ()
  resolveProxies(loan)   
}

Это преобразовывает прокси в реальные объекты, чтобы вы могли получить к ним доступ вне замыкания withTransaction {}.Обычно Джексон конвертирует их в JSON.

Я использую этот метод для разрешения любых прокси в списках или в качестве простых ссылок на другой объект домена:

  /**
   * Resolves all proxies for the given domain class.  This allows the domain to be used outside of an hibernate session
   * if needed.  This will check all fields and sub-objects for proxies.
   * <p>
   * <b>Note:</b> This will usually force a read of all referenced objects.
   * @param object The object.
   */
  def resolveProxies(Object object) {
    if (object == null) {
      return
    }

    for (property in object.class.gormPersistentEntity.persistentProperties) {
      def value = object[property.name]
      if (Collection.isAssignableFrom(property.type) && value) {
        for (item in value) {
          if (item != null) {
            // Resolved any sub-objects too.
            resolveProxies(item)
          }
        }
      } else if (value instanceof HibernateProxy) {
        // A simple reference, so unproxy it the GORM way.
        object[property.name] = value.getClass().get(value.id)
      }

    }
  }

Не стесняйтесь использовать этот код где угоднотебе это нужно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...