Have you tried to use the Generate model wizard to create entities from your database automatically? It would give you examples of mapping to composite-key entities.
I have a table called ana10 for customer. I implemented it with an entity type BaseStringIdEntity with the key ana1001 of type String, and for the moment with only one field ana1010 description string.
Now I want to implement ana11 table for customer addresses in one-to-many with a composite key without UUID. Trying to create it with Cuba Studio I thought of using BaseGenericIdEntity but could not find this choice.
So I manually implemented in IntelliJ outside Cuba Studio Ana11PK the class for the primary key with annotations @Embeddable and Ana11 class for the entity.
I do not know if I’m doing things well done, but the Ana11 entities that I created in IntelliJ is not editable from Cuba Studio … so … I’m asking for help.
It 'a very important thing because once I found the correct way to implement the classes with composite keys I can start with the actual conversion project (buying the license of course).
I send you the entire modules package zipped so you can understand what I’m trying to do and where I’m wrong.
I continued with my tests and I was able to develop Embeddable class Ana11PK and Ana11 entity class directly in Cuba Studio.
I have included Ana11 entities (addresses) Composition in parent Ana10 entities (customers) as a composition, and created the standard screen, everything seemed ok.
But now I have a runtime error when i open customer, that i can not solve.
I am attaching the current sources, ignore previous.
Thank you.
The exception is the following:
com.haulmont.cuba.core.global.RemoteException:
---
javax.persistence.PersistenceException: Exception [EclipseLink-6015] (Eclipse Persistence Services - 2.6.2.cuba11): org.eclipse.persistence.exceptions.QueryException
Exception Description: Invalid query key [ana1102] in expression.
Query: ReadAllQuery(name="ana11" referenceClass=Ana11 )
FetchGroup(ana11){ana10 => {class java.lang.Object=FetchGroup(ana10){ana1001, ana1010}}, ana1113 => {class java.lang.Object=FetchGroup(ana1113){tgn1301, tgn1310}}, ana1112, ana1111, id, ana1110}
---
org.eclipse.persistence.exceptions.QueryException:
Exception Description: Invalid query key [ana1102] in expression.
Query: ReadAllQuery(name="ana11" referenceClass=Ana11 )
FetchGroup(ana11){ana10 => {class java.lang.Object=FetchGroup(ana10){ana1001, ana1010}}, ana1113 => {class java.lang.Object=FetchGroup(ana1113){tgn1301, tgn1310}}, ana1112, ana1111, id, ana1110}
at com.haulmont.cuba.core.sys.ServiceInterceptor.aroundInvoke(ServiceInterceptor.java:93)
at sun.reflect.GeneratedMethodAccessor112.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:629)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:618)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy182.loadList(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.haulmont.cuba.core.sys.remoting.LocalServiceInvokerImpl.invoke(LocalServiceInvokerImpl.java:95)
at com.haulmont.cuba.web.sys.remoting.LocalServiceProxy$LocalServiceInvocationHandler.invoke(LocalServiceProxy.java:146)
at com.sun.proxy.$Proxy22.loadList(Unknown Source)
at com.haulmont.cuba.client.sys.DataManagerClientImpl.loadList(DataManagerClientImpl.java:52)
at com.haulmont.cuba.gui.data.impl.GenericDataSupplier.loadList(GenericDataSupplier.java:100)
at com.haulmont.cuba.gui.data.impl.CollectionDatasourceImpl.loadData(CollectionDatasourceImpl.java:542)
at com.haulmont.cuba.gui.data.impl.CollectionDatasourceImpl.refresh(CollectionDatasourceImpl.java:148)
at com.haulmont.cuba.gui.data.impl.CollectionDatasourceImpl.refresh(CollectionDatasourceImpl.java:106)
at com.haulmont.cuba.gui.data.impl.CollectionDatasourceImpl.setSuspended(CollectionDatasourceImpl.java:651)
at com.haulmont.cuba.gui.data.impl.DsContextImpl.resumeSuspended(DsContextImpl.java:83)
at com.haulmont.cuba.gui.WindowManager.afterShowWindow(WindowManager.java:968)
at com.haulmont.cuba.web.WebWindowManager.showWindow(WebWindowManager.java:398)
at com.haulmont.cuba.web.WebWindowManager.lambda$showWindow$4(WebWindowManager.java:358)
at com.haulmont.cuba.web.gui.WebWindow.close(WebWindow.java:1144)
at com.haulmont.cuba.web.gui.WebWindow.closeAndRun(WebWindow.java:1032)
at com.haulmont.cuba.gui.components.AbstractWindow.closeAndRun(AbstractWindow.java:289)
at com.haulmont.cuba.web.WebWindowManager.showWindow(WebWindowManager.java:357)
at com.haulmont.cuba.gui.WindowManager.openWindow(WindowManager.java:597)
at com.haulmont.cuba.web.WebWindowManager.openWindow(WebWindowManager.java:137)
at com.haulmont.cuba.gui.config.MenuCommand.execute(MenuCommand.java:100)
at com.haulmont.cuba.web.sys.MenuBuilder$1.menuSelected(MenuBuilder.java:173)
at com.vaadin.ui.MenuBar.changeVariables(MenuBar.java:207)
at com.vaadin.server.communication.ServerRpcHandler.changeVariables(ServerRpcHandler.java:609)
at com.vaadin.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:428)
at com.vaadin.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:274)
at com.vaadin.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:79)
at com.haulmont.cuba.web.sys.CubaVaadinServletService$CubaUidlRequestHandler.lambda$synchronizedHandleRequest$112(CubaVaadinServletService.java:314)
at com.haulmont.cuba.web.sys.CubaVaadinServletService.withUserSession(CubaVaadinServletService.java:196)
at com.haulmont.cuba.web.sys.CubaVaadinServletService$CubaUidlRequestHandler.synchronizedHandleRequest(CubaVaadinServletService.java:314)
at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:41)
at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1424)
at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:369)
at com.haulmont.cuba.web.sys.CubaApplicationServlet.serviceAppRequest(CubaApplicationServlet.java:278)
at com.haulmont.cuba.web.sys.CubaApplicationServlet.service(CubaApplicationServlet.java:187)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at com.haulmont.cuba.web.sys.CubaHttpFilter.handleNotFiltered(CubaHttpFilter.java:108)
at com.haulmont.cuba.web.sys.CubaHttpFilter.doFilter(CubaHttpFilter.java:95)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:528)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1099)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1520)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1476)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
It’s quite hard to find out the problem without ability to open the project in IDE and run it. Could you send us the whole project? You can press Alt+/ in Studio and select zipProject - an archive will be created in the project folder.
I have managed to make the Ana10-Ana11 composition work by doing the following:
In order to create the database, I had to comment out the duplicate ANA1101 varchar(16) field in ERP_ANA11 table. It is mistakenly added to the script by Studio because it doesn’t recognize the @MapsId(“ana1101”) annotation on the entity attribute. We’ll fix it in a nearest future version.
Added equals() and hashCode() methods to the Ana11PK primary key entity:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Ana11PK ana11PK = (Ana11PK) o;
return Objects.equals(ana1101, ana11PK.ana1101) &&
Objects.equals(ana1102, ana11PK.ana1102);
}
@Override
public int hashCode() {
return Objects.hash(ana1101, ana1102);
}
Added a nested datasource and corresponding fields to edit embedded primary key in ana11-edit.xml editor screen:
I applied the changes you made. The program works correctly, the only question I have left is how to put order by ana1102 on the composition inside entity ana10.
I have left a few things to understand, the most important is that unfortunately I will have to see how to work with your framework and an Oracle version 8.1.7 for backward compatibility with the current erp; until now I have worked with mysql to understand the potential of Cuba.
I hope to bring the database used by erp to Oracle version 11 to solve the problem.
Anyway … I really want to thank you, Rostislav, Gleb and all the Cuba team for the help you are giving me. You have created a wonderful java framework, really powerful and I’m sure it’s the right tool to do the conversion of our old erp.
I’m back for another doubt about composite keys. After solving the problem between ana10 ana11 and I try to do the same thing between ven20 and ven21 which are order header and order lines.
For my tests at the beginning I used BaseUuidEntity but unfortunately, as I had already written to you, the Oracle database is filled with composite keys and I can not change this.
Then:
Ven20PK order header is a key composed of three fields: type, year and number
Ven21PK order line is a key composed of Ven20PK plus the line number.
Cuba Studio will not let me define an attribute Ven20PK inside another EmbeddableEntity Ven21PK.
We will probably add support for nested Embeddables to Studio, but it will take time. For now, could you try to create Ven21PK as an independent set of fields, duplicating the ones in Ven20PK?
when you say create ven21PK as an independent set of fields, you mean that after I have to use the @PrimaryKeyColumns annotation on the class?
And Cuba Studio supports these annotations or not … like @MapsId?
I do not have enough experience to find myself the right road and I do not want to go too far out from your standard, because otherwise the road becomes too rough …
So if you say that your standard necessarily involves a UUID instead of composite key I’ll have to add the id fields as I have already done for ven20 and ven21 in my test project.
Please show me what is the best way, according to your experience.
If you can replace composite keys with UUID or Long keys, the further development of your application will be simpler and more straightforward. If you cannot do it because you have to keep compatibility with the legacy system or for some other reason - let us know and we’ll try to investigate this issue with nested composite key.
Thank you for your answer. I managed to build a model that seems to work. The problem I have right now is that when I move from browser to the orders edit order, I have the classic exception of detached entity.
I have no problems to enter the order lines, the problem occurs when I come back to see the rows inserted, it seems that the key entities ven21PK is detached.
The jpa model that I built appears to be correct and the rows are inserted correctly in the database
I will send the project so you can have a look and give me some help,
still a little effort and we should find the right way.
I am sure that together we can fix it and manage composite keys.
Thank you.
This is the exception:
IllegalStateException: Can not get unfetched attribute [ven2123] from detached object it.poloristorazione.erp.entity.Ven21-it.poloristorazione.erp.entity.Ven21PK@4ac0ff8 [detached]