Data manipulation from service for deep composition

I have deep composition Entities as following that I want to populate programmatically from service called from another UI but it is not working. I must have been making mistake somewhere.

Deep composition Entities:
DemandPlan
DemandPlanLine
DemandPlanDetail

I also have two other Entities i.e. Material and DemandPerspective.

When I run the UI DemandPerspective, there are some data initialized. It is initialized from TestService which is called from DemandPerspective Interface.

Where am I making the mistake and is there any better approach I should follow?
I have prepared a sample app which attached. To test it, go to Application > Demand Perspective.
After you have initialized you will see 3 records in demand perspective created. if you need to repeat, just delete it and display again. After you see 3 records here, go to Demand Plan, see if there is any record created, if not here is the problem,

test-datamanipulation.zip (497.6 KB)

Here is the service I am calling:

 public void initDemandPerspectiveData() {
    try (Transaction tx = persistence.createTransaction()) {

        EntityManager em = persistence.getEntityManager();
        DemandPerspective perspective = metadata.create(DemandPerspective.class);
        perspective.setName("Adjustments");
        em.persist(perspective);

        updateDemandTable(em, perspective);

        DemandPerspective perspective2 = metadata.create(DemandPerspective.class);
        perspective2.setName("Statistical Forecast");
        em.persist(perspective2);

        updateDemandTable(em, perspective2);

        DemandPerspective perspective3 = metadata.create(DemandPerspective.class);
        perspective3.setName("Demand Plan");
        em.persist(perspective3);

        updateDemandTable(em, perspective3);

        tx.commit();
    }
}


private void updateDemandTable(EntityManager em, DemandPerspective demandPerspective) {
    demandPerspective = em.merge(demandPerspective);

    TypedQuery<DemandPlan> demandPlanTypedQuery = em.createQuery(
            "select e from testdatamanipulation$DemandPlan e join e.demandPlanLine l " +
                    "where l.demandPerspective.id = ?1", DemandPlan.class);
    demandPlanTypedQuery.setParameter(1, demandPerspective.getId());
    //           .setViewName("demandPlan-view");

    List<DemandPlan> demandPlanList = demandPlanTypedQuery.getResultList();

    if(demandPlanList ==null){

        LoadContext<Material> loadContext = new LoadContext<>(Material.class);
        loadContext.setView("material-view");
        loadContext.setQueryString("select e from testdatamanipulation$Material e where e.demandForecastRelevant = :relevant")
                .setParameter("relevant", true);
        List<Material> materialList = dataManager.loadList(loadContext);

        for (Material material1 : materialList) {

            //1 Header Entity
            DemandPlan demandPlan = metadata.create(DemandPlan.class);
            demandPlan.setMaterial(material1);
            demandPlan.setDemandPlanLine(new ArrayList<>());

            //2. update DemandPlanLine (Assumed 1 line per header
            DemandPlanLine line = metadata.create(DemandPlanLine.class);
            line.setDemandPerspective(demandPerspective);
            line.setQuantityPd1(BigDecimal.ZERO);
            line.setQuantityPd2(BigDecimal.ZERO);
            line.setQuantityPd3(BigDecimal.ZERO);
            line.setQuantityPd4(BigDecimal.ZERO);

            line.setDemandPlan(demandPlan);
            demandPlan.getDemandPlanLine().add(line);

            //3. 2nd composition
            line.setDemandPlanDetail(new ArrayList<>());

            int pd = 1;
            Date periodDate = new Date();
            Date demandPlanPeriodZeroDate = timeSource.currentTimestamp();
            for (int i = 0; i < 24; i++) {
                DemandPlanDetail detail = metadata.create(DemandPlanDetail.class);
                detail.setQuantity(BigDecimal.ZERO);
                detail.setOrdinalPosition(pd);
                periodDate = DateUtils.addMonths(demandPlanPeriodZeroDate, pd);
                detail.setDemandDate(periodDate);
                line.getDemandPlanDetail().add(detail);

                pd++;

            }


            //---

            em.persist(demandPlan);
        }
    }

}

Hi Mortoza,

In updateDemandTable() method, demandPlanList variable is never null, it’s empty. So you should test it like this:

if (demandPlanList.isEmpty()) {
// ...

Thank you Konstantin. You’re the best.

Hi Konstantin
I am now getting the following error, when I run the service.

java.lang.IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST: com.company.testdatamanipulation.entity.DemandPlanLine-c99796ea-35ee-0ea9-c2e6-a76597fdc979 [new].
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.discoverUnregisteredNewObjects(RepeatableWriteUnitOfWork.java:313)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.calculateChanges(UnitOfWorkImpl.java:728)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1521)
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork(RepeatableWriteUnitOfWork.java:278)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:1174)
at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:134)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730)
at com.haulmont.cuba.core.sys.TransactionImpl.commit(TransactionImpl.java:98)
at com.company.testdatamanipulation.service.TestServiceBean.initDemandPerspectiveData(TestServiceBean.java:55)
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:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85)
at com.haulmont.cuba.core.sys.ServiceInterceptor.aroundInvoke(ServiceInterceptor.java:117)
at sun.reflect.GeneratedMethodAccessor122.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
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.$Proxy254.initDemandPerspectiveData(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:498)
at com.haulmont.cuba.core.sys.remoting.LocalServiceInvokerImpl.invoke(LocalServiceInvokerImpl.java:94)
at com.haulmont.cuba.web.sys.remoting.LocalServiceProxy$LocalServiceInvocationHandler.invoke(LocalServiceProxy.java:148)
at com.sun.proxy.$Proxy58.initDemandPerspectiveData(Unknown Source)
at com.company.testdatamanipulation.web.demandperspective.DemandPerspectiveBrowse.ready(DemandPerspectiveBrowse.java:22)
at com.haulmont.cuba.gui.WindowManager.afterShowWindow(WindowManager.java:1114)
at com.haulmont.cuba.web.WebWindowManager.showWindow(WebWindowManager.java:407)
at com.haulmont.cuba.gui.WindowManager.openWindow(WindowManager.java:708)
at com.haulmont.cuba.web.WebWindowManager.openWindow(WebWindowManager.java:144)
at com.haulmont.cuba.gui.config.MenuCommand$ScreenCommand.run(MenuCommand.java:181)
at com.haulmont.cuba.gui.config.MenuCommand.execute(MenuCommand.java:76)
at com.haulmont.cuba.web.sys.MenuBuilder.lambda$createMenuBarCommand$0(MenuBuilder.java:176)
at com.haulmont.cuba.web.gui.components.mainwindow.WebAppMenu$MenuItemImpl.lambda$setCommand$2434f46b$1(WebAppMenu.java:338)
at com.vaadin.ui.MenuBar.changeVariables(MenuBar.java:212)
at com.vaadin.server.communication.ServerRpcHandler.changeVariables(ServerRpcHandler.java:623)
at com.vaadin.server.communication.ServerRpcHandler.handleInvocation(ServerRpcHandler.java:470)
at com.vaadin.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:413)
at com.vaadin.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:274)
at com.vaadin.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:90)
at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:41)
at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1436)
at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:361)
at com.haulmont.cuba.web.sys.CubaApplicationServlet.serviceAppRequest(CubaApplicationServlet.java:301)
at com.haulmont.cuba.web.sys.CubaApplicationServlet.service(CubaApplicationServlet.java:192)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
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:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
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)

You should persist each instance of DemandPlanDetail:

for (int i = 0; i < 24; i++) {
    DemandPlanDetail detail = metadata.create(DemandPlanDetail.class);
    // ...
    em.persist(detail);    
    // ...
}

Hi Konstantin
Thank you.
Here is the final code:

  for (Material material1 : materialList) {

            //1 Header Entity
            DemandPlan demandPlan = metadata.create(DemandPlan.class);
            demandPlan.setMaterial(material1);
            demandPlan.setDemandPlanLine(new ArrayList<>());

            //2. update DemandPlanLine (Assumed 1 line per header
            DemandPlanLine line = metadata.create(DemandPlanLine.class);
            line.setDemandPerspective(demandPerspective);
            line.setQuantityPd1(BigDecimal.ZERO);
            line.setQuantityPd2(BigDecimal.ZERO);
            line.setQuantityPd3(BigDecimal.ZERO);
            line.setQuantityPd4(BigDecimal.ZERO);

            line.setDemandPlan(demandPlan);
            demandPlan.getDemandPlanLine().add(line);

            //3. 2nd composition
            line.setDemandPlanDetail(new ArrayList<>());

            int pd = 1;
            Date periodDate = new Date();
            Date demandPlanPeriodZeroDate = timeSource.currentTimestamp();
            for (int i = 0; i < 24; i++) {
                DemandPlanDetail detail = metadata.create(DemandPlanDetail.class);
                detail.setQuantity(BigDecimal.ZERO);
                detail.setOrdinalPosition(pd);
                periodDate = DateUtils.addMonths(demandPlanPeriodZeroDate, pd);
                detail.setDemandDate(periodDate);
                line.getDemandPlanDetail().add(detail);
                em.persist(detail);
                pd++;

            }
            em.persist(line);
            em.persist(demandPlan);
        }

    }

Hi Konatantin,
Further to the above, I am trying another similar solution but there might be something I am missing.
This is related to Loading and manipulating data in Edit screen.

I have 2 composition levels as follows:

BudgetFinancial : (Composition) --> BudgetFinancialLine (Composition)–> BudgetFinancialLineDetail

//Approach 1
//==============

BudgetFinancialLine line = metadata.create(BudgetFinancialLine.class);
                       line.setAccount(account);
                    line.setCostCentre(costCentre);
                   line.setBudgetFinancialLineDetail(new ArrayList<>());

                    for (FinancialPeriod period : getItem().getFinancialYear().getFinancialPeriod()) {
                        BudgetFinancialLineDetail detail = metadata.create(BudgetFinancialLineDetail.class);
                        detail.setFinancialPeriod(period);
                        detail.setAmount(BigDecimal.ZERO);
                        detail.setBudgetFinancialLine(line);
                        line.getBudgetFinancialLineDetail().add(detail);
                    }
                    line.setAmount(BigDecimal.ZERO);
                    line.setBudgetFinancial(getItem());
                    budgetFinancialLineDs.addItem(line);

I get the following exception when I try to save it:

IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST: com.company.erp.entity.acct.BudgetFinancialLineDetail-01937887-e0ee-7cea-1d35-7c277f6aa59a [new].

Then I did try as follows:

` //Approach 2
//===============

BudgetFinancialLine line = metadata.create(BudgetFinancialLine.class);
                    line.setAccount(account);
                    line.setCostCentre(costCentre);
                    List<BudgetFinancialLineDetail> lineDetailList = new ArrayList<>();
                    for (FinancialPeriod period : getItem().getFinancialYear().getFinancialPeriod()) {
                        BudgetFinancialLineDetail detail = metadata.create(BudgetFinancialLineDetail.class);
                        detail.setFinancialPeriod(period);
                        detail.setAmount(BigDecimal.ZERO);
                        detail.setBudgetFinancialLine(line);
                        lineDetailList.add(detail);
                    }
                    line.setAmount(BigDecimal.ZERO);
                    line.setBudgetFinancialLineDetail(lineDetailList);
                    line.setBudgetFinancial(getItem());
                    budgetFinancialLineDs.addItem(line);

This approach is also returning the same result. Could you please give some clue?

Hi Mortoza,

You create instances of BudgetFinancialLineDetail and add them to collection in another entity, but you should also send these new instances to the middleware separately together with BudgetFinancialLine. It will be done automatically if you add them to a collection datasource defined in the screen.

1 Like

Thanks Konatantin. It worked.
Here is my final code:

for (CostCentre costCentre : account.getCostCentre()) {

                    BudgetFinancialLine line = metadata.create(BudgetFinancialLine.class);
                    lineList.add(line);
                    line.setAccount(account);
                    line.setCostCentre(costCentre);

                    for (FinancialPeriod period : getItem().getFinancialYear().getFinancialPeriod()) {
                        BudgetFinancialLineDetail detail = metadata.create(BudgetFinancialLineDetail.class);
                        detail.setFinancialPeriod(period);
                        detail.setAmount(BigDecimal.ZERO);
                        detail.setActualLy(BigDecimal.ZERO);
                        detail.setBudgetFinancialLine(line);
                        lineDetailList.add(detail);

                    }
                    line.setBudgetFinancialLineDetail(lineDetailList);

                    line.setActualLy(BigDecimal.ZERO);
                    line.setAmount(BigDecimal.ZERO);
                    line.setBudgetFinancial(getItem());
                    budgetFinancialLineDs.addItem(line);

                    getItem().setBudgetFinancialLine(lineList);
                }
2 Likes