diff --git a/product/ERP5/Tool/DomainTool.py b/product/ERP5/Tool/DomainTool.py
index 7424aca2cac9335e00ab534830a282a754978d53..90caae84c13271acec68a01ee826aa2789f71487 100644
--- a/product/ERP5/Tool/DomainTool.py
+++ b/product/ERP5/Tool/DomainTool.py
@@ -242,18 +242,26 @@ class DomainTool(BaseTool):
       if kw.get('src__'):
         return sql_result_list
       result_list = []
-      for predicate in sql_result_list:
-        predicate = predicate.getObject()
-        if (not test) or predicate.test(
-                       context,
-                       tested_base_category_list=tested_base_category_list):
-          result_list.append(predicate)
-      if filter_method is not None:
-        result_list = filter_method(result_list)
-      if sort_key_method is not None:
-        result_list.sort(key=sort_key_method)
-      elif sort_method is not None:
-        result_list.sort(cmp=sort_method)
+      if sql_result_list:
+        if test:
+          cache = {}
+          def isMemberOf(context, c, strict_membership):
+            if c in cache:
+              return cache[c]
+            cache[c] = result = portal_categories.isMemberOf(
+              context, c, strict_membership=strict_membership)
+            return result
+        for predicate in sql_result_list:
+          predicate = predicate.getObject()
+          if not test or predicate.test(context, tested_base_category_list,
+                                        isMemberOf=isMemberOf):
+            result_list.append(predicate)
+        if filter_method is not None:
+          result_list = filter_method(result_list)
+        if sort_key_method is not None:
+          result_list.sort(key=sort_key_method)
+        elif sort_method is not None:
+          result_list.sort(cmp=sort_method)
       return result_list
 
     # XXX FIXME method should not be public 
diff --git a/product/ERP5Type/Core/Predicate.py b/product/ERP5Type/Core/Predicate.py
index 838b6fde4997b11c515922fdaabc7ef347f64fb9..4a111472f943fff7068a5e51ef478ba9c28bee43 100644
--- a/product/ERP5Type/Core/Predicate.py
+++ b/product/ERP5Type/Core/Predicate.py
@@ -87,7 +87,7 @@ class Predicate(XMLObject):
 
   security.declareProtected( Permissions.AccessContentsInformation, 'test' )
   def test(self, context, tested_base_category_list=None, 
-           strict_membership=0, **kw):
+           strict_membership=0, isMemberOf=None, **kw):
     """
       A Predicate can be tested on a given context.
       Parameters can passed in order to ignore some conditions.
@@ -97,6 +97,9 @@ class Predicate(XMLObject):
         destination or the source of a predicate.
       - if strict_membership is specified, we should make sure that we
         are strictly a member of tested categories
+      - isMemberOf can be a function caching results for
+        CategoryTool.isMemberOf: it is always called with given 'context' and
+        'strict_membership' values, and different categories.
     """
     self = self.asPredicate()
     if self is None:
@@ -150,17 +153,19 @@ class Predicate(XMLObject):
     # Test category memberships. Enable the read-only transaction cache
     # because this part is strictly read-only, and context.isMemberOf
     # is very expensive when the category list has many items.
+    if isMemberOf is None:
+      isMemberOf = context._getCategoryTool().isMemberOf
     with readOnlyTransactionCache():
       for c in self.getMembershipCriterionCategoryList():
         bc = c.split('/', 1)[0]
         if tested_base_category_list is None or bc in tested_base_category_list:
           if bc in multimembership_criterion_base_category_list:
-            if not context.isMemberOf(c, strict_membership=strict_membership):
+            if not isMemberOf(context, c, strict_membership=strict_membership):
               return 0
           elif bc in membership_criterion_base_category_list and \
                not tested_base_category.get(bc):
             tested_base_category[bc] = \
-              context.isMemberOf(c, strict_membership=strict_membership)
+              isMemberOf(context, c, strict_membership=strict_membership)
     if 0 in tested_base_category.itervalues():
       return 0