Thursday, June 9, 2011

A shout out to XMarks

I have to give a plug to out to Xmarks (recently acquired by LastPass).  XMarks bookmark sync allows you to synchronize your bookmarks across browsers and computers.  For someone like me I run three browsers on three computers and the ability to synchronize those bookmarks is paramount.  Being in software development I often need to test on different browsers.  I also run into problems with other websites I use that don't work on certain browsers, so for example I generally use Chrome but sometimes need to switch to IE when a site doesn't work on Chrome.  Then I have a work computer and two home computers.  All of this leaves me with nine or more browsers which  I use fairly often.  And in my line of work bookmarks are key to accessing all the information I need.  XMarks is free, but you can signup for a paid version and I encourage you to contribute to help support such a useful tool.  I was not solicited in any way to write this, I just wanted to give credit where credit is due.

Thursday, June 2, 2011

ADF Entity associations with constants

This post discusses two approaches for creating entity object associations when you need to use constants in your relationship query; this can commonly come up when you have a child entity that can have different types of parents. 

Let's start by laying out a simple example where we have a company selling products and services such that we either have an ORDER or a durational CONTRACT.  For some reason we've chosen to model these  entities separately, however in each case we are selling PRODUCTs and we'd like to share a common entity for the product lines.  So an ORDER has PRODUCTs and a CONTRACT has PRODUCTs.  To model this we'll give our PRODUCT entity two attributes:
  • ParentEntityId - the primary key of our parent
  • ParentEntityType - the type of our parent, either 'Order' or 'Contract'
For these I would have created the following EOs in my ADF model project:
  • OrderEO
  • ContractEO
  • ProductEO
And I would like the following associations:
  • OrderEOToProductEO
  • ContractEOToProductEO
How should I build these associations? 

Option 1: Build an EO Association based on ID and modify the generated association query

When you create the association you will choose the relationship between the OrderEO.OrderId and ProductEO.ParentEntityId.  You will then need to manually modify the query expression to add a condition for ParentEntityType.  

The query from source to destination would be: 
(:Bind_OrderId = ProductEO.PARENT_ENTITY_ID) AND ('Order' = ProductEO.PARENT_ENTITY_TYPE)

And from destination to source:
(:Bind_ParentEntityId = OrderEO.ORDER_ID) AND (:Bind_ParentEntityType = 'Order')

The advantage of this approach is that only the EO association is hampered with the details of how these entities are related.  The disadvantage is that you've manually changed the query and if you alter the relationship of these entities in the future (or someone else does), the query may need manual intervention to include this clause for the parent entity code.  

Option 2:  Use a transient attribute on the parent entities

Create a transient attribute in Order and Contract called "ParentEntityType" and set it to be "Derived from SQL Expression".  For OrderEO the attribute will have a value of "Order", and for ContractEO "Contract".  For example (from OrderEO.xml):

  Attribute
    Name="ParentEntityType"
    IsQueriable="false"
    IsPersistent="false"
    ColumnName="none"
    SQLType="VARCHAR"
    Type="java.lang.String"
    ColumnType="VARCHAR2"
    DefaultValue="Order"
    Precision="255"
    Expression="'Order'"

Then when you create your EO assocation you can select both attributes for the relationship.  You select OrderEO.OrderId = ProductEO.ParentEntityId and OrderEO.ParentEntityType = ProductEO.ParentEntityType.  

The query from source to destination would be: 
(:Bind_OrderId = ProductEO.PARENT_ENTITY_ID) AND (:Bind_ParentEntityType = ProductEO.PARENT_ENTITY_TYPE)

And from destination to source:
(:Bind_ParentEntityId = OrderEO.ORDER_ID) AND (:Bind_ParentEntityType = 'Order')

The advantage of this approach is that the query is generated automatically by the framework and any changes you make in the future to the association will auto-generate without manual intervention.  You've also included the constant as an attribute of the EO which could be used across multiple associations/etc. The disadvantage is that you've added an attribute to your EOs to store a constant that is probably only used in this relationship.  And if you don't want these constants in your VOs then you have to manually remove them so they only show up in the EO.

Conclusion

Either way works and I've done both, but I recommend Option 1 as this isolates the association specific logic in the EOAssociation and does not taint your EO/VO with attributes that are just for constants.  Also note that if you can model your relationship with VOs and View Links then this becomes easier because the view link will use a view criteria.