diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/method/MapSpaceSqlMethodExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/method/MapSpaceSqlMethodExecutor.java
index 18a50d1ee6af1ac0f1ae8154bc5c5a59321d8be1..37251f3ed0f9afa599b92b90dcf80abfd4a1073d 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/method/MapSpaceSqlMethodExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/method/MapSpaceSqlMethodExecutor.java
@@ -16,22 +16,16 @@
 
 package ch.ethz.sis.openbis.generic.server.api.v3.executor.method;
 
-import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
-import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.common.IMapObjectByIdExecutor;
-import ch.ethz.sis.openbis.generic.server.api.v3.executor.space.IMapSpaceByIdExecutor;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.space.IMapSpaceTechIdByIdExecutor;
 import ch.ethz.sis.openbis.generic.server.api.v3.translator.ITranslator;
 import ch.ethz.sis.openbis.generic.server.api.v3.translator.entity.space.sql.ISpaceSqlTranslator;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.space.Space;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.fetchoptions.space.SpaceFetchOptions;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.space.ISpaceId;
-import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
 
 /**
  * @author pkupczyk
@@ -41,7 +35,7 @@ public class MapSpaceSqlMethodExecutor extends AbstractMapMethodExecutor<ISpaceI
 {
 
     @Autowired
-    private IMapSpaceByIdExecutor mapExecutor;
+    private IMapSpaceTechIdByIdExecutor mapExecutor;
 
     @Autowired
     private ISpaceSqlTranslator translator;
@@ -49,23 +43,7 @@ public class MapSpaceSqlMethodExecutor extends AbstractMapMethodExecutor<ISpaceI
     @Override
     protected IMapObjectByIdExecutor<ISpaceId, Long> getMapExecutor()
     {
-        // TODO replace with ISpaceId -> Long mapExecutor once there is one
-        return new IMapObjectByIdExecutor<ISpaceId, Long>()
-            {
-                @Override
-                public Map<ISpaceId, Long> map(IOperationContext context, Collection<? extends ISpaceId> ids)
-                {
-                    Map<ISpaceId, SpacePE> peMap = mapExecutor.map(context, ids);
-                    Map<ISpaceId, Long> idMap = new LinkedHashMap<ISpaceId, Long>();
-
-                    for (Map.Entry<ISpaceId, SpacePE> peEntry : peMap.entrySet())
-                    {
-                        idMap.put(peEntry.getKey(), peEntry.getValue().getId());
-                    }
-
-                    return idMap;
-                }
-            };
+        return mapExecutor;
     }
 
     @Override
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ListSampleTechIdByIdentifier.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ListSampleTechIdByIdentifier.java
index 2677186b333933152788e9dd5835828547c7127b..730b9dc28e9568caa979adf02097afa66e7dd260 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ListSampleTechIdByIdentifier.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ListSampleTechIdByIdentifier.java
@@ -16,7 +16,6 @@
 
 package ch.ethz.sis.openbis.generic.server.api.v3.executor.sample;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
@@ -26,7 +25,7 @@ import java.util.Map.Entry;
 import net.lemnik.eodsql.QueryTool;
 
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.common.TechIdStringIdentifierRecord;
-import ch.ethz.sis.openbis.generic.server.api.v3.helper.common.IListObjectById;
+import ch.ethz.sis.openbis.generic.server.api.v3.helper.common.AbstractListTechIdById;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.sample.SampleIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.basic.CodeConverter;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFactory;
@@ -36,9 +35,8 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFa
  *
  * @author Franz-Josef Elmer
  */
-public class ListSampleTechIdByIdentifier implements IListObjectById<SampleIdentifier, Long>
+public class ListSampleTechIdByIdentifier extends AbstractListTechIdById<SampleIdentifier>
 {
-    private Map<Long, SampleIdentifier> identifiersByTechIds = new HashMap<Long, SampleIdentifier>();
     private String homeSpaceCodeOrNull; 
     
     public ListSampleTechIdByIdentifier(String homeSpaceCodeOrNull)
@@ -53,13 +51,7 @@ public class ListSampleTechIdByIdentifier implements IListObjectById<SampleIdent
     }
 
     @Override
-    public SampleIdentifier createId(Long techId)
-    {
-        return identifiersByTechIds.get(techId);
-    }
-    
-    @Override
-    public List<Long> listByIds(List<SampleIdentifier> ids)
+    protected Map<Long, SampleIdentifier> createIdsByTechIdsMap(List<SampleIdentifier> ids)
     {
         Map<Key, Map<String, SampleIdentifier>> groupedIdentifiers = new HashMap<>();
         for (SampleIdentifier sampleIdentifier : ids)
@@ -92,6 +84,8 @@ public class ListSampleTechIdByIdentifier implements IListObjectById<SampleIdent
             }
             identifiersByCode.put(sampleSubCode, sampleIdentifier);
         }
+        
+        Map<Long, SampleIdentifier> result = new HashMap<>();
         SampleQuery query = QueryTool.getManagedQuery(SampleQuery.class);
         for (Entry<Key, Map<String, SampleIdentifier>> entry : groupedIdentifiers.entrySet())
         {
@@ -101,10 +95,10 @@ public class ListSampleTechIdByIdentifier implements IListObjectById<SampleIdent
             for (TechIdStringIdentifierRecord record : records)
             {
                 String sampleCode = record.identifier;
-                identifiersByTechIds.put(record.id, identifiersByCode.get(sampleCode));
+                result.put(record.id, identifiersByCode.get(sampleCode));
             }
         }
-        return new ArrayList<>(identifiersByTechIds.keySet());
+        return result;
     }
     
     private List<TechIdStringIdentifierRecord> list(SampleQuery query, Key key, Collection<String> codes)
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ListSampleTechIdByPermId.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ListSampleTechIdByPermId.java
index 6905e21ba1e90275c8fc33d9e12942db441468c3..4cf18016ea47885de8f3741237ca9b1864a1ea8c 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ListSampleTechIdByPermId.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ListSampleTechIdByPermId.java
@@ -16,15 +16,12 @@
 
 package ch.ethz.sis.openbis.generic.server.api.v3.executor.sample;
 
-import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 import net.lemnik.eodsql.QueryTool;
 
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.common.TechIdStringIdentifierRecord;
-import ch.ethz.sis.openbis.generic.server.api.v3.helper.common.IListObjectById;
+import ch.ethz.sis.openbis.generic.server.api.v3.helper.common.AbstractListTechIdByPermId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.sample.SamplePermId;
 
 /**
@@ -32,10 +29,8 @@ import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.sample.SamplePermId;
  *
  * @author Franz-Josef Elmer
  */
-public class ListSampleTechIdByPermId implements IListObjectById<SamplePermId, Long>
+public class ListSampleTechIdByPermId extends AbstractListTechIdByPermId<SamplePermId>
 {
-    private Map<Long, SamplePermId> permIdsByTechIds = new HashMap<Long, SamplePermId>(); 
-
     @Override
     public Class<SamplePermId> getIdClass()
     {
@@ -43,28 +38,15 @@ public class ListSampleTechIdByPermId implements IListObjectById<SamplePermId, L
     }
 
     @Override
-    public SamplePermId createId(Long techId)
+    protected List<TechIdStringIdentifierRecord> queryTechIds(String[] permIds)
     {
-        return permIdsByTechIds.get(techId);
+        SampleQuery query = QueryTool.getManagedQuery(SampleQuery.class);
+        return query.listSampleTechIdsByPermIds(permIds);
     }
 
     @Override
-    public List<Long> listByIds(List<SamplePermId> ids)
+    protected SamplePermId createPermId(String permIdAsString)
     {
-        SampleQuery query = QueryTool.getManagedQuery(SampleQuery.class);
-        
-        List<String> permIds = new ArrayList<>(ids.size());
-        for (SamplePermId permId : ids)
-        {
-            permIds.add(permId.getPermId());
-        } 
-        List<Long> techIds = new ArrayList<>();
-        for (TechIdStringIdentifierRecord record : query.listSampleTechIdsByPermIds(permIds.toArray(new String[permIds.size()])))
-        {
-            techIds.add(record.id);
-            permIdsByTechIds.put(record.id, new SamplePermId(record.identifier));
-        }
-        return techIds;
+        return new SamplePermId(permIdAsString);
     }
-
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/space/IMapSpaceTechIdByIdExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/space/IMapSpaceTechIdByIdExecutor.java
new file mode 100644
index 0000000000000000000000000000000000000000..a8667b540145bc6578202dec364c394de88b5a9f
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/space/IMapSpaceTechIdByIdExecutor.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2015 ETH Zuerich, SIS
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.ethz.sis.openbis.generic.server.api.v3.executor.space;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.common.IMapObjectByIdExecutor;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.space.ISpaceId;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public interface IMapSpaceTechIdByIdExecutor extends IMapObjectByIdExecutor<ISpaceId, Long>
+{
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/space/ListSpaceTechIdByPermId.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/space/ListSpaceTechIdByPermId.java
new file mode 100644
index 0000000000000000000000000000000000000000..9eb9c6b513ed35b3466da375eb0e0abd7ca75f3e
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/space/ListSpaceTechIdByPermId.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2015 ETH Zuerich, SIS
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.ethz.sis.openbis.generic.server.api.v3.executor.space;
+
+import java.util.List;
+
+import net.lemnik.eodsql.QueryTool;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.common.TechIdStringIdentifierRecord;
+import ch.ethz.sis.openbis.generic.server.api.v3.helper.common.AbstractListTechIdByPermId;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.space.SpacePermId;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class ListSpaceTechIdByPermId extends AbstractListTechIdByPermId<SpacePermId>
+{
+    @Override
+    public Class<SpacePermId> getIdClass()
+    {
+        return SpacePermId.class;
+    }
+
+    @Override
+    protected List<TechIdStringIdentifierRecord> queryTechIds(String[] permIds)
+    {
+        SpaceQuery query = QueryTool.getManagedQuery(SpaceQuery.class);
+        return query.listSpaceTechIdsByPermIds(permIds);
+    }
+
+    @Override
+    protected SpacePermId createPermId(String permIdAsString)
+    {
+        return new SpacePermId(permIdAsString);
+    }
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/space/MapSapceTechIdByIdExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/space/MapSapceTechIdByIdExecutor.java
new file mode 100644
index 0000000000000000000000000000000000000000..248966a4f9ad31dcf8ee3cb7c88ec32970bb8464
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/space/MapSapceTechIdByIdExecutor.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2015 ETH Zuerich, SIS
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.ethz.sis.openbis.generic.server.api.v3.executor.space;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.springframework.stereotype.Component;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.common.AbstractMapObjectByIdExecutor;
+import ch.ethz.sis.openbis.generic.server.api.v3.helper.common.IListObjectById;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.space.ISpaceId;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+@Component
+public class MapSapceTechIdByIdExecutor extends AbstractMapObjectByIdExecutor<ISpaceId, Long> implements IMapSpaceTechIdByIdExecutor
+{
+
+    @Override
+    protected List<IListObjectById<? extends ISpaceId, Long>> createListers(IOperationContext context)
+    {
+        List<IListObjectById<? extends ISpaceId, Long>> listers =
+                new LinkedList<IListObjectById<? extends ISpaceId, Long>>();
+        listers.add(new ListSpaceTechIdByPermId());
+        return listers;
+    }
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/space/SpaceQuery.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/space/SpaceQuery.java
new file mode 100644
index 0000000000000000000000000000000000000000..bdb7840face6d8afb2403c05083c10e3e7003b3c
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/space/SpaceQuery.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015 ETH Zuerich, SIS
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.ethz.sis.openbis.generic.server.api.v3.executor.space;
+
+import java.util.List;
+
+import net.lemnik.eodsql.Select;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.common.TechIdStringIdentifierRecord;
+import ch.ethz.sis.openbis.generic.server.api.v3.translator.entity.common.sql.ObjectQuery;
+import ch.systemsx.cisd.common.db.mapper.StringArrayMapper;
+
+/**
+ * @author Franz-Josef Elmer
+ */
+public interface SpaceQuery extends ObjectQuery
+{
+    @Select(sql = "select id, code as identifier from spaces where code = any(?{1})", parameterBindings =
+    { StringArrayMapper.class }, fetchSize = FETCH_SIZE)
+    public List<TechIdStringIdentifierRecord> listSpaceTechIdsByPermIds(String[] permIds);
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/helper/common/AbstractListTechIdById.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/helper/common/AbstractListTechIdById.java
new file mode 100644
index 0000000000000000000000000000000000000000..c1cba2d36dc0d78cf0e86d19bd78054f5aefa4cf
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/helper/common/AbstractListTechIdById.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2015 ETH Zuerich, SIS
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.ethz.sis.openbis.generic.server.api.v3.helper.common;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public abstract class AbstractListTechIdById<ID> implements IListObjectById<ID, Long>
+{
+    private Map<Long, ID> idsByTechIds = new HashMap<Long, ID>();
+    
+    @Override
+    public ID createId(Long techId)
+    {
+        return idsByTechIds.get(techId);
+    }
+
+    @Override
+    public List<Long> listByIds(List<ID> ids)
+    {
+        idsByTechIds = createIdsByTechIdsMap(ids);
+        return new ArrayList<>(idsByTechIds.keySet());
+    }
+    
+    protected abstract Map<Long, ID> createIdsByTechIdsMap(List<ID> ids);
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/helper/common/AbstractListTechIdByPermId.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/helper/common/AbstractListTechIdByPermId.java
new file mode 100644
index 0000000000000000000000000000000000000000..d39a3761b23f5f13f647970d3aff1419de9cba4f
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/helper/common/AbstractListTechIdByPermId.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2015 ETH Zuerich, SIS
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.ethz.sis.openbis.generic.server.api.v3.helper.common;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.common.TechIdStringIdentifierRecord;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.ObjectPermId;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public abstract class AbstractListTechIdByPermId<ID extends ObjectPermId> extends AbstractListTechIdById<ID>
+{
+
+    @Override
+    protected Map<Long, ID> createIdsByTechIdsMap(List<ID> ids)
+    {
+        List<String> permIds = new ArrayList<>(ids.size());
+        for (ID permId : ids)
+        {
+            permIds.add(permId.getPermId());
+        } 
+        String[] permIdsAsArray = permIds.toArray(new String[permIds.size()]);
+        Map<Long, ID> result = new HashMap<>();
+        List<TechIdStringIdentifierRecord> queryTechIds = queryTechIds(permIdsAsArray);
+        for (TechIdStringIdentifierRecord record : queryTechIds)
+        {
+            result.put(record.id, createPermId(record.identifier));
+        }
+        return result;
+    }
+    
+    protected abstract List<TechIdStringIdentifierRecord> queryTechIds(String[] permIds);
+    
+    protected abstract ID createPermId(String permIdAsString);
+
+}