我在Mironaut中有一个简单的应用程序,其中包含三个实体:客户,联系人和贷款。 客户与联系和贷款有一对多的关系。我用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\"])"}
答案 0 :(得分:0)
正如一条评论所述,在读取记录时,应确保使用@Transactional或withTransaction {}。
此外,如果要引用代理元素(如“客户”引用),则需要强制读取代理元素。我知道两种方法:1)对它们进行快速获取,或2)明确解析代理。
我选择了选项2),因为我不想在不需要时强制进行快速获取。我仅在返回JSON编码域对象的控制器中使用此方法。通常这只是在我的REST API方法中。
示例:
Loan.withTransaction {
def loan = Loan.findByXYZ()
resolveProxies(loan)
}
这会将代理转换为真实对象,因此您可以在withTransaction {}闭包之外访问它们。通常是Jackson将它们转换为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)
}
}
}
随时随地使用此代码。