Inject values into entity using hints

Sometimes an entity contains a property that is not mapped to a simple column, but instead holds some value fetched from another (joined) table or a value generated by query. For example, such property can holds some count or the result of some math operation, or value from other table.

We will use example where property SentMessage.content should be populated with value of Message.ctx (string value). Here is the T-SQL query that joins two tables and selects everything what is needed:

    select $C{sm.*}, $C{msg.ctx} from $T{SentMessage sm}
    join ($T{Message msg}) on ($$sm.refId) where ...

Since msg.ctx string is not part of SentMessage, we can only call DbOomQuery#list(SentMessage.class, String.class) to receive data. But, this would be painful! The returned result for above T-SQL query is List<Object[]>, and in order to populate each SentMessage.content we would need to:

  1. create a new List<SentMessage>.
  2. iterate returned list of Object[].
  3. for each list element, cast array elements to SentMessage and String.
  4. manually set property content of iterated SentMessage instance with string value.
  5. add such prepared SentMessage to the new list.

Not only that it is unnecessary complicated, but also some additional memory is allocated to hold both lists in the same time.

Using hints

Fortunately, DbOom framework comes with hints;) As explained elsewhere, hints can be used to instruct how returned values should be injected one into another.

So what would be the injection hint in our example? Its easy: for each row, please inject msg.ctx into sm.content. In the other words, we can say the following: map first columns of returned result into sm (SentMessage) and the last column put into sm.content.

Here is how to specify this hint in Java:

    DbOomQuery q = query(sql(
            "select $C{sm.*}, $C{msg.ctx} as content from $T{SentMessage sm} " +
            "join ($T{Message msg}) on ($$sm.refId) where..."));
    // set parameters
    List<SentMessage> list =
        q.withHints("sm", "sm.content").
            list(SentMessage.class, String.class);

And that is all! Here is how to read this in English: each record from resultset map into SentMessage and String, and name the first instance as "sm", while the second value, the string value, inject into SentMessage instance.

There is just one caveat - column name (specified with 'AS' keyword) must match the property name.

Also note that returned value is List<SentMessage>, where each SentMessage has populated content property; so everything is ready for you :)

See relations & hints for more details.