Preventing traversal of a container reference

Hi all,

I have a question regarding mapping an arrangement of classes whereby multiple container classes (Car and Motorcycle, in this case) have a containment relationship to a common class (Engine).

So, in my example scenario, I have three classes, Car, Motorcycle and Engine. Cars and Motorcycles have Engines.

  --------------             --------------
  |    Car     |             | Motorcycle |
  --------------             --------------
             /\                /\
             \/                \/
             |                 |
 engine 0..1 |                 | engine 0..1
           -----------------------
           |       Engine        |
           -----------------------

Car and Motorcycle each have a one-to-one mapping to engine:

<class name="CarImpl" entity-name="Car" ... >
...
  <one-to-one name="engine" entity-name="Engine" cascade="all" lazy="false" property-ref="oppCarengine"/>
</class>
<class name="MotorcycleImpl" entity-name="Motorcycle" ... >
...
  <one-to-one name="engine" entity-name="Engine" cascade="all" lazy="false" property-ref="oppMotorcycleengine"/>
</class>

I should mention that I didn’t create the mapping myself, rather it was produced by Teneo, based on an EMF model. We need the corresponding database schema to have child-to-parent foreign key links (i.e. a column in the Engine table referring to the containing Car - and the same for Motorcycle), rather than Car and Motorcycle each having a column referring to Engine, and achieved this in EMF by defining properties on Engine to serve as ‘opposites’ for Car.engine and Motorcycle.engine.

This results in the following being included in the mapping for Engine:

<class name="EngineImpl" entity-name="Engine" ... >
  <many-to-one name="oppCarengine" entity-name="com.example.bdp2.Car" not-null="false" lazy="false" insert="true" update="true">
    <column not-null="false" unique="false" name="`CAR_ENGINE_XXXID`" index="IDX_1_BDP2_DB98D6580D42CF183D8"/>
  </many-to-one>
  <many-to-one name="oppMotorcycleengine" entity-name="com.example.bdp2.Motorcycle" not-null="false" lazy="false" insert="true" update="true">
    <column not-null="false" unique="false" name="`MOTORCYCLE_ENGINE_XXXID`" index="IDX_1_BDP2_8065F71421D40FB031C"/>
  </many-to-one>
</class>

This works fine, but the problem is that the SQL to fetch a Car is needlessly traversing the reference from Engine to Motorcycle, which is obviously unnecessary, given that a single engine can only be contained within either a Car OR a Motorcycle, but not both, given that they are containment relationships.

i.e.

SELECT this_.[xxx_id]                     AS XXX1_904_2_,
       this_.[xxx_version]                AS XXX3_904_2_,
       this_.[id]                         AS ID4_904_2_,
       engine2_.[xxx_id]                  AS XXX1_905_0_,
       engine2_.[capacity]                AS CAPACITY3_905_0_,
       engine2_.[car_engine_xxxid]        AS CAR5_905_0_,
       engine2_.[motorcycle_engine_xxxid] AS MOTORCYCLE6_905_0_,
       motorcycle3_.[xxx_id]              AS XXX1_906_1_,
       motorcycle3_.[xxx_version]         AS XXX3_906_1_,
       motorcycle3_.[id]                  AS ID4_906_1_
FROM   [car] this_
       LEFT OUTER JOIN [engine] engine2_
                    ON this_.[xxx_id] = engine2_.[car_engine_xxxid]
       LEFT OUTER JOIN [motorcycle] motorcycle3_
                    ON engine2_.[motorcycle_engine_xxxid] =
                       motorcycle3_.[xxx_id]
WHERE  this_.[xxx_id] IN ( ? )  

In reality, what I’ve shown is a dramatic simplification of my model. There are several other classes also containing Engines, which in turn are part of a bigger model with other patterns of classes like Engine having multiple containers. This is resulting in a crazy number of joins which is hitting performance.

Rather that getting bogged down in why my mapping looks like it does (as I said, it’s auto-generated by Teneo/EMF), I’m interested in any advice as to how I can define it differently so that Hibernate understands that, when fetching a Car, there is no sense in following the many-to-one from Engine to Motorcycle. Once I understand that, I may be able to work around the default behaviour of Teneo to get it mapped the right way.

Many thanks in advance for any help!

Cheers,
Ben.