I think the reason this is working for me is because almost all of my qualifiers are "invalidated = 'N'" but this isn't the case in the tests, and it's grabbing the qualifier from the wrong entity.
On Thu, Sep 26, 2013 at 4:08 PM, Mike Kienenberger <[email protected]> wrote: > So I'm investigating this situation. > > PrefetchSelectQuery prefetchQuery = new PrefetchSelectQuery( > prefetchPath, > relationship); > > I replaced > > > prefetchQuery.setQualifier(classDescriptor.getEntity().translateToRelatedEntity( > queryQualifier, > prefetchPath)); > > with this instead: > > > prefetchQuery.setQualifier(relationship.getTargetEntity().translateToRelatedEntity( > queryQualifier, > prefetchPath)); > > which caused a number of cayenne tests to fail during build, but seems > to be generating correct prefetching query qualifiers. > > On Tue, Sep 24, 2013 at 4:16 PM, Mike Kienenberger <[email protected]> wrote: >> Added as Issue CAY-1875 - PrefetchSelectQuery incorrectly applies >> entity qualifiers >> >> On Tue, Sep 24, 2013 at 1:48 PM, Andrus Adamchik <[email protected]> >> wrote: >>> >>>> From what testing I've done so far, the qualifier isn't put on for >>>> prefetch queries, which leaves me at the same situation as when using >>>> my datacontext delegate. >>> >>> This is bad and is not supposed to happen. Appears to be a bug. I am >>> checking SelectQueryPrefetchRouterAction, and it applies *root* entity >>> qualifier to prefetch query instead of prefetched entity. Should be a >>> relatively easy fix for "disjoint" prefetches at least. >>> >>>> What do you think of my general idea of exposing PrefetchSelectQueries to >>>> the DataContextDelegate? >>> >>> FWIW, I was hoping DataContextDelegate itself is on the way out. >>> >>> So I'd start with entity qualifier, as it is intended exactly for what you >>> are trying to do - filtering selects (presuming we fix the bug above). The >>> "special DataContext" case where the qualifier should be ignored can >>> probably be handled by starting a separate ServerRuntime, where you can >>> strip off the qualifiers. For whatever overhead it creates (ideally not >>> much), this has an advantage of cleanly separating "spaces" with different >>> ORM rules. >>> >>> Andrus >>> >>> >>> On Sep 24, 2013, at 8:03 PM, Mike Kienenberger <[email protected]> wrote: >>>> From what testing I've done so far, the qualifier isn't put on for >>>> prefetch queries, which leaves me at the same situation as when using >>>> my datacontext delegate. >>>> >>>> And I also have one case where I need to be able to disable the >>>> qualifier on a specific entity for a specific datacontext. >>>> I don't think this is possible even if the modeler qualifier was >>>> working in all other cases. I consider doing something else, like an >>>> SQL template, but I'd still have entities being fetched in this >>>> situation where foreign keys from that entity wouldn't find a matching >>>> foreign entity due to qualifier restriction. >>>> >>>> >>>> >>>> On Tue, Sep 24, 2013 at 12:07 PM, Andrus Adamchik >>>> <[email protected]> wrote: >>>>>>> I still need a way to filter all query >>>>>>> types for specific entities to filter out certain entities (appending >>>>>>> "where INVALIDATED = 'N'"). >>>>> >>>>> Is this a global rule, or does it depend on some context (like user >>>>> role)? If it's the former, you can add a qualifier to affected entities >>>>> in the Modeler. >>>>> >>>>> Andrus >>>>> >>>>> On Sep 24, 2013, at 7:00 PM, Mike Kienenberger <[email protected]> wrote: >>>>> >>>>>> Here's one possible way to add support for intercepting prefetch >>>>>> queries. I'm not entirely certain it's the best way, but I didn't >>>>>> see another obvious point. >>>>>> >>>>>> What I did was to call >>>>>> QueryRouter.willPerformQuery(PrefetchSelectQuery query) before routing >>>>>> the newly-created prefetch select query. >>>>>> >>>>>> For DataDomainQueryAction, this will call context.willPerformQuery() >>>>>> if there's a non-null context. >>>>>> For anything else (DataDomainLegacyQueryAction, MockQueryRouter), it's a >>>>>> noop. >>>>>> >>>>>> If the returned query is null, then we skip routing the query and >>>>>> return either true or false. I picked true since it might be useful >>>>>> to process children of the prefetch even if the prefetch is not >>>>>> skipped. My own use case is never going to return null, so I'm fine >>>>>> with false. >>>>>> >>>>>> There's also no reason why I picked >>>>>> QueryRouter.willPerformQuery(PrefetchSelectQuery query) instead of >>>>>> QueryRouter.willPerformQuery(Query query) other than it made it more >>>>>> obvious that this method was only being used for >>>>>> PrefetchSelectQueries. But there may be other kinds of queries which >>>>>> should also be going through this method. The more I think about >>>>>> this, the more reasonable it seems have it be Query since developers >>>>>> might be writing their own Query types, and any Queries being created >>>>>> internally should be exposed through >>>>>> DataContextDelegate.willPerformQuery, and the QueryRouter is the most >>>>>> likely place to be able to forward such new queries. >>>>>> >>>>>> This has solved my issues with prefetching under 3.1. I'm still open >>>>>> to suggestions for solving my specific problem another way in the >>>>>> application code (adding database table views isn't an option), but I >>>>>> think exposing prefetch queries (as well as others) is something we >>>>>> should be supporting in Cayenne. >>>>>> >>>>>> >>>>>> Index: >>>>>> framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomainLegacyQueryAction.java >>>>>> =================================================================== >>>>>> --- >>>>>> framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomainLegacyQueryAction.java >>>>>> (revision 1524993) >>>>>> +++ >>>>>> framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomainLegacyQueryAction.java >>>>>> (working copy) >>>>>> @@ -27,6 +27,7 @@ >>>>>> >>>>>> import org.apache.cayenne.CayenneRuntimeException; >>>>>> import org.apache.cayenne.map.DataMap; >>>>>> +import org.apache.cayenne.query.PrefetchSelectQuery; >>>>>> import org.apache.cayenne.query.Query; >>>>>> import org.apache.cayenne.query.QueryMetadata; >>>>>> import org.apache.cayenne.query.QueryRouter; >>>>>> @@ -163,4 +164,8 @@ >>>>>> >>>>>> return q != null ? q : executedQuery; >>>>>> } >>>>>> + >>>>>> + public Query willPerformQuery(PrefetchSelectQuery prefetchQuery) { >>>>>> + return prefetchQuery; >>>>>> + } >>>>>> } >>>>>> Index: >>>>>> framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java >>>>>> =================================================================== >>>>>> --- >>>>>> framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java >>>>>> (revision 1524993) >>>>>> +++ >>>>>> framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/DataDomainQueryAction.java >>>>>> (working copy) >>>>>> @@ -772,4 +772,14 @@ >>>>>> } >>>>>> } >>>>>> } >>>>>> + >>>>>> + public Query willPerformQuery(PrefetchSelectQuery prefetchQuery) { >>>>>> + // Notify DataContextDelegate that we have created a new >>>>>> PrefetchSelectQuery >>>>>> + if (null != context) { >>>>>> + Query transformedQuery = >>>>>> context.nonNullDelegate().willPerformQuery(context, prefetchQuery); >>>>>> + return transformedQuery; >>>>>> + } else { >>>>>> + return prefetchQuery; >>>>>> + } >>>>>> + } >>>>>> } >>>>>> Index: >>>>>> framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/QueryRouter.java >>>>>> =================================================================== >>>>>> --- >>>>>> framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/QueryRouter.java >>>>>> (revision 1524993) >>>>>> +++ >>>>>> framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/QueryRouter.java >>>>>> (working copy) >>>>>> @@ -49,4 +49,6 @@ >>>>>> * @throws NullPointerException if a map parameter is null. >>>>>> */ >>>>>> QueryEngine engineForDataMap(DataMap map); >>>>>> + >>>>>> + Query willPerformQuery(PrefetchSelectQuery prefetchQuery); >>>>>> } >>>>>> Index: >>>>>> framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/SelectQueryPrefetchRouterAction.java >>>>>> =================================================================== >>>>>> --- >>>>>> framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/SelectQueryPrefetchRouterAction.java >>>>>> (revision 1524993) >>>>>> +++ >>>>>> framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/SelectQueryPrefetchRouterAction.java >>>>>> (working copy) >>>>>> @@ -114,9 +114,15 @@ >>>>>> >>>>>> // pass prefetch subtree to enable joint prefetches... >>>>>> prefetchQuery.setPrefetchTree(node); >>>>>> - >>>>>> + >>>>>> + Query transformedQuery = router.willPerformQuery(prefetchQuery); >>>>>> + if (null == transformedQuery) { >>>>>> + // Not sure if we want to return false instead. >>>>>> Returning true seems safer. >>>>>> + return true; >>>>>> + } >>>>>> + >>>>>> // route... >>>>>> - prefetchQuery.route(router, resolver, null); >>>>>> + transformedQuery.route(router, resolver, null); >>>>>> return true; >>>>>> } >>>>>> >>>>>> Index: >>>>>> framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/MockQueryRouter.java >>>>>> =================================================================== >>>>>> --- >>>>>> framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/MockQueryRouter.java >>>>>> (revision 1524993) >>>>>> +++ >>>>>> framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/query/MockQueryRouter.java >>>>>> (working copy) >>>>>> @@ -50,4 +50,8 @@ >>>>>> public QueryEngine engineForDataMap(DataMap map) { >>>>>> return new MockQueryEngine(); >>>>>> } >>>>>> + >>>>>> + public Query willPerformQuery(PrefetchSelectQuery prefetchQuery) { >>>>>> + return prefetchQuery; >>>>>> + } >>>>>> } >>>>>> >>>>>> >>>>>> >>>>>> On Mon, Sep 23, 2013 at 7:04 PM, Mike Kienenberger <[email protected]> >>>>>> wrote: >>>>>>> All of my tests pass now, but I'm still hitting a few issues for 3.1 >>>>>>> that the tests didn't reveal. >>>>>>> >>>>>>> In previous versions (not sure when it changed), there existed the >>>>>>> ability to intercept prefetch queries using >>>>>>> DataContextDelegate.willPerformQuery() or willPerformGenericQuery(). >>>>>>> Those queries are no longer available -- only the original query with >>>>>>> the prefetchTree goes through those methods. >>>>>>> >>>>>>> It's the end of the day here, so I haven't traced through the code yet >>>>>>> to see what's going on, but I still need a way to filter all query >>>>>>> types for specific entities to filter out certain entities (appending >>>>>>> "where INVALIDATED = 'N'"). I've got this working for select >>>>>>> queries, relationship queries, objectIdQueries, but not prefetch >>>>>>> queries. >>>>>>> >>>>>>> And I'm still wondering what the difference between >>>>>>> willPerformGenericQuery and willPerformQuery might be. So far, I >>>>>>> just forward willPerformGenericQuery requests through my >>>>>>> willPerformQuery code. >>>>>> >>>>> >>>> >>>
