Announcement Announcement Module
Collapse
No announcement yet.
Searching with data objects instead of values (with Hibernat Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Searching with data objects instead of values (with Hibernat

    Hi,

    Is there a generic way to do searches with an object instead of specifying values as parameters? Here is what I man:

    When searching an object (or objects), instead of specifying an ID or values for attributes, I would like to set an objects properties and do a search for all matching non-null properties.

    For example, instead of

    List findByName(String lastName, String firstName) {
    .
    .
    .
    }

    findByName("Foo", "Bar");

    I would like to do

    Person p = new Person();
    p.setLastName("Foo");
    p.setFirstName("Bar");

    findPersons(p);

    and in both cases, I would get a list of people with the name "Bar Foo".

    The obvious advantage of this approach is that if my object properties change, I don't have to change all my findByName() calls.

    One way we did id was to check all the the properties and to build a (Hibernate) request by adding all the fields that had non-null values. But it's a bit longish and required us to do it manually for each new class.

    I was wondering if there were facilities in Spring to do this?

    Thanks,

    L

  • #2
    try
    Code:
    List list = getHibernateTemplate().findByValueBean(query, person);
    HTH

    Comment


    • #3
      Ah, thanks. Let me take a look at that.

      L

      Comment


      • #4
        I tried this and it doesn't give me the expected result. For example, I have a test that looks like this:

        Code:
        public void testGetTerminalById() {
                _t.setTerminalId(new Integer(9999));
                _t = _dao.getTerminal(_t);
                assertNotNull(_t);
                assertEquals("Default Name", _t.getTerminalName());
                assertEquals(9999, _t.getTerminalId().intValue());
            }
        
            public void testGetTerminalByName() {
                _t.setTerminalName("Default Name");
                _t = _dao.getTerminal(_t);
                assertNotNull(_t);
                assertNotNull(_t.getTerminalId());
                assertEquals(9999, _t.getTerminalId().intValue());
            }
        and the implementation:

        Code:
        public Terminal getTerminal(Terminal terminal) {
                List l = getHibernateTemplate().findByValueBean("from Terminal", terminal);;
                if (HibernateDaoSupportUtils.isUnique(l)) {
                    return (Terminal) l.get(0);
                }
                
                _log.debug("Terminal not unique: " + l);
                return null;
            }
        In both cases, getTerminal returns null because it returns more than one value, even though I know that the values are unique in my table.

        L

        Comment


        • #5
          I am sorry for the confusion. What I meant was to use the following query:
          Code:
          String query = "from Terminal t where (:id is null or t.id = :id) and (:name is null or t.name = :name)";
          List list = getHibernateTemplate().findByValueBean(query, terminal);
          If Terminal class changes, you have to change one line of code.
          I am not, actually, aware of a method in Hibernate that automagically checks a class members and build a query on the fly depending on null/not null values.

          Comment


          • #6
            Originally posted by irbouho
            I am not, actually, aware of a method in Hibernate that automagically checks a class members and build a query on the fly depending on null/not null values.
            Still, there is one. You have the Example criterion which is build on an instance of javabean and you can tune to take in account zero values or not, match string with a like or exactly and you can then add this criterion to a Query to execute it. This may be what you are looking for.

            HTH

            Olivier

            Comment


            • #7
              Originally posted by irbouho
              I am sorry for the confusion. What I meant was to use the following query:
              Code:
              String query = "from Terminal t where (:id is null or t.id = :id) and (:name is null or t.name = :name)";
              List list = getHibernateTemplate().findByValueBean(query, terminal);
              Yes! That works! Thanks!

              L

              Comment


              • #8
                Originally posted by ojolly
                You have the Example criterion which is build on an instance ...
                I took a look at that. I didn't know about it. It may work but if I use it, I have to start handling the checked HibernateException. I didn't dig too deeply since the preceding option worked.

                Thanks for the pointer,

                L

                Comment


                • #9
                  About checked HibernateException, you may want (well, you want) to handle this kind of code inside the execute method of the hibernate template. With this construction by callback, you can safely handle methods returning HibernateException and the wrapping method will convert them to the usual unchecked exceptions.

                  Olivier

                  Comment


                  • #10
                    True. I'll remember that if I need to change my implementation.

                    Thanks,

                    L

                    Comment


                    • #11
                      Can this work wih composite keys also?

                      I have a composite key (generated by middlegen) which generates this fragment:

                      Code:
                          <composite-id name="comp_id" class="data.model.PlanTypePK">
                              <key-property 
                                  name="terminalid" 
                                  column="TERMINALID" 
                                  type="java.lang.Integer"
                                  length="10"
                              />
                              <key-property 
                                  name="planTypeLid" 
                                  column="PLAN_TYPE_LID" 
                                  type="java.lang.Integer"
                                  length="10"
                              />
                              <key-property 
                                  name="planTypeSid" 
                                  column="PLAN_TYPE_SID" 
                                  type="java.lang.Short"
                                  length="5"
                              />
                          </composite-id>
                      as my query string I use:

                      Code:
                      String query = "from PlanType t where &#40;&#58;comp_id.terminalid is null or t.comp_id.terminalid = &#58;comp_id.terminalid&#41; and"
                                      + " &#40;&#58;planTypeName is null or t.planTypeName = &#58;planTypeName&#41;";
                      When I try to do the search, I get this error:

                      Code:
                      org.springframework.orm.hibernate.HibernateQueryException&#58; Not all named parameters have been set&#58; &#91;comp_id.terminalid&#93; &#91;from PlanType t where &#40;&#58;comp_id.terminalid is null or t.comp_id.terminalid = &#58;comp_id.terminalid&#41; and &#40;&#58;planTypeName is null or t.planTypeName = &#58;planTypeName&#41;&#93;;
                      I checked and all values have something in them when the query is executed.

                      L

                      Comment


                      • #12
                        I'm now using a compination of the Example method and a normal HQL approach (if the primary key is valid). It works Ok for now.

                        Comment

                        Working...
                        X