Grails GORM 默认排序字段也是复合键的字段
Grails GORM default sort field which is also a field of a composite key
我的 Grails 是 2.5.0 版
我有两个域名类:
import org.apache.commons.lang.builder.HashCodeBuilder
class TemplateHeader implements Serializable {
int headerId
int ver
String templateName
String extraDescription
String serviceType
String createdBy
boolean isActive
String updatedBy
Date dateCreated
Date lastUpdated
static hasMany = [templateItems: TemplateItem]
static mapping = {
id composite: ['headerId', 'ver']
ver comment:''
templateName length: 40
serviceType length: 20
extraDescription length: 60
isActive defaultValue:false
templateItems sort:'itemNo', order:'asc'
}
static constraints = {
headerId unique: 'ver'
templateName nullable: false
serviceType nullable: false
}
boolean equals(other) {
if (!(other instanceof TemplateItem)) {
return false
}
other.id == id && other.ver == ver
}
int hashCode() {
def builder = new HashCodeBuilder()
builder.append id
builder.append ver
builder.toHashCode()
}
}
============================================= ==========
import org.apache.commons.lang.builder.HashCodeBuilder
class TemplateItem implements Serializable {
int itemNo
String itemName;
String unitName;
int unitPrice;
double defaultValue
boolean allowChange
String extraComment
String createdBy
String updatedBy
Date dateCreated
Date lastUpdated
static belongsTo = [templateHeader:TemplateHeader]
static mapping = {
id composite: [ 'templateHeader', 'itemNo']
itemNo comment:''
itemName length: 60
unitName length: 4
unitPrice comment:''
extraComment length: 60
defaultValue comment:''
allowChange comment:''
}
static constraints = {
itemName nullable: false
unitName nullable: false
extraComment nullable: true
defaultValue nullable: false
}
boolean equals(other) {
if (!(other instanceof TemplateItem)) {
return false
}
other.itemNo == itemNo && other.templateHeaderId == templateHeaderId
}
int hashCode() {
def builder = new HashCodeBuilder()
builder.append templateHeaderId
builder.append itemNo
builder.toHashCode()
}
}
当我运行 grails 应用程序时,它在构建表时显示以下异常:
|Running Grails application
context.GrailsContextLoaderListener Error initializing the application: Error creating bean with name 'transactionManagerPostProcessor': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager': Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory': Invocation of init method failed; nested exception is org.codehaus.groovy.grails.exceptions.GrailsDomainException: property from sort clause not found: accudata_portal.TemplateItem.itemNo
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManagerPostProcessor': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager': Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory': Invocation of init method failed; nested exception is org.codehaus.groovy.grails.exceptions.GrailsDomainException: property from sort clause not found: accudata_portal.TemplateItem.itemNo
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager': Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory': Invocation of init method failed; nested exception is org.codehaus.groovy.grails.exceptions.GrailsDomainException: property from sort clause not found: accudata_portal.TemplateItem.itemNo
... 4 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory': Invocation of init method failed; nested exception is org.codehaus.groovy.grails.exceptions.GrailsDomainException: property from sort clause not found: accudata_portal.TemplateItem.itemNo
... 4 more
Caused by: org.codehaus.groovy.grails.exceptions.GrailsDomainException: property from sort clause not found: accudata_portal.TemplateItem.itemNo
... 4 more
Error |
Forked Grails VM exited with error
有人告诉我如何解决吗?谢谢
我想知道为什么您在映射闭包中使用的字段没有收到错误,并且您没有为其定义任何映射,如 itemNo、unitPrice、defaultValue 等。
此外,您的 TemapletHeader 域中的 equals 条件应为:
if (!(other instanceof TemplateHeader))
现在回答您的问题,您收到此错误是因为 itemNo 属性 在 TemplateItem 域中TemplateHeader 域。 sort 关键字也接受映射。
要根据 itemNo 字段对 TemplateItem 对象进行排序,您必须在 TemplateItem 域的映射闭包中定义排序 属性
static mapping = {
.
.
.
sort 'itemNo': 'asc'
}
现在,每当您查询 TemplateItem 时,默认排序都会在 itemNo 字段上。
所以如果你使用
TemplateItem.findAllByTemplateHeader(templateHeaderInstance)
它将根据项目编号给出排序的模板项目。
通过在 TemplateItem 域中定义排序 属性 将不会对 TemplateHeader 域中的 templateItems 字段进行排序。原因是在获取域对象的关联时,Grails 忽略了该域的排序字段。如果您查看在获取 TemplateHeader 对象及其关联时生成的 sql,您将看到不同之处。
显然没有直接的方法可以实现您想要实现的目标,具体取决于您是想根据模板项对 TemapleHeader 对象进行排序,还是只对单个 TemplateHeader 对象中的模板项进行排序
要根据 TemplateItems 对 TemplateHeader 对象进行排序,请将以下排序 属性 添加到 TemplateHeader 域的映射闭包中:
static mapping = {
.
.
.
sort 'templateItems.itemNo': 'asc'
}
以及何时执行此 GORM
TemplateHeader header = TemplateHeader.list()
它生成以下 sql
select this_.header_id as header_i1_0_1_, this_.ver as ver2_0_1_, .... from template_header this_ inner join template_item templateit1_ on this_.header_id=templateit1_.template_header_header_id and this_.ver=templateit1_.template_header_ver order by templateit1_.item_no asc
现在这个查询的问题是它的执行成本非常高。它在 TemplateHeader 和 TemplateItem 域之间使用内部连接。因此,如果您在 TemplateHeader 域中有 2 条记录,在 TemplateItem 域中有 10 条记录,它将获取 10 条记录,而您只需要 2 条记录。另一个问题是 templateItems 属性 仍将被延迟获取。所以当你做 header.templateItems 时,它会再次查询数据库,结果不会根据 itemNo 排序。 sql 看起来像这样:
select templateit0_.template_header_header_id as template1_0_0_, templateit0_.template_header_ver as template2_0_0_, ... from template_item templateit0_ where templateit0_.template_header_header_id=? and templateit0_.template_header_ver=?
因此,如果您想对 TemplateHeader 对象的 templateItems 进行排序,您可以覆盖 templateItems 的 getter 并在那里对结果进行排序:
Set<TemplateItem> getTemplateItems() {
return templateItems?.sort { item_1, item_2 -> item_1?.itemNo <=> item_2?.itemNo }
}
以防万一在将 TemplateItem 对象添加到 TemplateHeader 对象时遇到这样的错误:
No signature of method: TemplateHeader.addToTemplateItems() is applicable for argument types: (TemplateItem)
然后尝试将 templateItems 声明为列表。
我的 Grails 是 2.5.0 版
我有两个域名类:
import org.apache.commons.lang.builder.HashCodeBuilder
class TemplateHeader implements Serializable {
int headerId
int ver
String templateName
String extraDescription
String serviceType
String createdBy
boolean isActive
String updatedBy
Date dateCreated
Date lastUpdated
static hasMany = [templateItems: TemplateItem]
static mapping = {
id composite: ['headerId', 'ver']
ver comment:''
templateName length: 40
serviceType length: 20
extraDescription length: 60
isActive defaultValue:false
templateItems sort:'itemNo', order:'asc'
}
static constraints = {
headerId unique: 'ver'
templateName nullable: false
serviceType nullable: false
}
boolean equals(other) {
if (!(other instanceof TemplateItem)) {
return false
}
other.id == id && other.ver == ver
}
int hashCode() {
def builder = new HashCodeBuilder()
builder.append id
builder.append ver
builder.toHashCode()
}
}
============================================= ==========
import org.apache.commons.lang.builder.HashCodeBuilder
class TemplateItem implements Serializable {
int itemNo
String itemName;
String unitName;
int unitPrice;
double defaultValue
boolean allowChange
String extraComment
String createdBy
String updatedBy
Date dateCreated
Date lastUpdated
static belongsTo = [templateHeader:TemplateHeader]
static mapping = {
id composite: [ 'templateHeader', 'itemNo']
itemNo comment:''
itemName length: 60
unitName length: 4
unitPrice comment:''
extraComment length: 60
defaultValue comment:''
allowChange comment:''
}
static constraints = {
itemName nullable: false
unitName nullable: false
extraComment nullable: true
defaultValue nullable: false
}
boolean equals(other) {
if (!(other instanceof TemplateItem)) {
return false
}
other.itemNo == itemNo && other.templateHeaderId == templateHeaderId
}
int hashCode() {
def builder = new HashCodeBuilder()
builder.append templateHeaderId
builder.append itemNo
builder.toHashCode()
}
}
当我运行 grails 应用程序时,它在构建表时显示以下异常:
|Running Grails application
context.GrailsContextLoaderListener Error initializing the application: Error creating bean with name 'transactionManagerPostProcessor': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager': Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory': Invocation of init method failed; nested exception is org.codehaus.groovy.grails.exceptions.GrailsDomainException: property from sort clause not found: accudata_portal.TemplateItem.itemNo
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManagerPostProcessor': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager': Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory': Invocation of init method failed; nested exception is org.codehaus.groovy.grails.exceptions.GrailsDomainException: property from sort clause not found: accudata_portal.TemplateItem.itemNo
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager': Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory': Invocation of init method failed; nested exception is org.codehaus.groovy.grails.exceptions.GrailsDomainException: property from sort clause not found: accudata_portal.TemplateItem.itemNo
... 4 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory': Invocation of init method failed; nested exception is org.codehaus.groovy.grails.exceptions.GrailsDomainException: property from sort clause not found: accudata_portal.TemplateItem.itemNo
... 4 more
Caused by: org.codehaus.groovy.grails.exceptions.GrailsDomainException: property from sort clause not found: accudata_portal.TemplateItem.itemNo
... 4 more
Error |
Forked Grails VM exited with error
有人告诉我如何解决吗?谢谢
我想知道为什么您在映射闭包中使用的字段没有收到错误,并且您没有为其定义任何映射,如 itemNo、unitPrice、defaultValue 等。
此外,您的 TemapletHeader 域中的 equals 条件应为:
if (!(other instanceof TemplateHeader))
现在回答您的问题,您收到此错误是因为 itemNo 属性 在 TemplateItem 域中TemplateHeader 域。 sort 关键字也接受映射。
要根据 itemNo 字段对 TemplateItem 对象进行排序,您必须在 TemplateItem 域的映射闭包中定义排序 属性
static mapping = {
.
.
.
sort 'itemNo': 'asc'
}
现在,每当您查询 TemplateItem 时,默认排序都会在 itemNo 字段上。 所以如果你使用
TemplateItem.findAllByTemplateHeader(templateHeaderInstance)
它将根据项目编号给出排序的模板项目。
通过在 TemplateItem 域中定义排序 属性 将不会对 TemplateHeader 域中的 templateItems 字段进行排序。原因是在获取域对象的关联时,Grails 忽略了该域的排序字段。如果您查看在获取 TemplateHeader 对象及其关联时生成的 sql,您将看到不同之处。
显然没有直接的方法可以实现您想要实现的目标,具体取决于您是想根据模板项对 TemapleHeader 对象进行排序,还是只对单个 TemplateHeader 对象中的模板项进行排序
要根据 TemplateItems 对 TemplateHeader 对象进行排序,请将以下排序 属性 添加到 TemplateHeader 域的映射闭包中:
static mapping = {
.
.
.
sort 'templateItems.itemNo': 'asc'
}
以及何时执行此 GORM
TemplateHeader header = TemplateHeader.list()
它生成以下 sql
select this_.header_id as header_i1_0_1_, this_.ver as ver2_0_1_, .... from template_header this_ inner join template_item templateit1_ on this_.header_id=templateit1_.template_header_header_id and this_.ver=templateit1_.template_header_ver order by templateit1_.item_no asc
现在这个查询的问题是它的执行成本非常高。它在 TemplateHeader 和 TemplateItem 域之间使用内部连接。因此,如果您在 TemplateHeader 域中有 2 条记录,在 TemplateItem 域中有 10 条记录,它将获取 10 条记录,而您只需要 2 条记录。另一个问题是 templateItems 属性 仍将被延迟获取。所以当你做 header.templateItems 时,它会再次查询数据库,结果不会根据 itemNo 排序。 sql 看起来像这样:
select templateit0_.template_header_header_id as template1_0_0_, templateit0_.template_header_ver as template2_0_0_, ... from template_item templateit0_ where templateit0_.template_header_header_id=? and templateit0_.template_header_ver=?
因此,如果您想对 TemplateHeader 对象的 templateItems 进行排序,您可以覆盖 templateItems 的 getter 并在那里对结果进行排序:
Set<TemplateItem> getTemplateItems() {
return templateItems?.sort { item_1, item_2 -> item_1?.itemNo <=> item_2?.itemNo }
}
以防万一在将 TemplateItem 对象添加到 TemplateHeader 对象时遇到这样的错误:
No signature of method: TemplateHeader.addToTemplateItems() is applicable for argument types: (TemplateItem)
然后尝试将 templateItems 声明为列表。