Announcement Announcement Module
Collapse
No announcement yet.
Manual (Non-@GeneratedValue) Entity identifiers are excluded from the create.jspx Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Manual (Non-@GeneratedValue) Entity identifiers are excluded from the create.jspx

    By default Roo excludes the entity @Id fields from the create.jspx and update.jspx views. While expected for the automatically generated identifiers this behavior seems incomplete for the ‘manually’ managed ids (e.g. without @GeneratedValue annotation).

    The following example illustrates the issue:
    1. New entity with string identifier (myId) and single string attribute (firstName)
    Code:
    entity --class ~.domain.Person --identifierField myId --identifierType java.lang.String
    field string --fieldName firstName
    2. From STS move the myId attribute (with the annotations) from the Person_Roo_Entity.aj to the Person.java, add getter/setter for it and remove the @GeneratedValue(..) annotation.
    Roo detects the change and removes the myId from the Person_Roo_Entity.aj

    The myId attribute inside the Person class looks like:
    Code:
        @Id    
        @Column(name = "myId")    
        private String myId;
    3. Create a scaffold controller for the Person:
    Code:
    controller scaffold --entity ~.domain.Person --class ~.web.PersonController
    The result crete/update jspx views include only the 'firstName' attribute and if you try to save the object an exception is thrown due to uninitialized myId field.

    Is there a way to make the controller command aware of the 'manual' semantics of the identifier?

    My Dev Environment:
    --------------------------------------------
    Roo :1.0.1.RELEASE [rev 601]
    STS : 2.3.0.RELEASE [Build Id: 200912171331]
    Java :build 1.6.0_16-b01

  • #2
    Roo manages identifiers for you in the most intuitive way. I am not sure if it is a good ideas to let users manage identifiers themselves as there is obviously a lot of room for uniqueness problems. But I agree in the odd case it might make sense. So the solution is to customize the generated code to fit your needs.

    Another (maybe more elegant solution) is to let Roo manage the identifiers and simply have another field which looks like an id but it is actually not. For example you could make sure that the Roo maintained identifier is given a different name (like 'myId') and then create a field called 'id' which will appear in your forms. Just an idea.

    HTH,
    Stefan

    Comment


    • #3
      Thanks for the ideas Stefan,

      I decided to stick with the "customized views" approach.

      It does not feel natural to have two unique identifiers for the same entity: one as a business key and another as database Id. Actually I used the second approach to generate the views and then "unified" the Ids and disabled controller's automatically maintained views.

      Cheers, Chris

      Comment


      • #4
        It's a very old ORM problem.

        ORM providers tend to recommend identifiers are totally synthetic and have no business meaning, making their display on a UI generally unnecessary. Indeed often great lengths are gone to to hide the ID, as it reveals an internal of the system and allows guessing at how many records there are, manual changing of the identifier to see other records etc.

        On the other hand data architects tend to prefer identifiers have real business meaning. They make everything as immutable as possible and composite primary keys are the norm. Many ORM-like solutions don't handle this or do so with lots of extra hoops (even JPA requires writing custom Serializable identifiers to represent the composite primary key). So more work for a developer, but a better model from a strictly relational perspective (which in some way should be the priority given the database is likely to outlive the application by a few decades anyway and have lots of applications using it).

        Of course in the present era of noSql DBs, identifiers have again switched to having business meaning. That's because noSql DBs often want naturally sorted records so they can tackle range queries and partitioning more effectively, so totally synthetic identifiers are again a problem.

        Then we have offline operation and document databases, which almost always use UUIDs extensively. That's because partitioning is a problem to be managed some other way (eg use a sharding model) and you need to use UUIDs. Of course then we try to do UUIDs in a browser, which is a nightmare of unreliability, so then the server has to give our UUIDs so they have a semblance of proper UUID randomness and form.

        I guess to conclude it's non-trivial and there are many schools of thought. With Roo I just went with sequential identifiers by default as most people are backing to a relational DB. I've often seen a compromise where a surrogate primary key is used and that's the sequence or UUID, but the real primary key remains a composite primary key but JPA is configured to simply treat those as read-only fields. Remember as Roo just uses JPA you are free to write your own identifiers at any time and add them to the .java file, and Roo will recognise this. The web tier is designed to work with numeric keys, though.

        Comment


        • #5
          It's a common problem, indeed.

          In some environments, people in charge of some application business want to assign unique meaningful codes manually and they want the database be aware of not repeating these values.

          It should be elegant to have a hidden numeric identifier, but it comes out two issues:

          1.- Sometimes these persons have direct knowledge of the underlying existing technology (database tables, for instance) and want to take the decisions (regardless the lack of their technical knowledge)

          2.- Sometimes, and this is the most common situation, the underlying database already exists when you come to develop a Java application. And there is no way (nor intention) to fix the absence of numerical identifiers.

          So, is it possible to tell Roo that we don't want it manages the identifiers? My request include the generated test files, because I need to avoid this kind of asserts in the code:

          org.junit.Assert.assertNull("Expected 'TableExample' identifier to be null", obj.getCode());

          (See public void testPersist() within the XXXTest_Roo_IntegrationTest class file)


          If you create a JIRA ticket, I will vote for it.

          Comment


          • #6
            Originally posted by jbbarquero View Post
            So, is it possible to tell Roo that we don't want it manages the identifiers? My request include the generated test files, because I need to avoid this kind of asserts in the code:

            org.junit.Assert.assertNull("Expected 'TableExample' identifier to be null", obj.getCode());

            (See public void testPersist() within the XXXTest_Roo_IntegrationTest class file)
            When we have non-Roo managed Id or non-integral type Id like String, the integration tests generated are all failing. With most of the entities with such id Roo support for test generation becomes use less.
            Can this feature be added to test generation?

            Comment


            • #7
              You can stop Roo from generating an identifier by providing your own @Id field with associated accessor and mutator in the entity's .java file. Note that automated integration testing is only designed to automatically test mainstream entities with sequence-based keys. You can always delete (or never create) the integration test and data on demand .java files for entities that do comply with this requirement and write them by hand if you'd still like tests for that entity.

              Comment


              • #8
                After doing what Ben has said, you can use Roo with all its features, as well.

                Let Roo creates the integration tests and you copy from the .aj files to the .java files all the test methods that you want to manage manually.

                Automatically, Roo will delete these methods from the .aj files, and you can safely modify them according your needs without Roo interfering

                For instance, you can provide a rando or fixed ID to the JPA object (just before the assert id is null)

                Code:
                        org.junit.Assert.assertNull("Expected 'TableExample' identifier to be null", obj.getCode());
                
                //Try here:
                obj.getSode("Test_code");
                
                        obj.persist();
                //...
                It worked for us.
                Last edited by jbbarquero; May 28th, 2010, 07:47 AM.

                Comment


                • #9
                  Please Ben, could you take in mind that the problem still remains?

                  We can modify the jspx files, but since Roo is aware of them, it deletes all the changes that we make.

                  Are you going to consider this in Roo? If not, I will create a JIRA Ticket for studying this issue.

                  Regards.

                  Comment


                  • #10
                    Maintaining jspx changes

                    Originally posted by jbbarquero View Post
                    We can modify the jspx files, but since Roo is aware of them, it deletes all the changes that we make.
                    Regards.
                    I tried the way of modifying the jspx file, and in order to maintain my changes in the jspx file, just need to change the respective Controller @RooWebScaffold automaticallyMaintainView entry from default value of "true" to "false".

                    However the downside is any future changes in the jspx need to be manually maintained.

                    Comment

                    Working...
                    X