Search code examples
apache-cayenne

Data lost during SelectQuery


Example: s I've got an object a of the class A in relationship with objects b, c and d.
If I do:

SelectQuery query = new SelectQuery(A.class);
query.addPrefetch("b").setSemantics(PrefetchTreeNode.DISJOINT_PREFETCH_SEMANTICS);
query.addPrefetch("c").setSemantics(PrefetchTreeNode.DISJOINT_PREFETCH_SEMANTICS);
List<?> res = context.performQuery(query);

then later:

SelectQuery query = new SelectQuery(A.class);
query.addPrefetch("d").setSemantics(PrefetchTreeNode.DISJOINT_PREFETCH_SEMANTICS);
List<?> res = context.performQuery(query);

The relationships from a to b and c are invalidated (see DataRowUtils line 115).

I'm using Cayenne 3.0.2 but the behavior seems identical in versions 3.1 and 3.2M1

Is there a way to work around this issue?

My idea is to override CayenneDataObject in class A with this function:

public void writePropertyDirectly(String propName, Object val) {
    if(propName.equals("b") || propName.equals("c")) {
        if(val instanceof Fault && readPropertyDirectly(propName) != null) {
            return;
        }
    }
    super.writePropertyDirectly(propName, val);
}

Is that a bad idea? It seems to work.
Once loaded, I don't want to refresh b and c from the database at all.
Thanks


Solution

  • Actually this behavior is expected. Invalidation of to-one relationships is done eagerly on select to guarantee a fresh view of them, and on a premise that it should be easy to restore them from the memory cache when needed. So for a simple FK relationship when you call 'getB' or 'getC', you will get an object for the Fault, and you won't see a DB query.

    An exception to that (an unexpected query when reading a to-one) can happen for a few reasons. The most likely one is eager garbage collection of the ObjectContext-local cache. To prevent it Cayenne 3.1 and 3.2 provide an ability to specify retain strategy set as 'cayenne.server.object_retain_strategy' property. You can try 'hard' strategy and see if there's any difference.

    Your above solution is only ok if you know of all the scenarios where A is accessed and refreshed. In general it may cause hard-to-debug issues with data refreshing.