I am using Wicket, Spring, and Hibernate. I am trying to build a sortable grid using org.apache.wicket.markup.repeater.data.DataView and org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider involving data from multiple tables with one-to-many relationships. However, some (Wicket) OrderByBorder components that passes property from related tables to the
Criteria.addOrder() method does not work as expected. I must have done something wrong or insufficient. Please take a look at the following code and help me solve the issue. Thanks!
I have the following domain classes (mapping to relational tables from a MySQL database)
CloudResource.javaCode:
package wicket.in.action.WicketGui.domain;
import javax.persistence.*;
@Entity
@Table(name = "cloudResource")
public class CloudResource implements DomainObject {
@Id
@GeneratedValue
private Long id;
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
@ManyToOne
@JoinColumn(name = "accountId")
private Account account;
public Account getAccount() {
return this.account;
}
public void setAccount(Account account) {
this.account = account;
}
@Column(name = "resourceId")
private String resourceId;
public String getResourceId() {
return this.resourceId;
}
public void setResourceId(String resourceId) {
this.resourceId = resourceId;
}
@ManyToOne
@JoinColumn(name = "regionId")
private Region region;
public Region getRegion() {
return this.region;
}
public void setRegion(Region region) {
this.region = region;
}
@Column(name = "type")
private String type;
public String getType() {
return this.type;
}
public void setType(String type) {
this.type = type;
}
@Column(name = "status")
private String status;
public String getStatus() {
return this.status;
}
public void setStatus(String status) {
this.status = status;
}
@Column(name = "platform")
private String platform;
public String getPlatform() {
return this.platform;
}
public void setPlatform(String platform) {
this.platform = platform;
}
@Column(name = "comment")
private String comment;
public String getComment() {
return this.comment;
}
public void setComment(String comment) {
this.comment = comment;
}
@ManyToOne
@JoinColumn(name = "personalGroupId")
private PersonalGroup personalGroup;
public PersonalGroup getPersonalGroup() {
return this.personalGroup;
}
public void setPersonalGroup(PersonalGroup personalGroup) {
this.personalGroup = personalGroup;
}
public CloudResource() {
}
public CloudResource(Account account, String resourceId, Region region, String type,
String status, String platform, String comment, PersonalGroup personalGroup) {
this.account = account;
this.resourceId = resourceId;
this.region = region;
this.type = type;
this.status = status;
this.platform = platform;
this.comment = comment;
this.personalGroup = personalGroup;
}
@Override
public String toString() {
return "CloudResource[" + this.id + "]";
}
}
Account.javaCode:
package wicket.in.action.WicketGui.domain;
import javax.persistence.*;
import java.util.List;
@Entity
@Table(name = "account")
public class Account implements DomainObject {
@Id
@GeneratedValue
private Long id;
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
@ManyToOne
@JoinColumn(name = "cloudProviderId")
private CloudProvider cloudProvider;
public CloudProvider getCloudProvider() {
return this.cloudProvider;
}
public void setCloudProvider(CloudProvider cloudProviderId) {
this.cloudProvider = cloudProvider;
}
@ManyToOne
@JoinColumn(name = "userId")
private User user;
public User getUser() {
return this.user;
}
public void setUser(User user) {
this.user = user;
}
@Column(name = "accessKeyId")
private String accessKeyId;
public String getAccessKeyId() {
return this.accessKeyId;
}
public void setAccessKeyId(String accessKeyId) {
this.accessKeyId = accessKeyId;
}
@Column(name = "secretAccessKey")
private String secretAccessKey;
public String getSecretAccessKey() {
return this.secretAccessKey;
}
public void setSecretAccessKey(String secretAccessKey) {
this.secretAccessKey = secretAccessKey;
}
@OneToMany(mappedBy = "account")
private List<CloudResource> cloudResources;
public List<CloudResource> getCloudResources() {
return this.cloudResources;
}
public void setCloudResources(List<CloudResource> cloudResources) {
this.cloudResources = cloudResources;
}
public Account() {
}
public Account(CloudProvider CloudProvider, User user, String accessKeyId, String secretAccessKey) {
this.cloudProvider = cloudProvider;
this.user = user;
this.accessKeyId = accessKeyId;
this.secretAccessKey = secretAccessKey;
}
@Override
public String toString() {
return "Account[" + this.id + "]";
}
}
Account.javaCode:
package wicket.in.action.WicketGui.domain;
import javax.persistence.*;
import java.util.List;
@Entity
@Table(name = "cloudProvider")
public class CloudProvider implements DomainObject {
@Id
@GeneratedValue
private Long id;
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
@Column(name = "name")
private String name;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
@OneToMany(mappedBy = "cloudProvider")
private List<Account> accounts;
public List<Account> getAccounts() {
return this.accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
@OneToMany(mappedBy = "cloudProvider")
private List<Region> regions;
public List<Region> getRegions() {
return this.regions;
}
public void setRegions(List<Region> regions) {
this.regions = regions;
}
public CloudProvider() {
}
public CloudProvider(String name) {
this.name = name;
}
@Override
public String toString() {
return "CloudProvider[" + this.id + "]";
}
}
The following data access class returns list of CloudResource using org.hibernate.Criteria.
CloudResourceDaoImpl.javaCode:
package wicket.in.action.WicketGui.dao.hibernate;
import org.hibernate.Criteria;
import org.hibernate.criterion.Order;
import wicket.in.action.WicketGui.dao.CloudResourceDao;
import wicket.in.action.WicketGui.domain.CloudResource;
import java.util.List;
public class CloudResourceDaoImpl extends AbstractHibernateDaoImpl<CloudResource> implements CloudResourceDao {
public CloudResourceDaoImpl() {
super(CloudResource.class);
}
public List<CloudResource> findAllCloudResources(int first, int count, String sortProperty, boolean sortAsc) {
Criteria criteria = getSession().createCriteria(CloudResource.class)
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! The following line does not work sometimes !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
.addOrder(sortAsc ? Order.asc(sortProperty) : Order.desc(sortProperty))
.setFirstResult(first)
.setMaxResults(count);
return (List<CloudResource>) criteria.list();
}
public int findAllCloudResourcesCount() {
return getSession().createCriteria(CloudResource.class).list().size();
}
}
Criteria.addOrder("type"), Criteria.addOrder("account"), and Criteria.addOrder("account.id") all work. However, the following exception was thrown when I tried to use Criteria.addOrder("account.secretAccessKey").
Quote:
WicketMessage: Error attaching this container for rendering: [Page class = wicket.in.action.WicketGui.Index, id = 2, version = 1, ajax = 0]
Root cause:
org.hibernate.QueryException: could not resolve property: account.secretAccessKey of: wicket.in.action.WicketGui.domain.CloudResource
at org.hibernate.persister.entity.AbstractPropertyMapping.throwPropertyException(AbstractPropertyMapping.java:43)
at org.hibernate.persister.entity.AbstractPropertyMapping.toColumns(AbstractPropertyMapping.java:63)
at org.hibernate.persister.entity.BasicEntityPropertyMapping.toColumns(BasicEntityPropertyMapping.java:31)
at org.hibernate.persister.entity.AbstractEntityPersister.toColumns(AbstractEntityPersister.java:1304)
at org.hibernate.loader.criteria.CriteriaQueryTranslator.getColumns(CriteriaQueryTranslator.java:434)
at org.hibernate.loader.criteria.CriteriaQueryTranslator.getColumnsUsingProjection(CriteriaQueryTranslator.java:394)
at org.hibernate.criterion.Order.toSqlString(Order.java:45)
at org.hibernate.loader.criteria.CriteriaQueryTranslator.getOrderBy(CriteriaQueryTranslator.java:348)
at org.hibernate.loader.criteria.CriteriaJoinWalker.<init>(CriteriaJoinWalker.java:82)
at org.hibernate.loader.criteria.CriteriaLoader.<init>(CriteriaLoader.java:68)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1550)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:283)
at wicket.in.action.WicketGui.dao.hibernate.CloudResourceDaoImpl.findAllCloudResources(CloudResourceDaoImpl.java:22)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:318)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:198)
at $Proxy19.findAllCloudResources(Unknown Source)
at wicket.in.action.WicketGui.services.ResourcesServiceImpl.findAllCloudResources(ResourcesServiceImpl.java:108)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.wicket.proxy.LazyInitProxyFactory$JdkHandler.invoke(LazyInitProxyFactory.java:416)
at org.apache.wicket.proxy.$Proxy21.findAllCloudResources(Unknown Source)
at wicket.in.action.WicketGui.CloudResourcesSortableDataProvider.iterator(CloudResourcesSortableDataProvider.java:61)
at org.apache.wicket.markup.repeater.data.DataViewBase$ModelIterator.<init>(DataViewBase.java:103)
at org.apache.wicket.markup.repeater.data.DataViewBase.getItemModels(DataViewBase.java:75)
at org.apache.wicket.markup.repeater.AbstractPageableView.getItemModels(AbstractPageableView.java:99)
at org.apache.wicket.markup.repeater.RefreshingView.onPopulate(RefreshingView.java:104)
at org.apache.wicket.markup.repeater.AbstractRepeater.onBeforeRender(AbstractRepeater.java:127)
at org.apache.wicket.markup.repeater.AbstractPageableView.onBeforeRender(AbstractPageableView.java:109)
at org.apache.wicket.Component.internalBeforeRender(Component.java:995)
at org.apache.wicket.Component.beforeRender(Component.java:1027)
at org.apache.wicket.MarkupContainer.onBeforeRenderChildren(MarkupContainer.java:1513)
at org.apache.wicket.Component.onBeforeRender(Component.java:3657)
at org.apache.wicket.Page.onBeforeRender(Page.java:1402)
at org.apache.wicket.Component.internalBeforeRender(Component.java:995)
at org.apache.wicket.Component.beforeRender(Component.java:1027)
at org.apache.wicket.Component.prepareForRender(Component.java:2139)
at org.apache.wicket.Page.renderPage(Page.java:870)
at org.apache.wicket.protocol.http.WebRequestCycle.redirectTo(WebRequestCycle.java:164)
at org.apache.wicket.request.target.component.PageRequestTarget.respond(PageRequestTarget.java:58)
at org.apache.wicket.request.AbstractRequestCycleProcessor.respond(AbstractRequestCycleProcessor.java:103)
at org.apache.wicket.RequestCycle.processEventsAndRespond(RequestCycle.java:1172)
at org.apache.wicket.RequestCycle.step(RequestCycle.java:1241)
at org.apache.wicket.RequestCycle.steps(RequestCycle.java:1316)
at org.apache.wicket.RequestCycle.request(RequestCycle.java:493)
at org.apache.wicket.protocol.http.WicketFilter.doGet(WicketFilter.java:354)
at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:194)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:174)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:77)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:726)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:324)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:505)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:829)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:514)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:380)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:395)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:488)
Complete stack:
org.apache.wicket.WicketRuntimeException: Error attaching this container for rendering: [Page class = wicket.in.action.WicketGui.Index, id = 2, version = 1, ajax = 0]
at org.apache.wicket.MarkupContainer.onBeforeRenderChildren(MarkupContainer.java:1525)
at org.apache.wicket.Component.onBeforeRender(Component.java:3657)
at org.apache.wicket.Page.onBeforeRender(Page.java:1402)
at org.apache.wicket.Component.internalBeforeRender(Component.java:995)
at org.apache.wicket.Component.beforeRender(Component.java:1027)
at org.apache.wicket.Component.prepareForRender(Component.java:2139)
at org.apache.wicket.Page.renderPage(Page.java:870)
at org.apache.wicket.protocol.http.WebRequestCycle.redirectTo(WebRequestCycle.java:164)
at org.apache.wicket.request.target.component.PageRequestTarget.respond(PageRequestTarget.java:58)
at org.apache.wicket.request.AbstractRequestCycleProcessor.respond(AbstractRequestCycleProcessor.java:103)
at org.apache.wicket.RequestCycle.processEventsAndRespond(RequestCycle.java:1172)
at org.apache.wicket.RequestCycle.step(RequestCycle.java:1241)
at org.apache.wicket.RequestCycle.steps(RequestCycle.java:1316)
at org.apache.wicket.RequestCycle.request(RequestCycle.java:493)
at org.apache.wicket.protocol.http.WicketFilter.doGet(WicketFilter.java:354)