PUBLIC - Liferay Portal Community Edition
  1. PUBLIC - Liferay Portal Community Edition
  2. LPS-11479

ServiceBuilder doesn't support one-to-one relationships out of the box

    Details

    • Type: Bug Bug
    • Status: Verified
    • Resolution: Unresolved
    • Affects Version/s: 6.0.3 GA, 6.0.5 GA, 6.0.6 GA, 6.2.0 CE M4
    • Fix Version/s: None
    • Environment:
      Using Liferay 6.03 with tomcat 6.0.26 bundle. IDE is Eclipse Galileo with Liferay IDE. Liferay plugins SDK 6.0.3. SO Linux, Fedora 13. JDK is java-1.6.0, openjdk-1.6.0.0-41.b18
    • Fix Priority:
      3
    • Similar Issues:
      Show 5 results 

      Description

      Service builder doesn't work as expected when trying to generate a one-to-one relation between two entities defined in the same service.xml file. Consider the next service.xml snip:

      <entity name="Producto" table="productos">
      <column name="id" type="int" primary="true"></column>
      </entity>
      <entity name="Formato" table="formatos">
      <column name="id" type="int" primary="true"></column>
      <column name="producto" type="Producto" entity="Producto" mapping-key="idProducto"></column>
      </entity>
      Then generation fails with the following output:

      [java] Error on line 68, column 33 in com/liferay/portal/tools/servicebuilder/dependencies/model_impl.ftl
      [java] serviceBuilder.getSqlType(packagePath + ".model." + entity.getName(), column.getName(), column.getType()) is undefined.
      [java] It cannot be assigned to sqlType
      [java] The problematic instruction:
      [java] ----------
      [java] ==> assignment: sqlType=serviceBuilder.getSqlType(packagePath + ".model." + entity.getName(), column.getName(), column.getType()) [on line 68, column 33 in com/liferay/portal/tools/servicebuilder/dependencies/model_impl.ftl]
      [java] ----------
      [java] Java backtrace for programmers:
      [java] ----------
      [java] freemarker.core.InvalidReferenceException: Error on line 68, column 33 in com/liferay/portal/tools/servicebuilder/dependencies/model_impl.ftl
      [java] serviceBuilder.getSqlType(packagePath + ".model." + entity.getName(), column.getName(), column.getType()) is undefined.
      [java] It cannot be assigned to sqlType
      [java] at freemarker.core.Assignment.accept(Assignment.java:111)

      The expected behaviour should be having a generated method like getProducto().

      I suspect this can't also be done between entities in different services: http://www.liferay.com/web/guest/community/forums/-/message_boards/message/480294#_19_message_782016, but haven't tried nor found a ticket about this forum post.

        Activity

        Hide
        Jakub Liska added a comment -

        Miguel you should have set at least major priority for this feature/bug Without one-to-one relationship support servicebuilder looks like spider without one leg. Please vote up people.

        Show
        Jakub Liska added a comment - Miguel you should have set at least major priority for this feature/bug Without one-to-one relationship support servicebuilder looks like spider without one leg. Please vote up people.
        Hide
        Tomáš Polešovský added a comment -

        This issue is currently being addressed in Sprint 2 of the 100 PaperCuts program. Please see http://liferay.com/community/100-papercuts

        Show
        Tomáš Polešovský added a comment - This issue is currently being addressed in Sprint 2 of the 100 PaperCuts program. Please see http://liferay.com/community/100-papercuts
        Hide
        Tomáš Polešovský added a comment -

        Hello gyus,

        I'll try to implement the functionality. But I see one limitation. Currently, portal doesn't offer typical ORM object accessors for relations. That means, for many-to-one and many-to-many relations there are no such methods like getDetails() or getMaster() in the MODEL bean. These methods are in the *Persistence class with one argument - primary/foreign key. I'll try to implement it the same way to be consistent with current system.

        I.e:
        1, it will be possible to specify one-to-one relation without exceptions
        2, there will be getProducto(int productoPK) method in the FormatoPersistence class that returns Producto object, but no method formato.getProducto() in the formato model bean.

        I think to be consistent you should create another ticket to enable ServiceBuilder:
        1, to have List<Formato> producto.getFormatos() method in the producto MODEL bean
        2, to have Producto formato.getProducto() method in the formato MODEL bean

        Is it OK?

        – tom

        Show
        Tomáš Polešovský added a comment - Hello gyus, I'll try to implement the functionality. But I see one limitation. Currently, portal doesn't offer typical ORM object accessors for relations. That means, for many-to-one and many-to-many relations there are no such methods like getDetails() or getMaster() in the MODEL bean. These methods are in the *Persistence class with one argument - primary/foreign key. I'll try to implement it the same way to be consistent with current system. I.e: 1, it will be possible to specify one-to-one relation without exceptions 2, there will be getProducto(int productoPK) method in the FormatoPersistence class that returns Producto object, but no method formato.getProducto() in the formato model bean. I think to be consistent you should create another ticket to enable ServiceBuilder: 1, to have List<Formato> producto.getFormatos() method in the producto MODEL bean 2, to have Producto formato.getProducto() method in the formato MODEL bean Is it OK? – tom
        Hide
        Jelmer Kuperus added a comment -

        There was some discussion about this issue in http://www.liferay.com/community/forums/-/message_boards/message/7649123

        As a workaround you can add a getProducto method to FormatoImpl like this

        1public class FormatoImpl {
        2 public Producto getProducto() {
        3 if (idProducto == 0)

        { 4 return null; 5 }

        6 return ProductoLocalServiceUtil.getProducto(idProducto);
        7 }
        8}

        regenerate the service and you are done. It isn't particularly pretty but it seems to be how it is done in the core of Liferay

        Show
        Jelmer Kuperus added a comment - There was some discussion about this issue in http://www.liferay.com/community/forums/-/message_boards/message/7649123 As a workaround you can add a getProducto method to FormatoImpl like this 1public class FormatoImpl { 2 public Producto getProducto() { 3 if (idProducto == 0) { 4 return null; 5 } 6 return ProductoLocalServiceUtil.getProducto(idProducto); 7 } 8} regenerate the service and you are done. It isn't particularly pretty but it seems to be how it is done in the core of Liferay
        Hide
        Tomáš Polešovský added a comment -

        This is nice workaround and I agree with Jelmer that it's up to Liferay core engineers to decide what is the right way.

        Therefore all I can do is to create patch for ServiceBuilder with the workaround above - but I'm not sure whether it's needed now. I'll think a bit about it if it's worth to create small patch that could help adopt it into portal.

        Show
        Tomáš Polešovský added a comment - This is nice workaround and I agree with Jelmer that it's up to Liferay core engineers to decide what is the right way. Therefore all I can do is to create patch for ServiceBuilder with the workaround above - but I'm not sure whether it's needed now. I'll think a bit about it if it's worth to create small patch that could help adopt it into portal.
        Hide
        Cynthia Wilburn (Inactive) added a comment -

        Adding 6.0.6 GA to affected versions. All resolved 6.0.5 issues can be found in the release notes for 6.0.6 GA.

        Show
        Cynthia Wilburn (Inactive) added a comment - Adding 6.0.6 GA to affected versions. All resolved 6.0.5 issues can be found in the release notes for 6.0.6 GA.
        Hide
        Mika Koivisto added a comment -

        The workaround Jelmer describes is the way it should be done. You really want to keep the entities as light weight as possible and not do the kind of relationships that you can do with Hibernate. It gets easily very expensive to retrieve one entity from db when it has a ton of child entities that are also retrieved. Not you can mitigate that by using lazy loading but it introduces a whole another kind of issues.

        Show
        Mika Koivisto added a comment - The workaround Jelmer describes is the way it should be done. You really want to keep the entities as light weight as possible and not do the kind of relationships that you can do with Hibernate. It gets easily very expensive to retrieve one entity from db when it has a ton of child entities that are also retrieved. Not you can mitigate that by using lazy loading but it introduces a whole another kind of issues.
        Hide
        Aniceto P Madrid added a comment -

        Reproducible

        Show
        Aniceto P Madrid added a comment - Reproducible

          People

          • Votes:
            30 Vote for this issue
            Watchers:
            17 Start watching this issue

            Dates

            • Created:
              Updated:
              Days since last comment:
              2 years, 10 weeks, 3 days ago

              Development

                Structure Helper Panel