diff --git a/src/main/java/org/olat/core/commons/persistence/DB.java b/src/main/java/org/olat/core/commons/persistence/DB.java
index 29ec03b1de89ff67d18f1479d1056435ce35fac5..1af632cca7e3433f1e3cdc3f90bd2fe02928c6f2 100644
--- a/src/main/java/org/olat/core/commons/persistence/DB.java
+++ b/src/main/java/org/olat/core/commons/persistence/DB.java
@@ -36,6 +36,12 @@ import org.olat.core.id.Persistable;
 
 public interface DB {
 	
+	public boolean isMySQL();
+	
+	public boolean isPostgreSQL();
+	
+	public boolean isOracle();
+	
 	/**
 	 * Close the database session.
 	 */
diff --git a/src/main/java/org/olat/core/commons/persistence/DBImpl.java b/src/main/java/org/olat/core/commons/persistence/DBImpl.java
index 9dd7e4023e15eb030cf325691208ff05e5d30ddb..6bcb4ba5e4dc1af526c6da1492a0ca910aca86f5 100644
--- a/src/main/java/org/olat/core/commons/persistence/DBImpl.java
+++ b/src/main/java/org/olat/core/commons/persistence/DBImpl.java
@@ -87,7 +87,22 @@ public class DBImpl extends LogDelegator implements DB, Destroyable {
 	protected static DBImpl getInstance() {
 		return INSTANCE;
 	}
-	
+
+	@Override
+	public boolean isMySQL() {
+		return "mysql".equals(dbVendor);
+	}
+
+	@Override
+	public boolean isPostgreSQL() {
+		return "postgresql".equals(dbVendor);
+	}
+
+	@Override
+	public boolean isOracle() {
+		return "oracle".equals(dbVendor);
+	}
+
 	@Override
 	public String getDbVendor() {
 		return dbVendor;
diff --git a/src/main/java/org/olat/core/commons/persistence/NativeQueryBuilder.java b/src/main/java/org/olat/core/commons/persistence/NativeQueryBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..f3f44ccbb892cae09ab0c67696d2d75e72634335
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/persistence/NativeQueryBuilder.java
@@ -0,0 +1,156 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.commons.persistence;
+
+/**
+ * Provide some help to build native SQL queries for Oracle, MySQL and PostreSQL.
+ * 
+ * Initial date: 02.02.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class NativeQueryBuilder {
+
+	private final StringBuilder sb;
+	private final DB dbInstance;
+
+	/**
+	 * @param len
+	 */
+	public NativeQueryBuilder(int len, DB dbInstance) {
+		sb = new StringBuilder(len);
+		this.dbInstance = dbInstance;
+	}
+
+	/**
+	 * 
+	 */
+	public NativeQueryBuilder(DB dbInstance) {
+		sb = new StringBuilder(128);
+		this.dbInstance = dbInstance;
+	}
+
+	/**
+	 * @param val
+	 * @return Itself
+	 */
+	public NativeQueryBuilder append(String val) {
+		sb.append(val);
+		return this;
+	}
+	
+	/**
+	 * 
+	 * @param val The value to append
+	 * @param append If true append happens, if false not
+	 * @return Itself
+	 */
+	public NativeQueryBuilder append(String val, boolean append) {
+		if(append) {
+			sb.append(val);
+		}
+		return this;
+	}
+	
+	public NativeQueryBuilder append(String valTrue, String valFalse, boolean choice) {
+		if(choice) {
+			sb.append(valTrue);
+		} else {
+			sb.append(valFalse);
+		}
+		return this;
+	}
+	
+	/**
+	 * Append true as boolean for PostgreSQL, 1 for Oracle and MySQL.
+	 * @return
+	 */
+	public NativeQueryBuilder appendTrue() {
+		if(dbInstance.isPostgreSQL()) {
+			sb.append("true");
+		} else {
+			sb.append("1");
+		}
+		return this;
+	}
+	
+	/**
+	 * Append false as boolean for PostgreSQL, 0 for Oracle and MySQL.
+	 * @return
+	 */
+	public NativeQueryBuilder appendFalse() {
+		if(dbInstance.isPostgreSQL()) {
+			sb.append("false");
+		} else {
+			sb.append("0");
+		}
+		return this;
+	}
+	
+	/**
+	 * Append an "as" for MySQL and PostgreSQL but not Oracle.
+	 * @return
+	 */
+	public NativeQueryBuilder appendAs() {
+		if(dbInstance.isOracle()) {
+			sb.append(" ");
+		} else {
+			sb.append(" as ");
+		}
+		return this;
+	}
+	
+	public NativeQueryBuilder appendToArray(String var) {
+		if(dbInstance.isMySQL()) {
+			sb.append(" group_concat(").append(var).append(")");
+		} else if(dbInstance.isPostgreSQL()) {
+			sb.append(" array_to_string(array_agg(").append(var).append("),',')");
+		} else if(dbInstance.isOracle()) {
+			sb.append(" listagg(").append(var).append(",',')");
+		}
+		return this;
+	}
+
+	/**
+	 * @param i
+	 * @return Itself
+	 */
+	public NativeQueryBuilder append(int i) {
+		sb.append(i);
+		return this;
+	}
+
+	/**
+	 * @param sMin
+	 * @return Itself
+	 */
+	public NativeQueryBuilder append(long sMin) {
+		sb.append(String.valueOf(sMin));
+		return this;
+	}
+
+	/**
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public String toString() {
+		return sb.toString();
+	}
+}
diff --git a/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml b/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml
index c99beea3e42c26390e66058369fdf00675e458cd..17f8f769553c83da61b06d48d042979d7238e43f 100644
--- a/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml
+++ b/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml
@@ -127,10 +127,6 @@
 		<class>org.olat.instantMessaging.model.InstantMessageNotificationImpl</class>
 		<class>org.olat.ims.qti.statistics.model.QTIStatisticResult</class>
 		<class>org.olat.ims.qti.statistics.model.QTIStatisticResultSet</class>
-		<class>org.olat.modules.coach.model.EfficiencyStatementGroupStatEntry</class>
-		<class>org.olat.modules.coach.model.EfficiencyStatementCourseStatEntry</class>
-		<class>org.olat.modules.coach.model.EfficiencyStatementStudentStatEntry</class>
-		<class>org.olat.modules.coach.model.EfficiencyStatementIdentityStatEntry</class>
 		<class>org.olat.modules.qpool.model.PoolImpl</class>
 		<class>org.olat.modules.qpool.model.PoolToItem</class>
 		<class>org.olat.modules.qpool.model.PoolItemShortView</class>
diff --git a/src/main/java/org/olat/course/CourseFactory.java b/src/main/java/org/olat/course/CourseFactory.java
index 95e6e2dc145b72c3f842b45f3cea23c1c38563b4..8c2cc01438380f0b5a82b321790eabf90704e8a2 100644
--- a/src/main/java/org/olat/course/CourseFactory.java
+++ b/src/main/java/org/olat/course/CourseFactory.java
@@ -556,11 +556,10 @@ public class CourseFactory extends BasicManager {
 				true, Locale.ENGLISH, exportedCourseZIPFile, exportedCourseZIPFile.getName());
 		
 		re.setSoftkey(softKey);
-		re.setAccess(access);
 		repositoryService.update(re);
 		
 		ICourse course = CourseFactory.loadCourse(re.getOlatResource());
-		CourseFactory.publishCourse(course, RepositoryEntry.ACC_USERS, false,  null, Locale.ENGLISH);
+		CourseFactory.publishCourse(course, access, false,  null, Locale.ENGLISH);
 		return re;
 	}
 
diff --git a/src/main/java/org/olat/course/assessment/manager/UserCourseInformationsManagerImpl.java b/src/main/java/org/olat/course/assessment/manager/UserCourseInformationsManagerImpl.java
index c505505c1180b01413aae04c602f2454c521bb38..4930beb0c5b7fd62c69f4181bdb00679e0b03d55 100644
--- a/src/main/java/org/olat/course/assessment/manager/UserCourseInformationsManagerImpl.java
+++ b/src/main/java/org/olat/course/assessment/manager/UserCourseInformationsManagerImpl.java
@@ -35,7 +35,8 @@ import org.olat.core.commons.persistence.DB;
 import org.olat.core.commons.persistence.PersistenceHelper;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
-import org.olat.core.manager.BasicManager;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
 import org.olat.core.util.coordinate.CoordinatorManager;
 import org.olat.core.util.coordinate.SyncerExecutor;
 import org.olat.core.util.resource.OresHelper;
@@ -54,7 +55,9 @@ import org.springframework.stereotype.Service;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
 @Service("userCourseInformationsManager")
-public class UserCourseInformationsManagerImpl extends BasicManager implements UserCourseInformationsManager {
+public class UserCourseInformationsManagerImpl implements UserCourseInformationsManager {
+	
+	private static final OLog log = Tracing.createLoggerFor(UserCourseInformationsManagerImpl.class);
 
 	@Autowired
 	private DB dbInstance;
@@ -81,7 +84,7 @@ public class UserCourseInformationsManagerImpl extends BasicManager implements U
 			}
 			return infoList.get(0);
 		} catch (Exception e) {
-			logError("Cannot retrieve course informations for: " + identity + " from " + identity, e);
+			log.error("Cannot retrieve course informations for: " + identity + " from " + identity, e);
 			return null;
 		}
 	}
@@ -108,7 +111,7 @@ public class UserCourseInformationsManagerImpl extends BasicManager implements U
 			List<UserCourseInformations> infoList = query.getResultList();
 			return infoList;
 		} catch (Exception e) {
-			logError("Cannot retrieve course informations for: " + identity + " from " + identity, e);
+			log.error("Cannot retrieve course informations for: " + identity + " from " + identity, e);
 			return null;
 		}
 	}
@@ -167,7 +170,7 @@ public class UserCourseInformationsManagerImpl extends BasicManager implements U
 							}
 						}
 					} catch (Exception e) {
-						logError("Cannot update course informations for: " + identity + " from " + identity, e);
+						log.error("Cannot update course informations for: " + identity + " from " + identity, e);
 					}
 				}
 			});
@@ -196,7 +199,7 @@ public class UserCourseInformationsManagerImpl extends BasicManager implements U
 			}
 			return infoList.get(0);
 		} catch (Exception e) {
-			logError("Cannot retrieve course informations for: " + id, e);
+			log.error("Cannot retrieve course informations for: " + id, e);
 			return null;
 		}
 	}
@@ -222,7 +225,7 @@ public class UserCourseInformationsManagerImpl extends BasicManager implements U
 			
 			return new UltraLightInfos((Long)infos[0], (Date)infos[1]);
 		} catch (Exception e) {
-			logError("Cannot retrieve course informations for: " + identity + " from " + identity, e);
+			log.error("Cannot retrieve course informations for: " + identity + " from " + identity, e);
 			return null;
 		}
 	}
@@ -284,7 +287,7 @@ public class UserCourseInformationsManagerImpl extends BasicManager implements U
 			}
 			return infoList.get(0);
 		} catch (Exception e) {
-			logError("Cannot retrieve course informations for: " + courseResourceId, e);
+			log.error("Cannot retrieve course informations for: " + courseResourceId, e);
 			return null;
 		}
 	}
@@ -331,7 +334,7 @@ public class UserCourseInformationsManagerImpl extends BasicManager implements U
 			}
 			return dateMap;
 		} catch (Exception e) {
-			logError("Cannot retrieve course informations for: " + courseResourceId, e);
+			log.error("Cannot retrieve course informations for: " + courseResourceId, e);
 			return Collections.emptyMap();
 		}
 	}
@@ -350,7 +353,7 @@ public class UserCourseInformationsManagerImpl extends BasicManager implements U
 					.executeUpdate();
 			return count;
 		} catch (Exception e) {
-			logError("Cannot Delete course informations for: " + entry, e);
+			log.error("Cannot Delete course informations for: " + entry, e);
 			return -1;
 		}
 	}
diff --git a/src/main/java/org/olat/modules/coach/CoachingService.java b/src/main/java/org/olat/modules/coach/CoachingService.java
index 13739b189e9a2c973512d07e642d36a5d235a2a8..e511af643a704eb08a8250770d10e239553b7d85 100644
--- a/src/main/java/org/olat/modules/coach/CoachingService.java
+++ b/src/main/java/org/olat/modules/coach/CoachingService.java
@@ -19,17 +19,15 @@
  */
 package org.olat.modules.coach;
 
-import java.util.Collection;
 import java.util.List;
-import java.util.Map;
 
-import org.olat.basesecurity.IdentityRef;
 import org.olat.core.id.Identity;
 import org.olat.course.assessment.UserEfficiencyStatement;
 import org.olat.group.BusinessGroup;
 import org.olat.modules.coach.model.CourseStatEntry;
 import org.olat.modules.coach.model.EfficiencyStatementEntry;
 import org.olat.modules.coach.model.GroupStatEntry;
+import org.olat.modules.coach.model.SearchCoachedIdentityParams;
 import org.olat.modules.coach.model.StudentStatEntry;
 import org.olat.repository.RepositoryEntry;
 
@@ -44,16 +42,15 @@ public interface CoachingService {
 
 	public boolean isCoach(Identity coach);
 	
-	public Map<Long, String> getIdentities(Collection<Long> identityNames);
 
-	public List<RepositoryEntry> getStudentsCourses(Identity coach, Identity student, int firstResult, int maxResults);
+	public List<RepositoryEntry> getStudentsCourses(Identity coach, Identity student);
 	
 	public List<StudentStatEntry> getStudentsStatistics(Identity coach);
 	
 	
-	public List<StudentStatEntry> getUsersStatistics(List<? extends IdentityRef> identities);
+	public List<StudentStatEntry> getUsersStatistics(SearchCoachedIdentityParams params);
 	
-	public List<RepositoryEntry> getUserCourses(Identity student, int firstResult, int maxResults);
+	public List<RepositoryEntry> getUserCourses(Identity student);
 	
 	
 	public List<CourseStatEntry> getCoursesStatistics(Identity coach);
diff --git a/src/main/java/org/olat/modules/coach/manager/CoachingDAO.java b/src/main/java/org/olat/modules/coach/manager/CoachingDAO.java
index d4107983b00c78a46b8118ea20ad99d2b39a8d7c..067dc492a05eda23659db2b81b6db7b2307bfe97 100644
--- a/src/main/java/org/olat/modules/coach/manager/CoachingDAO.java
+++ b/src/main/java/org/olat/modules/coach/manager/CoachingDAO.java
@@ -21,24 +21,29 @@ package org.olat.modules.coach.manager;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import javax.persistence.Query;
-import javax.persistence.TypedQuery;
 
+import org.olat.basesecurity.GroupRoles;
 import org.olat.basesecurity.IdentityRef;
 import org.olat.basesecurity.IdentityShort;
 import org.olat.core.commons.persistence.DB;
+import org.olat.core.commons.persistence.NativeQueryBuilder;
+import org.olat.core.commons.persistence.PersistenceHelper;
 import org.olat.core.id.Identity;
-import org.olat.core.manager.BasicManager;
+import org.olat.core.util.StringHelper;
 import org.olat.course.assessment.UserEfficiencyStatement;
 import org.olat.course.assessment.model.UserEfficiencyStatementLight;
 import org.olat.modules.coach.model.CourseStatEntry;
-import org.olat.modules.coach.model.EfficiencyStatementCourseStatEntry;
 import org.olat.modules.coach.model.EfficiencyStatementEntry;
-import org.olat.modules.coach.model.EfficiencyStatementGroupStatEntry;
-import org.olat.modules.coach.model.EfficiencyStatementStudentStatEntry;
 import org.olat.modules.coach.model.GroupStatEntry;
+import org.olat.modules.coach.model.SearchCoachedIdentityParams;
 import org.olat.modules.coach.model.StudentStatEntry;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryManager;
@@ -55,27 +60,40 @@ import org.springframework.stereotype.Service;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
 @Service
-public class CoachingDAO extends BasicManager {
+public class CoachingDAO {
 
 	@Autowired
 	private DB dbInstance;
 	@Autowired
 	private RepositoryManager repositoryManager;
 
-	public boolean isCoach(Identity coach) {
-		try {
-			return repositoryManager.hasLearningResourcesAsTeacher(coach);
-		} catch (Exception e) {
-			logError("isCoach: ", e);
-			return false;
-		}
+	public boolean isCoach(IdentityRef coach) {
+		StringBuilder sb = new StringBuilder(1024);
+		sb.append("select v.key from ").append(RepositoryEntry.class.getName()).append(" v ")
+		  .append(" inner join v.olatResource as res on res.resName='CourseModule'")
+		  .append(" inner join v.groups as relGroup")
+		  .append(" inner join relGroup.group as baseGroup")
+		  .append(" inner join baseGroup.members as membership on membership.role in ('").append(GroupRoles.owner.name()).append("','").append(GroupRoles.coach.name()).append("')")
+		  .append(" where membership.identity.key=:identityKey")
+		  .append(" and (")
+		  .append("  (membership.role = 'coach' and (v.access>=3 or (v.access=").append(RepositoryEntry.ACC_OWNERS).append(" and v.membersOnly=true)))")
+		  .append("  or")
+		  .append("  (membership.role = 'owner' and v.access>=1)")
+		  .append(" )");
+		
+		List<Long> firstKey = dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), Long.class)
+				.setParameter("identityKey", coach.getKey())
+				.setFirstResult(0)
+				.setMaxResults(1)
+				.getResultList();
+		return firstKey.size() > 0;
 	}
 
 	public EfficiencyStatementEntry getEfficencyStatementEntry(UserEfficiencyStatement statement) {
 		RepositoryEntry re = repositoryManager.lookupRepositoryEntry(statement.getCourseRepoKey(), false);
 		Identity identity = statement.getIdentity();
-		EfficiencyStatementEntry entry = new EfficiencyStatementEntry(identity, re, statement);
-		return entry;
+		return new EfficiencyStatementEntry(identity, re, statement);
 	}
 
 	public List<EfficiencyStatementEntry> getEfficencyStatementEntriesAlt(List<Identity> students, List<RepositoryEntry> courses) {
@@ -127,10 +145,10 @@ public class CoachingDAO extends BasicManager {
 		sb.append("select statement from ").append(UserEfficiencyStatementLight.class.getName()).append(" as statement ")
 		  .append(" where statement.identity.key=:studentKey");
 
-		TypedQuery<UserEfficiencyStatement> dbQuery = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), UserEfficiencyStatement.class);
-		dbQuery.setParameter("studentKey", student.getKey());
-		List<UserEfficiencyStatement> props = dbQuery.getResultList();
-		return props;
+		return dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), UserEfficiencyStatement.class)
+				.setParameter("studentKey", student.getKey())
+				.getResultList();
 	}
 	
 	private UserEfficiencyStatement getUserEfficiencyStatementFor(Long studentKey, RepositoryEntry course, List<UserEfficiencyStatement> statements) {
@@ -150,221 +168,834 @@ public class CoachingDAO extends BasicManager {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select statement from ").append(UserEfficiencyStatementLight.class.getName()).append(" as statement ")
 		  .append(" where statement.identity.key in (:studentsKey) and statement.resource.key in (:courseResourcesKey)");
-
-		TypedQuery<UserEfficiencyStatement> dbQuery = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), UserEfficiencyStatement.class);
 		
 		List<Long> coursesKey = new ArrayList<Long>();
 		for(RepositoryEntry course:courses) {
 			coursesKey.add(course.getOlatResource().getKey());
 		}
-		dbQuery.setParameter("courseResourcesKey",coursesKey);
-		dbQuery.setParameter("studentsKey", studentKeys);
 
-		List<UserEfficiencyStatement> props = dbQuery.getResultList();
-		return props;
+		return dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), UserEfficiencyStatement.class)
+				.setParameter("courseResourcesKey",coursesKey)
+				.setParameter("studentsKey", studentKeys).getResultList();
 	}
-
-	public List<GroupStatEntry> getGroupsStatistics(Identity coach) {
-		try {
-			StringBuilder query = new StringBuilder();
-			query.append("select s.groupKey, s.groupName, count(distinct s.repoKey), count(distinct s.studentKey), count(s.studentKey),")
-			     .append("sum(s.passed), sum(s.failed), sum(s.notAttempted), avg(s.score), count(s.initialLaunchKey) ")
-			     .append(" from ").append(EfficiencyStatementGroupStatEntry.class.getName()).append(" as s ")
-	             .append(" where s.tutorKey=:coachKey")
-	             .append(" group by s.groupKey, s.groupName");
+	
+	protected List<GroupStatEntry> getGroupsStatisticsNative(Identity coach) {
+		Map<Long,GroupStatEntry> map = new HashMap<>();
+		boolean hasGroups = getGroups(coach, map);
+		if(hasGroups) {
+			boolean hasCoachedGroups = getGroupsStatisticsInfosForCoach(coach, map);
+			boolean hasOwnedGroups = getGroupsStatisticsInfosForOwner(coach, map);
+			for(GroupStatEntry entry:map.values()) {
+				entry.getRepoIds().clear();
+				entry.setCountStudents(entry.getCountDistinctStudents() * entry.getCountCourses());
+			}
+			if(hasOwnedGroups) {
+				getGroupsStatisticsStatementForOwner(coach, map);
+			}
+			if(hasCoachedGroups) {
+				getGroupsStatisticsStatementForCoach(coach, map);
+			}
 			
-			Query dbQuery = dbInstance.getCurrentEntityManager().createQuery(query.toString());
-			dbQuery.setParameter("coachKey", coach.getKey());
-
-			@SuppressWarnings("unchecked")
-			List<Object[]> rawStats = dbQuery.getResultList();
-			List<GroupStatEntry> stats = new ArrayList<GroupStatEntry>();
-			for(Object[] rawStat:rawStats) {
-				GroupStatEntry entry = new GroupStatEntry();
-				entry.setGroupKey((Long)rawStat[0]);
-				entry.setGroupName((String)rawStat[1]);
-				entry.setCountCourses(((Number)rawStat[2]).intValue());
-				entry.setCountStudents(((Number)rawStat[3]).intValue());
-				entry.setCountStudents(((Number)rawStat[4]).intValue());
-				entry.setCountPassed(((Number)rawStat[5]).intValue());
-				entry.setCountFailed(((Number)rawStat[6]).intValue());
-				entry.setCountNotAttempted(((Number)rawStat[7]).intValue());
-				if(rawStat[8] != null) {
-					entry.setAverageScore(((Number)rawStat[8]).floatValue());
+			for(Iterator<Map.Entry<Long, GroupStatEntry>> it=map.entrySet().iterator(); it.hasNext() ; ) {
+				Map.Entry<Long, GroupStatEntry> entry = it.next();
+				GroupStatEntry groupEntry = entry.getValue();
+				if(groupEntry.getCountStudents() == 0) {
+					it.remove();
+				} else {
+					groupEntry.setRepoIds(null);
+					int attempted = groupEntry.getCountPassed() + groupEntry.getCountFailed();
+					groupEntry.setCountNotAttempted(groupEntry.getCountStudents() - attempted);
+					if(attempted > 0) {
+						float averageScore = (float)groupEntry.getSumScore() / attempted;
+						groupEntry.setAverageScore(averageScore);
+					}
 				}
-				entry.setInitialLaunch(((Number)rawStat[9]).intValue());
-				stats.add(entry);
 			}
-			return stats;
-		} catch (Exception e) {
-			logError("getGroupsStatistics takes (ms): ", e);
-			return Collections.emptyList();
 		}
+		return new ArrayList<>(map.values());
 	}
+	
+	private boolean getGroups(Identity coach, Map<Long,GroupStatEntry> map) {
+		NativeQueryBuilder sb = new NativeQueryBuilder(1024, dbInstance);
+		sb.append("select ")
+		  .append(" infos.group_id as grp_id, ")
+		  .append(" infos.fk_group_id as bgrp_id, ")
+		  .append(" infos.groupname as grp_name, ")
+		  .append(" (select count(sg_participant.fk_identity_id) from o_bs_group_member sg_participant ")
+		  .append("   where infos.fk_group_id = sg_participant.fk_group_id and sg_participant.g_role='participant' ")
+		  .append(" ) as num_of_participant ")
+		  .append(" from o_gp_business infos where infos.fk_group_id in ( select ")
+		  .append("   distinct togroup.fk_group_id ")
+		  .append("  from o_re_to_group togroup ")
+		  .append("  inner join o_bs_group_member sg_coach on (sg_coach.fk_group_id=togroup.fk_group_id and sg_coach.g_role = 'coach') ")
+		  .append("  inner join o_repositoryentry sg_re on (togroup.fk_entry_id = sg_re.repositoryentry_id) ")
+		  .append("  inner join o_olatresource sg_res on (sg_res.resource_id = sg_re.fk_olatresource and sg_res.resname = 'CourseModule') ")
+		  .append("  where sg_coach.fk_identity_id=:coachKey and ( ")
+		  .append("   sg_re.accesscode>=").append(RepositoryEntry.ACC_USERS)
+		  .append("   or ")
+		  .append("   (sg_re.accesscode=").append(RepositoryEntry.ACC_OWNERS).append(" and sg_re.membersonly=").appendTrue().append(")) ")
+		  .append(" ) or infos.fk_group_id in ( select ")
+		  .append("	  distinct togroup.fk_group_id ")
+		  .append("  from o_re_to_group togroup ")
+		  .append("  inner join o_repositoryentry sg_re on (togroup.fk_entry_id = sg_re.repositoryentry_id) ")
+		  .append("  inner join o_olatresource sg_res on (sg_res.resource_id = sg_re.fk_olatresource and sg_res.resname = 'CourseModule') ")
+		  .append("  inner join o_re_to_group owngroup on (owngroup.r_defgroup=").appendTrue().append(" and owngroup.fk_entry_id = sg_re.repositoryentry_id) ")
+		  .append("  inner join o_bs_group_member sg_owner on (sg_owner.fk_group_id=owngroup.fk_group_id and sg_owner.g_role = 'owner') ")
+		  .append("  where togroup.r_defgroup=").appendFalse().append(" and sg_owner.fk_identity_id=:coachKey and sg_re.accesscode>=").append(RepositoryEntry.ACC_OWNERS)
+		  .append(" ) ");
 
-	public List<CourseStatEntry> getCoursesStatistics(Identity coach) {
-		//course has members or groups but not both, we can add without check
-		
-		StringBuilder query = new StringBuilder();
-		//                      0             1                    2                             3
-		query.append("select s.repoKey, s.repoDisplayName, count(distinct s.studentKey), count(s.studentKey),")
-		//                      4             5              6                 7                 8
-		     .append(" sum(s.passed), sum(s.failed), sum(s.notAttempted), avg(s.score), count(s.initialLaunchKey) ")
-		     .append(" from ").append(EfficiencyStatementCourseStatEntry.class.getName()).append(" as s ")
-             .append(" where s.tutorKey=:tutorKey")
-             .append(" group by s.repoKey, s.repoDisplayName");
+		List<?> rawList = dbInstance.getCurrentEntityManager()
+				.createNativeQuery(sb.toString())
+				.setParameter("coachKey", coach.getKey())
+				.getResultList();
 
-		List<Object[]> rawStats = dbInstance.getCurrentEntityManager()
-				.createQuery(query.toString(), Object[].class)
-				.setParameter("tutorKey", coach.getKey())
+		for(Object rawObject:rawList) {
+			Object[] rawStat = (Object[])rawObject;
+			Long groupKey = ((Number)rawStat[0]).longValue();
+			Long baseGroupKey = ((Number)rawStat[1]).longValue();
+			String title = (String)rawStat[2];
+			GroupStatEntry entry = new GroupStatEntry(groupKey, title);
+			entry.setCountDistinctStudents(((Number)rawStat[3]).intValue());
+			map.put(baseGroupKey, entry);
+		}
+		return rawList.size() > 0;
+	}
+	
+	private boolean getGroupsStatisticsInfosForCoach(Identity coach, Map<Long,GroupStatEntry> map) {
+		NativeQueryBuilder sb = new NativeQueryBuilder(1024, dbInstance);
+		sb.append("select ")
+		  .append("  togroup.fk_group_id as basegr_id, ")
+		  .append("  togroup.fk_entry_id as re_id, ")
+		  .append("  count(distinct pg_initial_launch.id) as pg_id ")
+		  .append(" from o_repositoryentry sg_re  ")
+		  .append(" inner join o_re_to_group togroup on (togroup.r_defgroup=").appendFalse().append(" and togroup.fk_entry_id = sg_re.repositoryentry_id) ")
+		  .append(" inner join o_bs_group_member sg_coach on (sg_coach.fk_group_id=togroup.fk_group_id and sg_coach.g_role = 'coach') ")
+		  .append(" inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=sg_coach.fk_group_id and sg_participant.g_role='participant') ")
+		  .append(" left join o_as_user_course_infos pg_initial_launch ")
+		  .append("   on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id) ")
+		  .append(" where sg_coach.fk_identity_id=:coachKey and ( ")
+		  .append("   (sg_re.accesscode >= ").append(RepositoryEntry.ACC_USERS).append(" and sg_coach.g_role = 'coach') ")//BAR
+		  .append("   or ")
+		  .append("   (sg_re.accesscode = ").append(RepositoryEntry.ACC_OWNERS).append(" and sg_re.membersonly=").appendTrue().append(")) ")
+		  .append(" group by togroup.fk_group_id, togroup.fk_entry_id ");
+		
+		List<?> rawList = dbInstance.getCurrentEntityManager()
+				.createNativeQuery(sb.toString())
+				.setParameter("coachKey", coach.getKey())
+				.getResultList();
+		
+		for(Object rawObject:rawList) {
+			Object[] rawStats = (Object[])rawObject;
+			Long baseGroupKey = ((Number)rawStats[0]).longValue();
+			GroupStatEntry entry = map.get(baseGroupKey);
+			if(entry != null) {
+				Long repoKey = ((Number)rawStats[1]).longValue();
+				if(!entry.getRepoIds().contains(repoKey)) {
+					int initalLaunch = ((Number)rawStats[2]).intValue();
+					entry.setInitialLaunch(initalLaunch + entry.getInitialLaunch());
+					entry.setCountCourses(entry.getCountCourses() + 1);
+					entry.getRepoIds().add(repoKey);
+				}
+			}
+		}
+		return rawList.size() > 0;
+	}
+	
+	private boolean getGroupsStatisticsInfosForOwner(Identity coach, Map<Long,GroupStatEntry> map) {
+		NativeQueryBuilder sb = new NativeQueryBuilder(1024, dbInstance);
+		sb.append("select ")
+		  .append("  togroup.fk_group_id as basegr_id, ")
+		  .append("  togroup.fk_entry_id as re_id, ")
+		  .append("  count(distinct pg_initial_launch.id) as pg_id ")
+		  .append(" from o_repositoryentry sg_re  ")
+		  .append(" inner join o_re_to_group owngroup on (owngroup.r_defgroup=").appendTrue().append(" and owngroup.fk_entry_id = sg_re.repositoryentry_id) ")
+		  .append(" inner join o_bs_group_member sg_owner on (sg_owner.fk_group_id=owngroup.fk_group_id and sg_owner.g_role = 'owner') ")
+		  .append(" inner join o_re_to_group togroup on (togroup.r_defgroup=").appendFalse().append(" and togroup.fk_entry_id = sg_re.repositoryentry_id) ")
+		  .append(" inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=togroup.fk_group_id and sg_participant.g_role='participant') ")
+		  .append(" left join o_as_user_course_infos pg_initial_launch ")
+		  .append("   on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id) ")
+		  .append(" where sg_owner.fk_identity_id=:coachKey and sg_re.accesscode >= ").append(RepositoryEntry.ACC_OWNERS)
+		  .append(" group by togroup.fk_group_id, togroup.fk_entry_id ");
+		
+		List<?> rawList = dbInstance.getCurrentEntityManager()
+				.createNativeQuery(sb.toString())
+				.setParameter("coachKey", coach.getKey())
+				.getResultList();
+		
+		for(Object rawObject:rawList) {
+			Object[] rawStats = (Object[])rawObject;
+			Long baseGroupKey = ((Number)rawStats[0]).longValue();
+			GroupStatEntry entry = map.get(baseGroupKey);
+			if(entry != null) {
+				Long repoKey = ((Number)rawStats[1]).longValue();
+				if(!entry.getRepoIds().contains(repoKey)) {
+					int initalLaunch = ((Number)rawStats[2]).intValue();
+					entry.setInitialLaunch(initalLaunch + entry.getInitialLaunch());
+					entry.setCountCourses(entry.getCountCourses() + 1);
+					entry.getRepoIds().add(repoKey);
+				}
+			}
+		}
+		return rawList.size() > 0;
+	}
+	
+	private boolean getGroupsStatisticsStatementForCoach(Identity coach, Map<Long,GroupStatEntry> map) {
+		NativeQueryBuilder sb = new NativeQueryBuilder(1024, dbInstance);
+		sb.append("select")
+		  .append(" fin_statement.bgp_id,")
+		  .append(" fin_statement.re_id,")
+		  .append(" sum(case when fin_statement.passed=").appendTrue().append(" then 1 else 0 end) as num_of_passed,")
+		  .append(" sum(case when fin_statement.passed=").appendFalse().append(" then 1 else 0 end) as num_of_failed,")
+		  .append(" sum(fin_statement.score) as avg_score ")
+		  .append("from ( select ")
+		  .append("  distinct sg_statement.id as id,")
+		  .append("  togroup.fk_group_id as bgp_id,")
+		  .append("  togroup.fk_entry_id as re_id,")
+		  .append("  sg_statement.passed as passed,")
+		  .append("  sg_statement.score as score ")
+		  .append(" from o_repositoryentry sg_re ")
+		  .append(" inner join o_re_to_group togroup on (togroup.r_defgroup=").appendFalse().append(" and togroup.fk_entry_id = sg_re.repositoryentry_id) ")
+		  .append(" inner join o_bs_group_member sg_coach on (sg_coach.fk_group_id=togroup.fk_group_id and sg_coach.g_role = 'coach') ")
+		  .append(" inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=sg_coach.fk_group_id and sg_participant.g_role='participant') ")
+		  .append(" inner join o_as_eff_statement sg_statement on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource) ")
+		  .append(" where sg_coach.fk_identity_id=:coachKey and ( ")
+		  .append("   (sg_re.accesscode >= ").append(RepositoryEntry.ACC_USERS).append(" and sg_coach.g_role = 'coach') ")//BAR
+		  .append("   or ")
+		  .append("   (sg_re.accesscode = ").append(RepositoryEntry.ACC_OWNERS).append(" and sg_re.membersonly=").appendTrue().append(")) ")
+		  .append(") ").appendAs().append(" fin_statement ")
+		  .append("group by fin_statement.bgp_id, fin_statement.re_id ");
+		
+		List<?> rawList = dbInstance.getCurrentEntityManager()
+				.createNativeQuery(sb.toString())
+				.setParameter("coachKey", coach.getKey())
+				.getResultList();
+		
+		for(Object rawObject:rawList) {
+			Object[] rawStats = (Object[])rawObject;
+			Long baseGroupKey = ((Number)rawStats[0]).longValue();
+			Long repoKey = ((Number)rawStats[1]).longValue();
+			GroupStatEntry entry = map.get(baseGroupKey);
+			if(entry != null && !entry.getRepoIds().contains(repoKey)) {
+				int passed = ((Number)rawStats[2]).intValue();
+				int failed = ((Number)rawStats[3]).intValue();
+				entry.setCountFailed(failed + entry.getCountFailed());
+				entry.setCountPassed(passed + entry.getCountPassed());
+				if(rawStats[4] != null) {
+					entry.setSumScore(entry.getSumScore() + ((Number)rawStats[4]).floatValue());
+				}
+				entry.getRepoIds().add(repoKey);
+			}
+		}
+		return rawList.size() > 0;
+	}
+	
+	private boolean getGroupsStatisticsStatementForOwner(Identity coach, Map<Long,GroupStatEntry> map) {
+		NativeQueryBuilder sb = new NativeQueryBuilder(1024, dbInstance);
+		sb.append("select")
+		  .append(" fin_statement.bgp_id,")
+		  .append(" fin_statement.re_id,")
+		  .append(" sum(case when fin_statement.passed=").appendTrue().append(" then 1 else 0 end) as num_of_passed,")
+		  .append(" sum(case when fin_statement.passed=").appendFalse().append(" then 1 else 0 end) as num_of_failed,")
+		  .append(" sum(fin_statement.score) as avg_score ")
+		  .append("from ( select ")
+		  .append("  distinct sg_statement.id as id,")
+		  .append("  togroup.fk_group_id as bgp_id,")
+		  .append("  togroup.fk_entry_id as re_id,")
+		  .append("  sg_statement.passed as passed,")
+		  .append("  sg_statement.score as score ")
+		  .append(" from o_repositoryentry sg_re ")
+		  .append(" inner join o_re_to_group owngroup on (owngroup.r_defgroup=").appendTrue().append(" and owngroup.fk_entry_id = sg_re.repositoryentry_id) ")
+		  .append(" inner join o_bs_group_member sg_owner on (sg_owner.fk_group_id=owngroup.fk_group_id and sg_owner.g_role = 'owner') ")
+		  .append(" inner join o_re_to_group togroup on (togroup.r_defgroup=").appendFalse().append(" and togroup.fk_entry_id = sg_re.repositoryentry_id) ")
+		  .append(" inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=togroup.fk_group_id and sg_participant.g_role='participant') ")
+		  .append(" inner join o_as_eff_statement sg_statement on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource) ")
+		  .append(" where sg_owner.fk_identity_id=:coachKey and sg_re.accesscode >= ").append(RepositoryEntry.ACC_OWNERS)
+		  .append(") ").appendAs().append(" fin_statement ")
+		  .append("group by fin_statement.bgp_id, fin_statement.re_id ");
+		
+		List<?> rawList = dbInstance.getCurrentEntityManager()
+				.createNativeQuery(sb.toString())
+				.setParameter("coachKey", coach.getKey())
 				.getResultList();
 		
-		List<CourseStatEntry> stats = new ArrayList<CourseStatEntry>();
-		for(Object[] rawStat:rawStats) {
+		for(Object rawObject:rawList) {
+			Object[] rawStats = (Object[])rawObject;
+			Long baseGroupKey = ((Number)rawStats[0]).longValue();
+			Long repoKey = ((Number)rawStats[1]).longValue();
+			GroupStatEntry entry = map.get(baseGroupKey);
+			if(entry != null && !entry.getRepoIds().contains(repoKey)) {
+				int passed = ((Number)rawStats[2]).intValue();
+				int failed = ((Number)rawStats[3]).intValue();
+				entry.setCountFailed(failed + entry.getCountFailed());
+				entry.setCountPassed(passed + entry.getCountPassed());
+				if(rawStats[4] != null) {
+					entry.setSumScore(entry.getSumScore() + ((Number)rawStats[4]).floatValue());
+				}
+				entry.getRepoIds().add(repoKey);
+			}
+		}
+		return rawList.size() > 0;
+	}
+	
+	protected List<CourseStatEntry> getCoursesStatisticsNative(Identity coach) {
+		Map<Long,CourseStatEntry> map = new HashMap<>();		
+		boolean hasCourses = getCourses(coach, map);
+		if(hasCourses) {
+			getCoursesStatisticsUserInfosForCoach(coach, map);
+			getCoursesStatisticsUserInfosForOwner(coach, map);
+			getCoursesStatisticsStatements(coach, map);
+			for(Iterator<Map.Entry<Long,CourseStatEntry>> it=map.entrySet().iterator(); it.hasNext(); ) {
+				CourseStatEntry entry = it.next().getValue();
+				if(entry.getCountStudents() == 0) {
+					it.remove();
+				} else {
+					int notAttempted = entry.getCountStudents() - entry.getCountPassed() - entry.getCountFailed();
+					entry.setCountNotAttempted(notAttempted);
+				}
+			}
+		}
+		return new ArrayList<>(map.values());
+	}
+	
+	private boolean getCourses(IdentityRef coach, Map<Long,CourseStatEntry> map) {
+		NativeQueryBuilder sb = new NativeQueryBuilder(1024, dbInstance);
+		sb.append("select v.key, v.displayname")
+		  .append(" from repositoryentry v")
+		  .append(" inner join v.olatResource as res")
+		  .append(" inner join v.groups as relGroup")
+		  .append(" inner join relGroup.group as baseGroup")
+		  .append(" inner join baseGroup.members as coach on coach.role in ('").append(GroupRoles.coach.name()).append("','").append(GroupRoles.owner.name()).append("')")
+		  .append(" where coach.identity.key=:coachKey and res.resName='CourseModule'")
+		  .append(" and ((v.access=1 and v.membersOnly=true) ")
+		  .append(" or (v.access >= ").append(RepositoryEntry.ACC_USERS).append(" and coach.role='").append(GroupRoles.coach.name()).append("')")
+		  .append(" or (v.access >= ").append(RepositoryEntry.ACC_OWNERS).append(" and coach.role='").append(GroupRoles.owner.name()).append("'))");
+
+		List<Object[]> rawList = dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), Object[].class)
+				.setParameter("coachKey", coach.getKey())
+				.getResultList();
+
+		for(Object[] rawStat:rawList) {
 			CourseStatEntry entry = new CourseStatEntry();
-			entry.setRepoKey((Long)rawStat[0]);
+			entry.setRepoKey(((Number)rawStat[0]).longValue());
 			entry.setRepoDisplayName((String)rawStat[1]);
-			entry.setCountStudents(((Number)rawStat[2]).intValue());
-			entry.setCountDistinctStudents(((Number)rawStat[3]).intValue());
-			entry.setCountPassed(((Number)rawStat[4]).intValue());
-			entry.setCountFailed(((Number)rawStat[5]).intValue());
-			entry.setCountNotAttempted(((Number)rawStat[6]).intValue());
-			if(rawStat[7] != null) {
-				entry.setAverageScore(((Number)rawStat[7]).floatValue());
+			map.put(entry.getRepoKey(), entry);
+		}
+		return rawList.size() > 0;
+	}
+	
+	private boolean getCoursesStatisticsUserInfosForCoach(Identity coach, Map<Long,CourseStatEntry> map) {
+		NativeQueryBuilder sb = new NativeQueryBuilder(1024, dbInstance);
+		sb.append("select")
+		  .append("  sg_re.repositoryentry_id as re_id,")
+		  .append("  count(distinct sg_participant.fk_identity_id) as student_id,")
+		  .append("  count(distinct pg_initial_launch.id) as pg_id")
+		  .append(" from o_repositoryentry sg_re ")
+		  .append(" inner join o_re_to_group togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id)")
+		  .append(" inner join o_bs_group_member sg_coach on (sg_coach.fk_group_id=togroup.fk_group_id and sg_coach.g_role = 'coach')")
+		  .append(" inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=sg_coach.fk_group_id and sg_participant.g_role='participant')")
+		  .append(" left join o_as_user_course_infos pg_initial_launch")
+		  .append("   on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id)")
+		  .append(" where sg_coach.fk_identity_id=:coachKey and ( ")
+		  .append("   (sg_re.accesscode >= ").append(RepositoryEntry.ACC_USERS).append(" and sg_coach.g_role = 'coach') ")//BAR
+		  .append("   or ")
+		  .append("   (sg_re.accesscode = ").append(RepositoryEntry.ACC_OWNERS).append(" and sg_re.membersonly=").appendTrue().append(")) ")
+		  .append(" group by sg_re.repositoryentry_id");
+
+		List<?> rawList = dbInstance.getCurrentEntityManager()
+				.createNativeQuery(sb.toString())
+				.setParameter("coachKey", coach.getKey())
+				.getResultList();
+		
+		for(Object rawObject:rawList) {
+			Object[] rawStats = (Object[])rawObject;
+			Long repoKey = ((Number)rawStats[0]).longValue();
+			CourseStatEntry entry = map.get(repoKey);
+			if(entry != null) {
+				entry.setCountStudents(((Number)rawStats[1]).intValue());
+				entry.setInitialLaunch(((Number)rawStats[2]).intValue());
 			}
-			if(rawStat[8] != null) {
-				entry.setInitialLaunch(((Number)rawStat[8]).intValue());
-			} else {
-				entry.setInitialLaunch(0);
+		}
+		return rawList.size() > 0;
+	}
+	
+	private boolean getCoursesStatisticsUserInfosForOwner(Identity coach, Map<Long,CourseStatEntry> map) {
+		NativeQueryBuilder sb = new NativeQueryBuilder(1024, dbInstance);
+		sb.append("select")
+		  .append("  sg_re.repositoryentry_id as re_id,")
+		  .append("  count(distinct sg_participant.fk_identity_id) as student_id,")
+		  .append("  count(distinct pg_initial_launch.id) as pg_id")
+		  .append(" from o_repositoryentry sg_re ")
+		  .append(" inner join o_re_to_group owngroup on (owngroup.fk_entry_id = sg_re.repositoryentry_id and owngroup.r_defgroup=").appendTrue().append(")")
+		  .append(" inner join o_bs_group_member sg_coach on (sg_coach.fk_group_id=owngroup.fk_group_id and sg_coach.g_role = 'owner')")
+		  .append(" inner join o_re_to_group togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id)")
+		  .append(" inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=togroup.fk_group_id and sg_participant.g_role='participant')")
+		  .append(" left join o_as_user_course_infos pg_initial_launch")
+		  .append("   on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id)")
+		  .append(" where sg_coach.fk_identity_id=:coachKey and sg_re.accesscode >= ").append(RepositoryEntry.ACC_OWNERS)
+		  .append(" group by sg_re.repositoryentry_id");
+
+		List<?> rawList = dbInstance.getCurrentEntityManager()
+				.createNativeQuery(sb.toString())
+				.setParameter("coachKey", coach.getKey())
+				.getResultList();
+		
+		for(Object rawObject:rawList) {
+			Object[] rawStats = (Object[])rawObject;
+			Long repoKey = ((Number)rawStats[0]).longValue();
+			CourseStatEntry entry = map.get(repoKey);
+			if(entry != null) {
+				entry.setCountStudents(((Number)rawStats[1]).intValue());
+				entry.setInitialLaunch(((Number)rawStats[2]).intValue());
 			}
-			stats.add(entry);
 		}
-		return stats;
+		return rawList.size() > 0;
 	}
+	
+	private boolean getCoursesStatisticsStatements(Identity coach, Map<Long,CourseStatEntry> map) {
+		NativeQueryBuilder sb = new NativeQueryBuilder(1024, dbInstance);
+		sb.append("select ")
+		  .append(" fin_statement.course_repo_key, ")
+		  .append(" count(fin_statement.id), ")
+		  .append(" sum(case when fin_statement.passed=").appendTrue().append(" then 1 else 0 end) as num_of_passed, ")
+		  .append(" sum(case when fin_statement.passed=").appendFalse().append(" then 1 else 0 end) as num_of_failed, ")
+		  .append(" avg(fin_statement.score) ")
+		  .append("from o_as_eff_statement fin_statement ")
+		  .append("where fin_statement.id in ( select ")
+		  .append("  distinct sg_statement.id ")
+		  .append("	from o_repositoryentry sg_re ")
+		  .append("	inner join o_re_to_group togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id) ")
+		  .append(" inner join o_bs_group_member sg_coach on (sg_coach.fk_group_id=togroup.fk_group_id and sg_coach.g_role in ('owner','coach')) ")
+		  .append("	inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=sg_coach.fk_group_id and sg_participant.g_role='participant') ")
+		  .append(" inner join o_as_eff_statement sg_statement on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource) ")
+		  .append("	where sg_coach.fk_identity_id=:coachKey and ( ")
+		  .append("   (sg_re.accesscode >= ").append(RepositoryEntry.ACC_USERS).append(" and sg_coach.g_role = 'coach') ")//BAR
+		  .append("   or ")
+		  .append("   (sg_re.accesscode >= ").append(RepositoryEntry.ACC_OWNERS).append(" and sg_coach.g_role = 'owner') ")//B
+		  .append("   or ")
+		  .append("   (sg_re.accesscode = ").append(RepositoryEntry.ACC_OWNERS).append(" and sg_re.membersonly=").appendTrue().append(")) ")
+		  .append(") or fin_statement.id in ( select ")
+		  .append("   distinct sg_statement.id ")
+		  .append(" from o_repositoryentry sg_re ")
+		  .append(" inner join o_re_to_group owngroup on (owngroup.fk_entry_id = sg_re.repositoryentry_id and owngroup.r_defgroup=").appendTrue().append(") ")
+		  .append(" inner join o_bs_group_member sg_coach on (sg_coach.fk_group_id=owngroup.fk_group_id and sg_coach.g_role = 'owner') ")
+		  .append(" inner join o_re_to_group togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id) ")
+		  .append(" inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=togroup.fk_group_id and sg_participant.g_role='participant') ")
+		  .append(" inner join o_as_eff_statement sg_statement on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource) ")
+		  .append(" where sg_coach.fk_identity_id=:coachKey and sg_re.accesscode >= ").append(RepositoryEntry.ACC_OWNERS).append(") ")
+		  .append("group by fin_statement.course_repo_key ");
 
-	public List<StudentStatEntry> getStudentsStatistics(Identity coach) {
-		StringBuilder query = new StringBuilder();
-		//                     0          1                 2               3              4                             5
-		query.append("select s.studentKey, count(s.repoKey), sum(s.passed), sum(s.failed), sum(s.notAttempted), count(s.initialLaunchKey)")
-		     .append(" from ").append(EfficiencyStatementStudentStatEntry.class.getName()).append(" as s ")
-             .append(" where s.tutorKey=:coachKey")
-             .append(" group by s.studentKey");
+		List<?> rawList = dbInstance.getCurrentEntityManager()
+				.createNativeQuery(sb.toString())
+				.setParameter("coachKey", coach.getKey())
+				.getResultList();
 		
-		List<Object[]> rawStats = dbInstance.getCurrentEntityManager()
-				.createQuery(query.toString(), Object[].class)
+		for(Object rawObject:rawList) {
+			Object[] rawStats = (Object[])rawObject;
+			Long repoKey = ((Number)rawStats[0]).longValue();
+			CourseStatEntry entry = map.get(repoKey);
+			if(entry != null) {
+				int passed = ((Number)rawStats[2]).intValue();
+				int failed = ((Number)rawStats[3]).intValue();
+				entry.setCountFailed(failed);
+				entry.setCountPassed(passed);
+				if(rawStats[4] != null) {
+					entry.setAverageScore(((Number)rawStats[4]).floatValue());
+				}
+			}
+		}
+		return rawList.size() > 0;
+	}
+	
+	protected List<StudentStatEntry> getStudentsStatisticsNative(Identity coach) {
+		Map<Long, StudentStatEntry> map = new HashMap<>();
+		boolean hasCoachedStudents = getStudentsStastisticInfosForCoach(coach, map);
+		boolean hasOwnedStudents = getStudentsStastisticInfosForOwner(coach, map);
+		if(hasOwnedStudents || hasCoachedStudents) {
+			for(StudentStatEntry entry:map.values()) {
+				entry.setCountRepo(entry.getRepoIds().size());
+				entry.setRepoIds(null);
+				entry.setInitialLaunch(entry.getLaunchIds().size());
+				entry.setLaunchIds(null);
+			}
+			getStudentsStatisticStatement(coach, map);
+			for(StudentStatEntry entry:map.values()) {
+				int notAttempted = entry.getCountRepo() - entry.getCountPassed() - entry.getCountFailed();
+				entry.setCountNotAttempted(notAttempted);
+			}
+		}
+		return new ArrayList<>(map.values());
+	}
+	
+	private boolean getStudentsStastisticInfosForCoach(IdentityRef coach, Map<Long, StudentStatEntry> map) {
+		NativeQueryBuilder sb = new NativeQueryBuilder(1024, dbInstance);
+		sb.append("select")
+		  .append("  sg_participant.fk_identity_id as part_id,")
+		  .append("  ").appendToArray("sg_re.repositoryentry_id").append(" as re_ids,")
+		  .append("  ").appendToArray("pg_initial_launch.id").append(" as pg_ids")
+		  .append(" from o_repositoryentry sg_re")
+		  .append(" inner join o_olatresource sg_res on (sg_res.resource_id = sg_re.fk_olatresource and sg_res.resname = 'CourseModule') ")
+		  .append(" inner join o_re_to_group togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id)")
+		  .append(" inner join o_bs_group_member sg_coach on (sg_coach.fk_group_id=togroup.fk_group_id and sg_coach.g_role = 'coach')")
+		  .append(" inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=sg_coach.fk_group_id and sg_participant.g_role='participant')")
+		  .append(" left join o_as_user_course_infos pg_initial_launch")
+		  .append("   on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id)")
+		  .append(" where sg_coach.fk_identity_id=:coachKey and ( ")
+		  .append("   (sg_re.accesscode >= ").append(RepositoryEntry.ACC_USERS).append(" and sg_coach.g_role = 'coach') ")//BAR
+		  .append("   or ")
+		  .append("   (sg_re.accesscode = ").append(RepositoryEntry.ACC_OWNERS).append(" and sg_re.membersonly=").appendTrue().append(")) ")
+		  .append(" group by sg_participant.fk_identity_id");
+
+		List<?> rawList = dbInstance.getCurrentEntityManager()
+				.createNativeQuery(sb.toString())
 				.setParameter("coachKey", coach.getKey())
 				.getResultList();
 
-		List<StudentStatEntry> stats = new ArrayList<StudentStatEntry>();
-		for(Object[] rawStat:rawStats) {
-			StudentStatEntry entry = new StudentStatEntry();
-			entry.setStudentKey((Long)rawStat[0]);
-			entry.setCountRepo(((Number)rawStat[1]).intValue());
-			entry.setCountPassed(((Number)rawStat[2]).intValue());
-			entry.setCountFailed(((Number)rawStat[3]).intValue());
-			entry.setCountNotAttempted(((Number)rawStat[4]).intValue());
-			entry.setInitialLaunch(((Number)rawStat[5]).intValue());
-			stats.add(entry);
+		for(Object rawObject:rawList) {
+			Object[] rawStat = (Object[])rawObject;
+			StudentStatEntry entry = new StudentStatEntry(((Number)rawStat[0]).longValue());
+			
+			String repoIds = (String)rawStat[1]; {
+			if(StringHelper.containsNonWhitespace(repoIds))
+				for(String repoId:repoIds.split(",")) {
+					entry.getRepoIds().add(repoId);
+				}
+			}
+			String launchIds = (String)rawStat[2];
+			if(StringHelper.containsNonWhitespace(launchIds)) {
+				for(String launchId:launchIds.split(",")) {
+					entry.getLaunchIds().add(launchId);
+				}
+			}
+			map.put(entry.getStudentKey(), entry);
 		}
-		return stats;
+		return rawList.size() > 0;
 	}
 	
-	public List<StudentStatEntry> getUsersStatistics(List<? extends IdentityRef> identities) {
-		if(identities == null || identities.isEmpty()) return Collections.emptyList();
-		
-		StringBuilder query = new StringBuilder();
-		//                     0          1                 2               3              4                             5
-		query.append("select s.studentKey, count(s.repoKey), sum(s.passed), sum(s.failed), sum(s.notAttempted), count(s.initialLaunchKey)")
-		     .append(" from coachstatisticsidentity as s ")
-             .append(" where s.studentKey in (:identitiesKey)")
-             .append(" group by s.studentKey");
+	private boolean getStudentsStastisticInfosForOwner(IdentityRef coach, Map<Long, StudentStatEntry> map) {
+		NativeQueryBuilder sb = new NativeQueryBuilder(1024, dbInstance);
+		sb.append("select")
+		  .append("  sg_participant.fk_identity_id as part_id,")
+		  .append("  ").appendToArray("sg_re.repositoryentry_id").append(" as re_ids,")
+		  .append("  ").appendToArray("pg_initial_launch.id").append(" as pg_ids")
+		  .append(" from o_repositoryentry sg_re")
+		  .append(" inner join o_olatresource sg_res on (sg_res.resource_id = sg_re.fk_olatresource and sg_res.resname = 'CourseModule')")
+		  .append(" inner join o_re_to_group owngroup on (owngroup.fk_entry_id = sg_re.repositoryentry_id and owngroup.r_defgroup=").appendTrue().append(")")
+		  .append(" inner join o_bs_group_member sg_owner on (sg_owner.fk_group_id=owngroup.fk_group_id and sg_owner.g_role = 'owner')")
+		  .append(" inner join o_re_to_group togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id)")
+		  .append(" inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=togroup.fk_group_id and sg_participant.g_role='participant')")
+		  .append(" left join o_as_user_course_infos pg_initial_launch")
+		  .append("   on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id)")
+		  .append(" where sg_owner.fk_identity_id=:coachKey and sg_re.accesscode >= ").append(RepositoryEntry.ACC_OWNERS)
+		  .append(" group by sg_participant.fk_identity_id");
 		
-		List<Long> identityKeys = getIdentityKeys(identities);
-		List<Object[]> rawStats = dbInstance.getCurrentEntityManager()
-				.createQuery(query.toString(), Object[].class)
-				.setParameter("identitiesKey", identityKeys)
+		List<?> rawList = dbInstance.getCurrentEntityManager()
+				.createNativeQuery(sb.toString())
+				.setParameter("coachKey", coach.getKey())
 				.getResultList();
 
-		List<StudentStatEntry> stats = new ArrayList<StudentStatEntry>();
-		for(Object[] rawStat:rawStats) {
-			StudentStatEntry entry = new StudentStatEntry();
-			entry.setStudentKey((Long)rawStat[0]);
+		Map<Long,StudentStatEntry> stats = new HashMap<>();
+		for(Object rawObject:rawList) {
+			Object[] rawStat = (Object[])rawObject;
+			Long identityKey = ((Number)rawStat[0]).longValue();
+			StudentStatEntry entry;
+			if(map.containsKey(identityKey)) {
+				entry = map.get(identityKey);
+			} else {
+				entry = new StudentStatEntry(identityKey);
+				map.put(identityKey, entry);
+			}
+			String repoIds = (String)rawStat[1];
+			if(StringHelper.containsNonWhitespace(repoIds)) {
+				for(String repoId:repoIds.split(",")) {
+					entry.getRepoIds().add(repoId);
+				}
+			}
+			String launchIds = (String)rawStat[2];
+			if(StringHelper.containsNonWhitespace(launchIds)) {
+				for(String launchId:launchIds.split(",")) {
+					entry.getLaunchIds().add(launchId);
+				}
+			}
+			stats.put(entry.getStudentKey(), entry);
+		}
+		return rawList.size() > 0;
+	}
+	
+	private boolean getStudentsStatisticStatement(IdentityRef coach, Map<Long,StudentStatEntry> stats) {
+		NativeQueryBuilder sb = new NativeQueryBuilder(1024, dbInstance);
+		sb.append("select ")
+		  .append(" fin_statement.fk_identity, ")
+		  .append("  count(fin_statement.id), ")
+		  .append("  sum(case when fin_statement.passed=").appendTrue().append(" then 1 else 0 end) as num_of_passed, ")
+		  .append("  sum(case when fin_statement.passed=").appendFalse().append(" then 1 else 0 end) as num_of_failed ")
+		  .append(" from o_as_eff_statement fin_statement ")
+		  .append(" where fin_statement.id in ( select ")
+		  .append("   distinct sg_statement.id as st_id ")
+		  .append("  from o_repositoryentry sg_re ")
+		  .append("  inner join o_re_to_group togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id) ")
+		  .append("  inner join o_bs_group_member sg_coach on (sg_coach.fk_group_id=togroup.fk_group_id and sg_coach.g_role = 'coach') ")
+		  .append("  inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=sg_coach.fk_group_id and sg_participant.g_role='participant') ")
+		  .append("  inner join o_as_eff_statement sg_statement ")
+		  .append("    on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource) ")
+		  .append("  where sg_coach.fk_identity_id=:coachKey and ( ")
+		  .append("    (sg_re.accesscode>2 and sg_coach.g_role = 'coach') ")
+		  .append("    or ")
+		  .append("    (sg_re.accesscode=1 and sg_re.membersonly=").appendTrue().append(")) ")
+		  .append(" ) or fin_statement.id in ( select  ")
+		  .append("    distinct sg_statement.id as st_id ")
+		  .append("  from o_repositoryentry sg_re ")
+		  .append("  inner join o_re_to_group owngroup on (owngroup.fk_entry_id = sg_re.repositoryentry_id and owngroup.r_defgroup=").appendTrue().append(") ")
+		  .append("  inner join o_bs_group_member sg_owner on (sg_owner.fk_group_id=owngroup.fk_group_id and sg_owner.g_role = 'owner') ")
+		  .append("  inner join o_re_to_group togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id) ")
+		  .append("  inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=togroup.fk_group_id and sg_participant.g_role='participant') ")
+		  .append("  inner join o_as_eff_statement sg_statement ")
+		  .append("    on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource) ")
+		  .append("  where sg_owner.fk_identity_id=:coachKey and sg_re.accesscode>=").append(RepositoryEntry.ACC_OWNERS).append(") ")
+		  .append(" group by fin_statement.fk_identity");
+
+		List<?> rawList = dbInstance.getCurrentEntityManager()
+				.createNativeQuery(sb.toString())
+				.setParameter("coachKey", coach.getKey())
+				.getResultList();
+		
+		for(Object rawObject:rawList) {
+			Object[] rawStat = (Object[])rawObject;
+			Long identityKey = ((Number)rawStat[0]).longValue();
+			StudentStatEntry entry = stats.get(identityKey);
+			if(entry != null) {
+				int passed = ((Number)rawStat[2]).intValue();
+				int failed = ((Number)rawStat[3]).intValue();
+				entry.setCountPassed(passed);
+				entry.setCountFailed(failed);
+			}
+		}
+		return rawList.size() > 0;
+	}
+	
+	/**
+	 * Search all participants without restrictions on coach or owner relations.
+	 * 
+	 * @param params
+	 * @return The list of statistics
+	 */
+	protected List<StudentStatEntry> getUsersStatisticsNative(SearchCoachedIdentityParams params) {
+		Map<Long,StudentStatEntry> map = new HashMap<>();
+		boolean hasUsers = getUsersStatisticsInfos(params, map);
+		if(hasUsers) {
+			getUsersStatisticsStatements(params, map);
+		}
+		return new ArrayList<>(map.values());
+	}
+	
+	private boolean getUsersStatisticsInfos(SearchCoachedIdentityParams params, Map<Long, StudentStatEntry> map) {
+		NativeQueryBuilder sb = new NativeQueryBuilder(1024, dbInstance);
+		Map<String,String> queryParams = new HashMap<>();
+		sb.append("select ")
+		  .append(" sg_participant.fk_identity_id as part_id, ")
+		  .append("  count(distinct sg_re.repositoryentry_id) as re_count, ")
+		  .append("  count(distinct pg_initial_launch.id) as pg_id ")
+		  .append("  from o_repositoryentry sg_re ")
+		  .append(" inner join o_olatresource sg_res on (sg_res.resource_id = sg_re.fk_olatresource and sg_res.resname = 'CourseModule')")
+		  .append(" inner join o_re_to_group togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id) ")
+		  .append(" inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=togroup.fk_group_id and sg_participant.g_role='participant') ")
+		  .append(" inner join o_bs_identity id_participant on (sg_participant.fk_identity_id = id_participant.id) ")
+		  .append(" left join o_as_user_course_infos pg_initial_launch ")
+		  .append("   on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = id_participant.id) ")
+		  .append(" where sg_re.accesscode >= ").append(RepositoryEntry.ACC_OWNERS).append(" ");
+		appendUsersStatisticsSearchParams(params, queryParams, sb)
+		  .append(" group by sg_participant.fk_identity_id ");
+
+		Query query = dbInstance.getCurrentEntityManager().createNativeQuery(sb.toString());
+		for(Map.Entry<String, String> entry:queryParams.entrySet()) {
+			query.setParameter(entry.getKey(), entry.getValue());
+		}
+		
+		List<?> rawList = query.getResultList();
+		 
+		for(Object rawObject:rawList) {
+			Object[] rawStat = (Object[])rawObject;
+			Long identityKey = ((Number)rawStat[0]).longValue();
+			StudentStatEntry entry = new StudentStatEntry(identityKey);
 			entry.setCountRepo(((Number)rawStat[1]).intValue());
-			entry.setCountPassed(((Number)rawStat[2]).intValue());
-			entry.setCountFailed(((Number)rawStat[3]).intValue());
-			entry.setCountNotAttempted(((Number)rawStat[4]).intValue());
-			entry.setInitialLaunch(((Number)rawStat[5]).intValue());
-			stats.add(entry);
+			entry.setInitialLaunch(((Number)rawStat[2]).intValue());
+			map.put(identityKey, entry);
 		}
-		return stats;
+		return rawList.size() > 0;
 	}
 	
-	private List<Long> getIdentityKeys(List<? extends IdentityRef> identities) {
-		List<Long> identityKeys = new ArrayList<>(identities.size());
-		for(IdentityRef ref:identities) {
-			identityKeys.add(ref.getKey());
+	private boolean getUsersStatisticsStatements(SearchCoachedIdentityParams params, Map<Long,StudentStatEntry> map) {
+		NativeQueryBuilder sb = new NativeQueryBuilder(1024, dbInstance);
+		Map<String,String> queryParams = new HashMap<>();
+		sb.append("select ")
+		  .append(" fin_statement.fk_identity, ")
+		  .append(" sum(case when fin_statement.passed=").appendTrue().append(" then 1 else 0 end) as num_of_passed, ")
+		  .append(" sum(case when fin_statement.passed=").appendFalse().append(" then 1 else 0 end) as num_of_failed ")
+		  .append("from o_as_eff_statement fin_statement ")
+		  .append("where fin_statement.id in ( select ")
+		  .append("  distinct sg_statement.id as st_id ")
+		  .append(" from o_repositoryentry sg_re ")
+ 		  .append(" inner join o_re_to_group togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id) ")
+		  .append(" inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=togroup.fk_group_id and sg_participant.g_role='participant') ")
+		  .append(" inner join o_as_eff_statement sg_statement on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource) ")
+		  .append(" inner join o_bs_identity id_participant on (sg_participant.fk_identity_id = id_participant.id) ")
+		  .append(" where  sg_re.accesscode>0 ");
+		appendUsersStatisticsSearchParams(params, queryParams, sb)
+		  .append(") ")
+		  .append("group by fin_statement.fk_identity ");
+		
+		Query query = dbInstance.getCurrentEntityManager().createNativeQuery(sb.toString());
+		for(Map.Entry<String, String> entry:queryParams.entrySet()) {
+			query.setParameter(entry.getKey(), entry.getValue());
 		}
-		return identityKeys;
+		
+		List<?> rawList = query.getResultList();
+		for(Object rawObject:rawList) {
+			Object[] rawStat = (Object[])rawObject;
+			Long userKey = ((Number)rawStat[0]).longValue();
+			StudentStatEntry entry = map.get(userKey);
+			if(entry != null) {
+				int passed = ((Number)rawStat[1]).intValue();
+				int failed = ((Number)rawStat[2]).intValue();
+				entry.setCountPassed(passed);
+				entry.setCountFailed(failed);
+				int notAttempted = entry.getCountRepo() - passed - failed;
+				entry.setCountNotAttempted(notAttempted);
+			}
+		}
+		return rawList.size() > 0;
+	}
+	
+	private NativeQueryBuilder appendUsersStatisticsSearchParams(SearchCoachedIdentityParams params, Map<String,String> queryParams, NativeQueryBuilder sb) {
+		if(StringHelper.containsNonWhitespace(params.getLogin())) {
+			String login = PersistenceHelper.makeFuzzyQueryString(params.getLogin());
+			if (login.contains("_") && dbInstance.isOracle()) {
+				//oracle needs special ESCAPE sequence to search for escaped strings
+				sb.append(" and lower(id_participant.name) like :login ESCAPE '\\'");
+			} else if (dbInstance.isMySQL()) {
+				sb.append(" and id_participant.name like :login");
+			} else {
+				sb.append(" and lower(id_participant.name) like :login");
+			}
+			queryParams.put("login", login);
+		}
+		
+		if(params.getUserProperties() != null && params.getUserProperties().size() > 0) {
+			Map<String,String> searchParams = new HashMap<>(params.getUserProperties());
+	
+			int count = 0;
+			for(Map.Entry<String, String> entry:searchParams.entrySet()) {
+				String propName = entry.getKey();
+				String propValue = entry.getValue();
+				String qName = "p_" + ++count;
+	
+				sb.append(" and exists (select user").append(qName).append(".propvalue from o_userproperty user").append(qName)
+				  .append("  where user").append(qName).append(".fk_user_id=id_participant.fk_user_id ")
+				  .append("  and user").append(qName).append(".propname='").append(propName).append("' ");
+				
+				if(dbInstance.isMySQL()) {
+					sb.append(" and user").append(qName).append(".propvalue like :").append(qName).append(") ");
+				} else {
+					sb.append(" and lower(user").append(qName).append(".propvalue) like :").append(qName).append(") ");
+					if(dbInstance.isOracle()) {
+						sb.append(" escape '\\'");
+					}
+				}
+				queryParams.put(qName, PersistenceHelper.makeFuzzyQueryString(propValue));
+			}
+		}
+		return sb;
 	}
 	
 	public List<Long> getStudents(Identity coach, RepositoryEntry entry) {
-		StringBuilder sb = new StringBuilder();
-		sb.append("select distinct(participant.identity.key) from repoentrytogroup as relGroup ")
+		StringBuilder sc = new StringBuilder();
+		sc.append("select distinct(participant.identity.key) from repositoryentry as re")
+		  .append(" inner join re.groups as ownedRelGroup on ownedRelGroup.defaultGroup=true")
+		  .append(" inner join ownedRelGroup.group as ownedGroup")
+		  .append(" inner join ownedGroup.members as owner on owner.role='owner'")
+		  .append(" inner join re.groups as relGroup")
 		  .append(" inner join relGroup.group as baseGroup")
-		  .append(" inner join baseGroup.members as coach on coach.role='coach'")
 		  .append(" inner join baseGroup.members as participant on participant.role='participant'")
-          .append(" where coach.identity.key=:coachKey and relGroup.entry.key=:repoKey");
+          .append(" where owner.identity.key=:coachKey and re.key=:repoKey");
 
-		return dbInstance.getCurrentEntityManager()
-				.createQuery(sb.toString(), Long.class)
+		List<Long> identityKeys = dbInstance.getCurrentEntityManager()
+				.createQuery(sc.toString(), Long.class)
 				.setParameter("coachKey", coach.getKey())
 				.setParameter("repoKey", entry.getKey())
 				.getResultList();
+		
+		//owner see all participants
+		if(identityKeys.isEmpty()) {
+			StringBuilder sb = new StringBuilder();
+			sb.append("select distinct(participant.identity.key) from repoentrytogroup as relGroup ")
+			  .append(" inner join relGroup.group as baseGroup")
+			  .append(" inner join baseGroup.members as coach on coach.role = 'coach'")
+			  .append(" inner join baseGroup.members as participant on participant.role='participant'")
+	          .append(" where coach.identity.key=:coachKey and relGroup.entry.key=:repoKey");
+	
+			identityKeys = dbInstance.getCurrentEntityManager()
+					.createQuery(sb.toString(), Long.class)
+					.setParameter("coachKey", coach.getKey())
+					.setParameter("repoKey", entry.getKey())
+					.getResultList();
+		}
+		return identityKeys;
 	}
 
-	public List<RepositoryEntry> getStudentsCourses(Identity coach, Identity student, int firstResult, int maxResults) {
+	public List<RepositoryEntry> getStudentsCourses(Identity coach, Identity student) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select distinct(re) from ").append(RepositoryEntry.class.getName()).append(" as re ")
+		sb.append("select re from ").append(RepositoryEntry.class.getName()).append(" as re ")
+		  .append(" inner join re.olatResource res on res.resName='CourseModule'")
 		  .append(" inner join re.groups as relGroup ")
 		  .append(" inner join relGroup.group as baseGroup")
 		  .append(" inner join baseGroup.members as coach on coach.role='coach'")
 		  .append(" inner join baseGroup.members as participant on participant.role='participant'")
-		  .append(" where coach.identity.key=:coachKey and participant.identity.key=:studentKey");
+		  .append(" where coach.identity.key=:coachKey and participant.identity.key=:studentKey")
+		  .append(" and (re.access >= ").append(RepositoryEntry.ACC_USERS)
+		  .append("  or (re.access = ").append(RepositoryEntry.ACC_OWNERS).append(" and re.membersOnly=true))");
 
-		TypedQuery<RepositoryEntry> dbQuery = dbInstance.getCurrentEntityManager()
+		List<RepositoryEntry> coachedEntries = dbInstance.getCurrentEntityManager()
 				.createQuery(sb.toString(), RepositoryEntry.class)
 				.setParameter("coachKey", coach.getKey())
-				.setParameter("studentKey", student.getKey());
-		if(firstResult >= 0) {
-			dbQuery.setFirstResult(firstResult);
-		}
-		if(maxResults > 0) {
-			dbQuery.setMaxResults(maxResults);
-		}
+				.setParameter("studentKey", student.getKey())
+				.getResultList();
+		
+		StringBuilder sc = new StringBuilder();
+		sc.append("select re from ").append(RepositoryEntry.class.getName()).append(" as re ")
+		  .append(" inner join re.olatResource res on res.resName='CourseModule'")
+		  .append(" inner join re.groups as ownedRelGroup on ownedRelGroup.defaultGroup=true ")
+		  .append(" inner join ownedRelGroup.group as ownedGroup")
+		  .append(" inner join ownedGroup.members as owner on owner.role='owner'")
+		  .append(" inner join re.groups as relGroup")
+		  .append(" inner join relGroup.group as baseGroup")
+		  .append(" inner join baseGroup.members as participant on participant.role='participant'")
+		  .append(" where owner.identity.key=:coachKey and participant.identity.key=:studentKey")
+		  .append(" and re.access >= ").append(RepositoryEntry.ACC_OWNERS);
 
-		List<RepositoryEntry> courses = dbQuery.getResultList();
-		return courses;
+		List<RepositoryEntry> ownedEntries = dbInstance.getCurrentEntityManager()
+				.createQuery(sc.toString(), RepositoryEntry.class)
+				.setParameter("coachKey", coach.getKey())
+				.setParameter("studentKey", student.getKey())
+				.getResultList();
+		
+		Set<RepositoryEntry> uniqueRes = new HashSet<>(coachedEntries);
+		uniqueRes.addAll(ownedEntries);
+		return new ArrayList<>(uniqueRes);
 	}
 	
-	public List<RepositoryEntry> getUserCourses(IdentityRef student, int firstResult, int maxResults) {
+	public List<RepositoryEntry> getUserCourses(IdentityRef student) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select distinct(re) from ").append(RepositoryEntry.class.getName()).append(" as re ")
-		  .append(" inner join re.groups as relGroup ")
+		sb.append("select distinct(v) from ").append(RepositoryEntry.class.getName()).append(" as v ")
+		  .append(" inner join v.olatResource res on res.resName='CourseModule'")
+		  .append(" inner join v.groups as relGroup")
 		  .append(" inner join relGroup.group as baseGroup")
 		  .append(" inner join baseGroup.members as participant on participant.role='participant'")
-		  .append(" where participant.identity.key=:studentKey");
+		  .append(" where v.access >= ").append(RepositoryEntry.ACC_OWNERS).append(" and participant.identity.key=:studentKey");
 
-		TypedQuery<RepositoryEntry> dbQuery = dbInstance.getCurrentEntityManager()
+		return dbInstance.getCurrentEntityManager()
 				.createQuery(sb.toString(), RepositoryEntry.class)
-				.setParameter("studentKey", student.getKey());
-		if(firstResult >= 0) {
-			dbQuery.setFirstResult(firstResult);
-		}
-		if(maxResults > 0) {
-			dbQuery.setMaxResults(maxResults);
-		}
-
-		List<RepositoryEntry> courses = dbQuery.getResultList();
-		return courses;
+				.setParameter("studentKey", student.getKey())
+				.getResultList();
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/modules/coach/manager/CoachingServiceImpl.java b/src/main/java/org/olat/modules/coach/manager/CoachingServiceImpl.java
index 53cd7a5267c41103b5c702635a528b0078f93c77..0181eb68c5075cea8a543ea04e877e52ba83e5ed 100644
--- a/src/main/java/org/olat/modules/coach/manager/CoachingServiceImpl.java
+++ b/src/main/java/org/olat/modules/coach/manager/CoachingServiceImpl.java
@@ -19,15 +19,11 @@
  */
 package org.olat.modules.coach.manager;
 
-import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.GroupRoles;
-import org.olat.basesecurity.IdentityRef;
 import org.olat.basesecurity.IdentityShort;
 import org.olat.core.id.Identity;
 import org.olat.course.assessment.UserEfficiencyStatement;
@@ -37,6 +33,7 @@ import org.olat.modules.coach.CoachingService;
 import org.olat.modules.coach.model.CourseStatEntry;
 import org.olat.modules.coach.model.EfficiencyStatementEntry;
 import org.olat.modules.coach.model.GroupStatEntry;
+import org.olat.modules.coach.model.SearchCoachedIdentityParams;
 import org.olat.modules.coach.model.StudentStatEntry;
 import org.olat.repository.RepositoryEntry;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -68,47 +65,33 @@ public class CoachingServiceImpl implements CoachingService {
 	}
 
 	@Override
-	public Map<Long, String> getIdentities(Collection<Long> identityNames) {
-		Map<Long,String> identityMap = new HashMap<Long,String>();
-		
-		List<IdentityShort> identities = securityManager.findShortIdentitiesByKey(identityNames);
-		for(IdentityShort identity:identities) {
-			String fullName = identity.getFirstName()	+ " " + identity.getLastName();
-			identityMap.put(identity.getKey(), fullName);
-		}
-		return identityMap;
+	public List<RepositoryEntry> getStudentsCourses(Identity coach, Identity student) {
+		return coachingDao.getStudentsCourses(coach, student);
 	}
-
+	
 	@Override
-	public List<RepositoryEntry> getStudentsCourses(Identity coach, Identity student, int firstResult, int maxResults) {
-		return coachingDao.getStudentsCourses(coach, student, firstResult, maxResults);
+	public List<StudentStatEntry> getUsersStatistics(SearchCoachedIdentityParams params) {
+		return coachingDao.getUsersStatisticsNative(params);
 	}
 
 	@Override
 	public List<StudentStatEntry> getStudentsStatistics(Identity coach) {
-		return coachingDao.getStudentsStatistics(coach);
-	}
-	
-	
-
-	@Override
-	public List<StudentStatEntry> getUsersStatistics(List<? extends IdentityRef> identities) {
-		return coachingDao.getUsersStatistics(identities);
+		return coachingDao.getStudentsStatisticsNative(coach);
 	}
 
 	@Override
-	public List<RepositoryEntry> getUserCourses(Identity student, int firstResult, int maxResults) {
-		return coachingDao.getUserCourses(student, firstResult, maxResults);
+	public List<RepositoryEntry> getUserCourses(Identity student) {
+		return coachingDao.getUserCourses(student);
 	}
 
 	@Override
 	public List<CourseStatEntry> getCoursesStatistics(Identity coach) {
-		return coachingDao.getCoursesStatistics(coach);
+		return coachingDao.getCoursesStatisticsNative(coach);
 	}
 
 	@Override
 	public List<GroupStatEntry> getGroupsStatistics(Identity coach) {
-		return coachingDao.getGroupsStatistics(coach);
+		return coachingDao.getGroupsStatisticsNative(coach);
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/modules/coach/model/CourseStatEntry.java b/src/main/java/org/olat/modules/coach/model/CourseStatEntry.java
index 445b5d6b91580bf7d583aa1ab62339bdc92bf377..3bc1511b12042fd3237dc7ce374fe982b6d84841 100644
--- a/src/main/java/org/olat/modules/coach/model/CourseStatEntry.java
+++ b/src/main/java/org/olat/modules/coach/model/CourseStatEntry.java
@@ -30,13 +30,31 @@ public class CourseStatEntry {
 	private Long repoKey;
 	private String repoDisplayName;
 	private int countStudents;
-	private int countDistinctStudents;
 	private int countPassed;
 	private int countFailed;
 	private int countNotAttempted;
 	private Float averageScore;
 	private int initialLaunch;
 	
+	private double totalScore;
+	private int totalScoredStudents;
+	
+	public double getTotalScore() {
+		return totalScore;
+	}
+
+	public void setTotalScore(double totalScore) {
+		this.totalScore = totalScore;
+	}
+
+	public int getTotalScoredStudents() {
+		return totalScoredStudents;
+	}
+
+	public void setTotalScoredStudents(int totalScoredStudents) {
+		this.totalScoredStudents = totalScoredStudents;
+	}
+
 	public Long getRepoKey() {
 		return repoKey;
 	}
@@ -60,14 +78,6 @@ public class CourseStatEntry {
 	public void setCountStudents(int countStudents) {
 		this.countStudents = countStudents;
 	}
-	
-	public int getCountDistinctStudents() {
-		return countDistinctStudents;
-	}
-
-	public void setCountDistinctStudents(int countDistinctStudents) {
-		this.countDistinctStudents = countDistinctStudents;
-	}
 
 	public int getCountPassed() {
 		return countPassed;
@@ -108,23 +118,4 @@ public class CourseStatEntry {
 	public void setInitialLaunch(int initialLaunch) {
 		this.initialLaunch = initialLaunch;
 	}
-	
-	public void add(CourseStatEntry entry) {
-		countStudents += entry.getCountStudents();
-		countDistinctStudents += entry.getCountDistinctStudents();
-
-		float score1 = averageScore == null ? 0.0f : (averageScore * (countPassed + countFailed));
-		float score2 = entry.averageScore == null ? 0.0f : (entry.averageScore * (entry.countPassed + entry.countFailed));
-		float scores =  (score1 + score2);
-		if(scores <= 0.0f) {
-			averageScore = null;
-		} else {
-			averageScore = scores / (countPassed + countFailed + entry.countPassed + entry.countFailed);
-		}
-		
-		countPassed += entry.getCountPassed();
-		countFailed += entry.getCountFailed();
-		countNotAttempted += entry.getCountNotAttempted();
-		initialLaunch += entry.getInitialLaunch();
-	}
 }
diff --git a/src/main/java/org/olat/modules/coach/model/EfficiencyStatementCourseStatEntry.java b/src/main/java/org/olat/modules/coach/model/EfficiencyStatementCourseStatEntry.java
deleted file mode 100644
index 3facf38ae050c4bba6a1e52ab5282d4e032849cd..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/modules/coach/model/EfficiencyStatementCourseStatEntry.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.modules.coach.model;
-
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import javax.persistence.Table;
-
-/**
- * 
- * Initial date: 28.02.2014<br>
- * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
- *
- */
-@Entity
-@Table(name="o_as_eff_statement_courses_v")
-public class EfficiencyStatementCourseStatEntry {
-	
-	@Id
-	@Column(name="st_id", nullable=false, unique=true, insertable=false, updatable=false)
-	private Long statementKey;
-
-	@Column(name="re_id", nullable=false, unique=false, insertable=false, updatable=false)
-	private Long repoKey;
-
-	@Column(name="re_name", nullable=false, unique=false, insertable=false, updatable=false)
-	private String repoDisplayName;
-	
-	@Column(name="tutor_id", nullable=false, unique=false, insertable=false, updatable=false)
-	private Long tutorKey;
-	@Column(name="student_id", nullable=false, unique=false, insertable=false, updatable=false)
-	private Long studentKey;
-
-	@Column(name="st_score", nullable=false, unique=false, insertable=false, updatable=false)
-	private Float score;
-	@Column(name="st_passed", nullable=false, unique=false, insertable=false, updatable=false)
-	private int passed;
-	@Column(name="st_failed", nullable=false, unique=false, insertable=false, updatable=false)
-	private int failed;
-	@Column(name="st_not_attempted", nullable=false, unique=false, insertable=false, updatable=false)
-	private int notAttempted;
-
-	@Column(name="pg_id", nullable=false, unique=false, insertable=false, updatable=false)
-	private Long initialLaunchKey;
-
-	public Long getStatementKey() {
-		return statementKey;
-	}
-
-	public void setStatementKey(Long statementKey) {
-		this.statementKey = statementKey;
-	}
-
-	public Long getRepoKey() {
-		return repoKey;
-	}
-
-	public void setRepoKey(Long repoKey) {
-		this.repoKey = repoKey;
-	}
-
-	public String getRepoDisplayName() {
-		return repoDisplayName;
-	}
-
-	public void setRepoDisplayName(String repoDisplayName) {
-		this.repoDisplayName = repoDisplayName;
-	}
-
-	public Long getTutorKey() {
-		return tutorKey;
-	}
-
-	public void setTutorKey(Long tutorKey) {
-		this.tutorKey = tutorKey;
-	}
-
-	public Long getStudentKey() {
-		return studentKey;
-	}
-
-	public void setStudentKey(Long studentKey) {
-		this.studentKey = studentKey;
-	}
-
-	public Float getScore() {
-		return score;
-	}
-
-	public void setScore(Float score) {
-		this.score = score;
-	}
-
-	public int getPassed() {
-		return passed;
-	}
-
-	public void setPassed(int passed) {
-		this.passed = passed;
-	}
-
-	public int getFailed() {
-		return failed;
-	}
-
-	public void setFailed(int failed) {
-		this.failed = failed;
-	}
-
-	public int getNotAttempted() {
-		return notAttempted;
-	}
-
-	public void setNotAttempted(int notAttempted) {
-		this.notAttempted = notAttempted;
-	}
-
-	public Long getInitialLaunchKey() {
-		return initialLaunchKey;
-	}
-
-	public void setInitialLaunchKey(Long initialLaunchKey) {
-		this.initialLaunchKey = initialLaunchKey;
-	}
-}
diff --git a/src/main/java/org/olat/modules/coach/model/EfficiencyStatementGroupStatEntry.java b/src/main/java/org/olat/modules/coach/model/EfficiencyStatementGroupStatEntry.java
deleted file mode 100644
index 6183d14ded7344852363bf70a6c8c3c898fe41fd..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/modules/coach/model/EfficiencyStatementGroupStatEntry.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.modules.coach.model;
-
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import javax.persistence.Table;
-
-import org.olat.core.commons.persistence.PersistentObject;
-
-/**
- * The object is immutable
- * 
- * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
- */
-@Entity
-@Table(name="o_as_eff_statement_groups_v")
-public class EfficiencyStatementGroupStatEntry extends PersistentObject {
-
-	private static final long serialVersionUID = -5632894869497135693L;
-	
-	@Id
-	@Column(name="st_id", nullable=false, unique=true, insertable=false, updatable=false)
-	private Long statementKey;
-
-	@Column(name="re_id", nullable=false, unique=false, insertable=false, updatable=false)
-	private Long repoKey;
-	@Column(name="re_name", nullable=false, unique=false, insertable=false, updatable=false)
-	private String repoDisplayName;
-
-	@Column(name="bg_id", nullable=false, unique=false, insertable=false, updatable=false)
-	private Long groupKey;
-	@Column(name="bg_name", nullable=false, unique=false, insertable=false, updatable=false)
-	private String groupName;
-	
-	@Column(name="tutor_id", nullable=false, unique=false, insertable=false, updatable=false)
-	private Long tutorKey;
-	@Column(name="student_id", nullable=false, unique=false, insertable=false, updatable=false)
-	private Long studentKey;
-
-	@Column(name="st_score", nullable=false, unique=false, insertable=false, updatable=false)
-	private Float score;
-	@Column(name="st_passed", nullable=false, unique=false, insertable=false, updatable=false)
-	private int passed;
-	@Column(name="st_failed", nullable=false, unique=false, insertable=false, updatable=false)
-	private int failed;
-	@Column(name="st_not_attempted", nullable=false, unique=false, insertable=false, updatable=false)
-	private int notAttempted;
-
-	@Column(name="pg_id", nullable=false, unique=false, insertable=false, updatable=false)
-	private Long initialLaunchKey;
-	
-	public Long getRepoKey() {
-		return repoKey;
-	}
-	
-	public void setRepoKey(Long repoKey) {
-		this.repoKey = repoKey;
-	}
-	
-	public Long getGroupKey() {
-		return groupKey;
-	}
-
-	public void setGroupKey(Long groupKey) {
-		this.groupKey = groupKey;
-	}
-
-	public Long getStatementKey() {
-		return statementKey;
-	}
-
-	public void setStatementKey(Long statementKey) {
-		this.statementKey = statementKey;
-	}
-
-	public Long getTutorKey() {
-		return tutorKey;
-	}
-
-	public void setTutorKey(Long tutorKey) {
-		this.tutorKey = tutorKey;
-	}
-
-	public Long getStudentKey() {
-		return studentKey;
-	}
-
-	public void setStudentKey(Long studentKey) {
-		this.studentKey = studentKey;
-	}
-
-	public String getRepoDisplayName() {
-		return repoDisplayName;
-	}
-	
-	public void setRepoDisplayName(String repoDisplayName) {
-		this.repoDisplayName = repoDisplayName;
-	}
-	
-
-
-	public String getGroupName() {
-		return groupName;
-	}
-
-	public void setGroupName(String groupName) {
-		this.groupName = groupName;
-	}
-	
-	public Float getScore() {
-		return score;
-	}
-
-	public void setScore(Float score) {
-		this.score = score;
-	}
-
-	public int getPassed() {
-		return passed;
-	}
-
-	public void setPassed(int passed) {
-		this.passed = passed;
-	}
-
-	public int getFailed() {
-		return failed;
-	}
-
-	public void setFailed(int failed) {
-		this.failed = failed;
-	}
-
-	public int getNotAttempted() {
-		return notAttempted;
-	}
-
-	public void setNotAttempted(int notAttempted) {
-		this.notAttempted = notAttempted;
-	}
-
-	public Long getInitialLaunchKey() {
-		return initialLaunchKey;
-	}
-
-	public void setInitialLaunchKey(Long initialLaunchKey) {
-		this.initialLaunchKey = initialLaunchKey;
-	}
-
-	@Override
-	public String toString() {
-		StringBuilder sb = new StringBuilder();
-		sb.append("efficiencyStatementStatEntry[statementId=")
-		  .append(getKey()).append(":repositoryEntry=")
-		  .append(repoDisplayName).append(":tutorName=");
-		return sb.toString();
-	}
-
-	@Override
-	public boolean equals(Object obj) {
-		if(this == obj) {
-			return true;
-		}
-		return false;
-	}
-
-	@Override
-	public int hashCode() {
-		return super.hashCode();
-	}
-	
-	
-}
diff --git a/src/main/java/org/olat/modules/coach/model/EfficiencyStatementIdentityStatEntry.java b/src/main/java/org/olat/modules/coach/model/EfficiencyStatementIdentityStatEntry.java
deleted file mode 100644
index 030a97624804e211818e4ffb00a405ce1b268274..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/modules/coach/model/EfficiencyStatementIdentityStatEntry.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.modules.coach.model;
-
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import javax.persistence.Table;
-
-/**
- * 
- * Initial date: 28.02.2014<br>
- * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
- *
- */
-@Entity(name="coachstatisticsidentity")
-@Table(name="o_as_eff_statement_identity_v")
-public class EfficiencyStatementIdentityStatEntry {
-	
-	@Id
-	@Column(name="st_id", nullable=false, unique=true, insertable=false, updatable=false)
-	private Long statementKey;
-
-	@Column(name="re_id", nullable=false, unique=false, insertable=false, updatable=false)
-	private Long repoKey;
-	@Column(name="student_id", nullable=false, unique=false, insertable=false, updatable=false)
-	private Long studentKey;
-
-	@Column(name="st_score", nullable=false, unique=false, insertable=false, updatable=false)
-	private Float score;
-	@Column(name="st_passed", nullable=false, unique=false, insertable=false, updatable=false)
-	private int passed;
-	@Column(name="st_failed", nullable=false, unique=false, insertable=false, updatable=false)
-	private int failed;
-	@Column(name="st_not_attempted", nullable=false, unique=false, insertable=false, updatable=false)
-	private int notAttempted;
-
-	@Column(name="pg_id", nullable=false, unique=false, insertable=false, updatable=false)
-	private Long initialLaunchKey;
-
-	public Long getStatementKey() {
-		return statementKey;
-	}
-
-	public void setStatementKey(Long statementKey) {
-		this.statementKey = statementKey;
-	}
-
-	public Long getRepoKey() {
-		return repoKey;
-	}
-
-	public void setRepoKey(Long repoKey) {
-		this.repoKey = repoKey;
-	}
-
-	public Long getStudentKey() {
-		return studentKey;
-	}
-
-	public void setStudentKey(Long studentKey) {
-		this.studentKey = studentKey;
-	}
-
-	public Float getScore() {
-		return score;
-	}
-
-	public void setScore(Float score) {
-		this.score = score;
-	}
-
-	public int getPassed() {
-		return passed;
-	}
-
-	public void setPassed(int passed) {
-		this.passed = passed;
-	}
-
-	public int getFailed() {
-		return failed;
-	}
-
-	public void setFailed(int failed) {
-		this.failed = failed;
-	}
-
-	public int getNotAttempted() {
-		return notAttempted;
-	}
-
-	public void setNotAttempted(int notAttempted) {
-		this.notAttempted = notAttempted;
-	}
-
-	public Long getInitialLaunchKey() {
-		return initialLaunchKey;
-	}
-
-	public void setInitialLaunchKey(Long initialLaunchKey) {
-		this.initialLaunchKey = initialLaunchKey;
-	}
-}
diff --git a/src/main/java/org/olat/modules/coach/model/EfficiencyStatementStudentStatEntry.java b/src/main/java/org/olat/modules/coach/model/EfficiencyStatementStudentStatEntry.java
deleted file mode 100644
index c617eafe67139987fa379992401f38371ca9f52a..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/modules/coach/model/EfficiencyStatementStudentStatEntry.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.modules.coach.model;
-
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import javax.persistence.Table;
-
-/**
- * 
- * Initial date: 28.02.2014<br>
- * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
- *
- */
-@Entity
-@Table(name="o_as_eff_statement_students_v")
-public class EfficiencyStatementStudentStatEntry {
-	
-	@Id
-	@Column(name="st_id", nullable=false, unique=true, insertable=false, updatable=false)
-	private Long statementKey;
-
-	@Column(name="re_id", nullable=false, unique=false, insertable=false, updatable=false)
-	private Long repoKey;
-	@Column(name="tutor_id", nullable=false, unique=false, insertable=false, updatable=false)
-	private Long tutorKey;
-	@Column(name="student_id", nullable=false, unique=false, insertable=false, updatable=false)
-	private Long studentKey;
-
-	@Column(name="st_score", nullable=false, unique=false, insertable=false, updatable=false)
-	private Float score;
-	@Column(name="st_passed", nullable=false, unique=false, insertable=false, updatable=false)
-	private int passed;
-	@Column(name="st_failed", nullable=false, unique=false, insertable=false, updatable=false)
-	private int failed;
-	@Column(name="st_not_attempted", nullable=false, unique=false, insertable=false, updatable=false)
-	private int notAttempted;
-
-	@Column(name="pg_id", nullable=false, unique=false, insertable=false, updatable=false)
-	private Long initialLaunchKey;
-
-	public Long getStatementKey() {
-		return statementKey;
-	}
-
-	public void setStatementKey(Long statementKey) {
-		this.statementKey = statementKey;
-	}
-
-	public Long getRepoKey() {
-		return repoKey;
-	}
-
-	public void setRepoKey(Long repoKey) {
-		this.repoKey = repoKey;
-	}
-
-	public Long getTutorKey() {
-		return tutorKey;
-	}
-
-	public void setTutorKey(Long tutorKey) {
-		this.tutorKey = tutorKey;
-	}
-
-	public Long getStudentKey() {
-		return studentKey;
-	}
-
-	public void setStudentKey(Long studentKey) {
-		this.studentKey = studentKey;
-	}
-
-	public Float getScore() {
-		return score;
-	}
-
-	public void setScore(Float score) {
-		this.score = score;
-	}
-
-	public int getPassed() {
-		return passed;
-	}
-
-	public void setPassed(int passed) {
-		this.passed = passed;
-	}
-
-	public int getFailed() {
-		return failed;
-	}
-
-	public void setFailed(int failed) {
-		this.failed = failed;
-	}
-
-	public int getNotAttempted() {
-		return notAttempted;
-	}
-
-	public void setNotAttempted(int notAttempted) {
-		this.notAttempted = notAttempted;
-	}
-
-	public Long getInitialLaunchKey() {
-		return initialLaunchKey;
-	}
-
-	public void setInitialLaunchKey(Long initialLaunchKey) {
-		this.initialLaunchKey = initialLaunchKey;
-	}
-}
diff --git a/src/main/java/org/olat/modules/coach/model/GroupStatEntry.java b/src/main/java/org/olat/modules/coach/model/GroupStatEntry.java
index c2ef33018c7017103ef1ecec8383b6c6cddb588e..cd84cc340d2d531a574b86a7c9b1c7b1374dc244 100644
--- a/src/main/java/org/olat/modules/coach/model/GroupStatEntry.java
+++ b/src/main/java/org/olat/modules/coach/model/GroupStatEntry.java
@@ -19,6 +19,9 @@
  */
 package org.olat.modules.coach.model;
 
+import java.util.HashSet;
+import java.util.Set;
+
 /**
  * 
  * Dummy bean to transport statistic values about group
@@ -26,31 +29,40 @@ package org.olat.modules.coach.model;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
 public class GroupStatEntry {
-	// s.repoKey, 
-	private Long groupKey;
-	private String groupName;
-	private int countCourses;
-	private int countStudents;
-	private int countPassed;
-	private int countFailed;
-	private int countNotAttempted;
+
+	private final Long groupKey;
+	private final String groupName;
+	private int countCourses = 0;
+	private int countStudents = 0;
+	private int countDistinctStudents = 0;
+	private int countPassed = 0;
+	private int countFailed = 0;
+	private int countNotAttempted = 0;
 	private Float averageScore;
-	private int initialLaunch;
+	private double sumScore = 0.0d;
+	private int initialLaunch = 0;
+	
+	private Set<Long> repoIds = new HashSet<>();
+	
+	public GroupStatEntry(Long groupKey, String groupName) {
+		this.groupKey = groupKey;
+		this.groupName = groupName;
+	}
 	
 	public Long getGroupKey() {
 		return groupKey;
 	}
 
-	public void setGroupKey(Long groupKey) {
-		this.groupKey = groupKey;
-	}
-
 	public String getGroupName() {
 		return groupName;
 	}
 
-	public void setGroupName(String groupName) {
-		this.groupName = groupName;
+	public Set<Long> getRepoIds() {
+		return repoIds;
+	}
+
+	public void setRepoIds(Set<Long> repoIds) {
+		this.repoIds = repoIds;
 	}
 
 	public int getCountCourses() {
@@ -70,11 +82,11 @@ public class GroupStatEntry {
 	}
 	
 	public int getCountDistinctStudents() {
-		return countStudents;
+		return countDistinctStudents;
 	}
 	
-	public void setCountDistinctStudents(int countStudents) {
-		this.countStudents = countStudents;
+	public void setCountDistinctStudents(int countDistinctStudents) {
+		this.countDistinctStudents = countDistinctStudents;
 	}
 	
 	public int getCountPassed() {
@@ -109,6 +121,14 @@ public class GroupStatEntry {
 		this.averageScore = averageScore;
 	}
 
+	public double getSumScore() {
+		return sumScore;
+	}
+
+	public void setSumScore(double sumScore) {
+		this.sumScore = sumScore;
+	}
+
 	public int getInitialLaunch() {
 		return initialLaunch;
 	}
diff --git a/src/main/java/org/olat/modules/coach/model/SearchCoachedIdentityParams.java b/src/main/java/org/olat/modules/coach/model/SearchCoachedIdentityParams.java
new file mode 100644
index 0000000000000000000000000000000000000000..e8a944e56669a99131f1bc65c48d8bfdba4f4646
--- /dev/null
+++ b/src/main/java/org/olat/modules/coach/model/SearchCoachedIdentityParams.java
@@ -0,0 +1,50 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.coach.model;
+
+import java.util.Map;
+
+/**
+ * 
+ * Initial date: 02.02.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class SearchCoachedIdentityParams {
+	
+	private String login;
+	private Map<String,String> userProperties;
+	
+	public String getLogin() {
+		return login;
+	}
+	
+	public void setLogin(String login) {
+		this.login = login;
+	}
+	
+	public Map<String, String> getUserProperties() {
+		return userProperties;
+	}
+	
+	public void setUserProperties(Map<String, String> userProperties) {
+		this.userProperties = userProperties;
+	}
+}
diff --git a/src/main/java/org/olat/modules/coach/model/StudentStatEntry.java b/src/main/java/org/olat/modules/coach/model/StudentStatEntry.java
index 852cfa93a66a239be52fe630dc92f8eafe966151..1f481a6fc864bcb50a8eb7963351d19661d361dc 100644
--- a/src/main/java/org/olat/modules/coach/model/StudentStatEntry.java
+++ b/src/main/java/org/olat/modules/coach/model/StudentStatEntry.java
@@ -19,6 +19,9 @@
  */
 package org.olat.modules.coach.model;
 
+import java.util.HashSet;
+import java.util.Set;
+
 
 /**
  * 
@@ -28,26 +31,25 @@ package org.olat.modules.coach.model;
  */
 public class StudentStatEntry {
 	
-	private Long studentKey;
-	private int countRepo;
-	private int countPassed;
-	private int countFailed;
-	private int countNotAttempted;
-	private int initialLaunch;
+	private final Long studentKey;
+	private int countRepo = 0;
+	private int countPassed = 0;
+	private int countFailed = 0;
+	private int countNotAttempted = 0;
+	private int initialLaunch = 0;
+	
+	private Set<String> repoIds = new HashSet<>();
+	private Set<String> launchIds = new HashSet<>();
 	
 	
-	public StudentStatEntry() {
-		//
+	public StudentStatEntry(Long studentKey) {
+		this.studentKey = studentKey;
 	}
 
 	public Long getStudentKey() {
 		return studentKey;
 	}
 	
-	public void setStudentKey(Long studentKey) {
-		this.studentKey = studentKey;
-	}
-	
 	public int getCountRepo() {
 		return countRepo;
 	}
@@ -56,6 +58,22 @@ public class StudentStatEntry {
 		this.countRepo = countRepo;
 	}
 
+	public Set<String> getRepoIds() {
+		return repoIds;
+	}
+
+	public void setRepoIds(Set<String> repoIds) {
+		this.repoIds = repoIds;
+	}
+
+	public Set<String> getLaunchIds() {
+		return launchIds;
+	}
+
+	public void setLaunchIds(Set<String> launchIds) {
+		this.launchIds = launchIds;
+	}
+
 	public int getCountPassed() {
 		return countPassed;
 	}
@@ -87,12 +105,4 @@ public class StudentStatEntry {
 	public void setInitialLaunch(int initialLaunch) {
 		this.initialLaunch = initialLaunch;
 	}
-	
-	public void add(StudentStatEntry entry) {
-		countRepo += entry.getCountRepo();
-		countPassed += entry.getCountPassed();
-		countFailed += entry.getCountFailed();
-		countNotAttempted += entry.getCountNotAttempted();
-		initialLaunch += entry.getInitialLaunch();
-	}
 }
diff --git a/src/main/java/org/olat/modules/coach/ui/CourseListController.java b/src/main/java/org/olat/modules/coach/ui/CourseListController.java
index 27d4f274d1b1c3d839d88af4788f8b5cecbab5d5..7fdf1fd1e5aa5576c382d5564f422f6dda662978 100644
--- a/src/main/java/org/olat/modules/coach/ui/CourseListController.java
+++ b/src/main/java/org/olat/modules/coach/ui/CourseListController.java
@@ -21,7 +21,6 @@ package org.olat.modules.coach.ui;
 
 import java.util.List;
 
-import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.panel.Panel;
@@ -44,10 +43,10 @@ import org.olat.core.id.context.StateEntry;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.modules.coach.CoachingService;
 import org.olat.modules.coach.model.CourseStatEntry;
+import org.olat.modules.coach.ui.CoursesTableDataModel.Columns;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryManager;
-
-import org.olat.modules.coach.ui.CoursesTableDataModel.Columns;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
@@ -68,14 +67,13 @@ public class CourseListController extends BasicController implements Activateabl
 	
 	private boolean hasChanged = false;
 	
-	private final CoachingService coachingService;
-	private final RepositoryManager repositoryManager;
+	@Autowired
+	private CoachingService coachingService;
+	@Autowired
+	private RepositoryManager repositoryManager;
 	
 	public CourseListController(UserRequest ureq, WindowControl wControl) {
 		super(ureq, wControl);
-		
-		coachingService = CoreSpringFactory.getImpl(CoachingService.class);
-		repositoryManager = CoreSpringFactory.getImpl(RepositoryManager.class);
 
 		TableGuiConfiguration tableConfig = new TableGuiConfiguration();
 		tableConfig.setTableEmptyMessage(translate("error.no.found"));
diff --git a/src/main/java/org/olat/modules/coach/ui/CoursesTableDataModel.java b/src/main/java/org/olat/modules/coach/ui/CoursesTableDataModel.java
index ed5743b4d1f284db308c4167ec50a08402111c37..4c0e3093aabd41f85155667b6a247c83b65f11a5 100644
--- a/src/main/java/org/olat/modules/coach/ui/CoursesTableDataModel.java
+++ b/src/main/java/org/olat/modules/coach/ui/CoursesTableDataModel.java
@@ -63,10 +63,10 @@ public class CoursesTableDataModel implements TableDataModel<CourseStatEntry> {
 				return c.getRepoDisplayName();
 			}
 			case countStudents: {
-				return new Integer(c.getCountDistinctStudents());
+				return new Integer(c.getCountStudents());
 			}
 			case initialLaunch: {
-				int count = c.getCountDistinctStudents();
+				int count = c.getCountStudents();
 				if(count == 0) {
 					return new LightedValue("", Light.grey);
 				}
@@ -81,7 +81,7 @@ public class CoursesTableDataModel implements TableDataModel<CourseStatEntry> {
 				return new LightedValue(Integer.toString(launch), light);
 			}
 			case countPassed: {
-				int numOfStudents = c.getCountDistinctStudents();
+				int numOfStudents = c.getCountStudents();
 				if(numOfStudents == 0) {
 					return numOfStudents;
 				}
@@ -92,7 +92,7 @@ public class CoursesTableDataModel implements TableDataModel<CourseStatEntry> {
 				return val;
 			}
 			case countPassedLight: {
-				int count = c.getCountDistinctStudents();
+				int count = c.getCountStudents();
 				if(count == 0) {
 					return new LightedValue("", Light.grey);
 				}
diff --git a/src/main/java/org/olat/modules/coach/ui/StudentCoursesController.java b/src/main/java/org/olat/modules/coach/ui/StudentCoursesController.java
index 2b99c208f4412a9ae837d1b90404bf0647b61bba..8186cb1d8a1c376071439a1e7d4b37492c80141e 100644
--- a/src/main/java/org/olat/modules/coach/ui/StudentCoursesController.java
+++ b/src/main/java/org/olat/modules/coach/ui/StudentCoursesController.java
@@ -219,8 +219,8 @@ public class StudentCoursesController extends BasicController implements Activat
 	}
 	
 	private List<EfficiencyStatementEntry> loadModel() {
-		List<RepositoryEntry> courses = fullAccess ? coachingService.getUserCourses(student, 0, -1)
-				: coachingService.getStudentsCourses(getIdentity(), student, 0, -1);
+		List<RepositoryEntry> courses = fullAccess ? coachingService.getUserCourses(student)
+				: coachingService.getStudentsCourses(getIdentity(), student);
 		List<EfficiencyStatementEntry> statements = coachingService.getEfficencyStatements(student, courses);
 		
 		List<CertificateLight> certificates = certificatesManager.getLastCertificates(student);
diff --git a/src/main/java/org/olat/modules/coach/ui/StudentListController.java b/src/main/java/org/olat/modules/coach/ui/StudentListController.java
index 987f4fa195622ce807119f7b9ae3acbccb99025f..924874c41539fb15e01143362d9c629d7f19ecde 100644
--- a/src/main/java/org/olat/modules/coach/ui/StudentListController.java
+++ b/src/main/java/org/olat/modules/coach/ui/StudentListController.java
@@ -50,6 +50,7 @@ import org.olat.core.util.resource.OresHelper;
 import org.olat.modules.coach.CoachingService;
 import org.olat.modules.coach.model.StudentStatEntry;
 import org.olat.modules.coach.ui.StudentsTableDataModel.Columns;
+import org.olat.user.UserManager;
 import org.springframework.beans.factory.annotation.Autowired;
 
 /**
@@ -72,6 +73,9 @@ public class StudentListController extends BasicController implements Activateab
 	private boolean hasChanged;
 	
 	private final Map<Long,String> identityFullNameMap= new HashMap<Long,String>();
+	
+	@Autowired
+	private UserManager userManager;
 	@Autowired
 	private BaseSecurity securityManager;
 	@Autowired
@@ -111,14 +115,14 @@ public class StudentListController extends BasicController implements Activateab
 	
 	private void loadModel() {
 		List<StudentStatEntry> students = coachingService.getStudentsStatistics(getIdentity());
-		Set<Long> studentNames = new HashSet<Long>();
+		Set<Long> identityKeys = new HashSet<Long>();
 		for(StudentStatEntry student:students) {
 			if(!identityFullNameMap.containsKey(student.getStudentKey())) {
-				studentNames.add(student.getStudentKey());
+				identityKeys.add(student.getStudentKey());
 			}
 		}
-		if(!studentNames.isEmpty()) {
-			Map<Long,String> newIdentityFullNameMap = coachingService.getIdentities(studentNames);
+		if(!identityKeys.isEmpty()) {
+			Map<Long,String> newIdentityFullNameMap = userManager.getUserDisplayNamesByKey(identityKeys);
 			identityFullNameMap.putAll(newIdentityFullNameMap);
 		}
 		TableDataModel<StudentStatEntry> model = new StudentsTableDataModel(students, identityFullNameMap);
diff --git a/src/main/java/org/olat/modules/coach/ui/UserListController.java b/src/main/java/org/olat/modules/coach/ui/UserListController.java
index c477da66c58a6602e0b593a7e3779fa69bd1bd5e..d705285ee844e0c1f6bf07cae084f460da6a3ac4 100644
--- a/src/main/java/org/olat/modules/coach/ui/UserListController.java
+++ b/src/main/java/org/olat/modules/coach/ui/UserListController.java
@@ -25,7 +25,6 @@ import java.util.List;
 import java.util.Map;
 
 import org.olat.basesecurity.BaseSecurity;
-import org.olat.basesecurity.IdentityRef;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.link.Link;
@@ -46,13 +45,14 @@ import org.olat.core.gui.control.controller.BasicController;
 import org.olat.core.gui.control.generic.dtabs.Activateable2;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
-import org.olat.core.id.UserConstants;
 import org.olat.core.id.context.ContextEntry;
 import org.olat.core.id.context.StateEntry;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.modules.coach.CoachingService;
+import org.olat.modules.coach.model.SearchCoachedIdentityParams;
 import org.olat.modules.coach.model.StudentStatEntry;
 import org.olat.modules.coach.ui.StudentsTableDataModel.Columns;
+import org.olat.user.UserManager;
 import org.springframework.beans.factory.annotation.Autowired;
 
 /**
@@ -70,9 +70,11 @@ public class UserListController extends BasicController implements Activateable2
 	private StudentCoursesController studentCtrl;
 	
 	private boolean hasChanged;
-	private List<IdentityRef> identityRefs;
+	private SearchCoachedIdentityParams searchParams;
 	private final Map<Long,String> identityFullNameMap = new HashMap<Long,String>();
 	
+	@Autowired
+	private UserManager userManager;
 	@Autowired
 	private BaseSecurity securityManager;
 	@Autowired
@@ -118,19 +120,26 @@ public class UserListController extends BasicController implements Activateable2
 	}
 	
 	private void loadModel() {
-		List<StudentStatEntry> stats = coachingService.getUsersStatistics(identityRefs);
+		List<StudentStatEntry> stats = coachingService.getUsersStatistics(searchParams);
+		
+		List<Long> identityKeys = new ArrayList<>(stats.size());
+		for(StudentStatEntry entry:stats) {
+			Long identityKey = entry.getStudentKey();
+			if(!identityFullNameMap.containsKey(identityKey)) {
+				identityKeys.add(identityKey);
+			}
+		}
+		Map<Long,String> maps = userManager.getUserDisplayNamesByKey(identityKeys);
+		if(maps.size() > 0) {
+			identityFullNameMap.putAll(maps);
+		}
+		
 		TableDataModel<StudentStatEntry> model = new StudentsTableDataModel(stats, identityFullNameMap);
 		tableCtr.setTableDataModel(model);
 	}
 
-	public void loadModel(List<Identity> identities) {
-		List<IdentityRef> refs = new ArrayList<>(identities.size());
-		for(Identity identity:identities) {
-			String fullName = identity.getUser().getProperty(UserConstants.FIRSTNAME, getLocale()) + " " + identity.getUser().getProperty(UserConstants.LASTNAME, getLocale());
-			identityFullNameMap.put(identity.getKey(), fullName);
-			refs.add(new IdentityRefImpl(identity.getKey()));
-		}
-		identityRefs = refs;
+	public void search(SearchCoachedIdentityParams searchParams) {
+		this.searchParams = searchParams;
 		loadModel();
 	}
 
@@ -206,17 +215,4 @@ public class UserListController extends BasicController implements Activateable2
 		listenTo(studentCtrl);
 		content.setContent(studentCtrl.getInitialComponent());
 	}
-	
-	private static class IdentityRefImpl implements IdentityRef {
-		private final Long key;
-		
-		public IdentityRefImpl(Long key) {
-			this.key = key;
-		}
-		
-		@Override
-		public Long getKey() {
-			return key;
-		}
-	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/modules/coach/ui/UserSearchController.java b/src/main/java/org/olat/modules/coach/ui/UserSearchController.java
index 41fa0af3bf0bcedf74a833704736bb6f518e0efd..468e584bb2154b12afddd1f68aaaa175b0140007 100644
--- a/src/main/java/org/olat/modules/coach/ui/UserSearchController.java
+++ b/src/main/java/org/olat/modules/coach/ui/UserSearchController.java
@@ -19,11 +19,9 @@
  */
 package org.olat.modules.coach.ui;
 
-import java.util.List;
 import java.util.Map;
 
 import org.olat.basesecurity.BaseSecurity;
-import org.olat.basesecurity.SearchIdentityParams;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.panel.StackedPanel;
@@ -31,8 +29,8 @@ import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.BasicController;
-import org.olat.core.id.Identity;
 import org.olat.modules.coach.CoachingService;
+import org.olat.modules.coach.model.SearchCoachedIdentityParams;
 import org.springframework.beans.factory.annotation.Autowired;
 
 /**
@@ -92,19 +90,10 @@ public class UserSearchController extends BasicController {
 		String login = searchForm.getLogin();
 		Map<String,String> searchProps = searchForm.getSearchProperties();
 		
-		SearchIdentityParams params = new SearchIdentityParams();
+		SearchCoachedIdentityParams params = new SearchCoachedIdentityParams();
 		params.setLogin(login);
 		params.setUserProperties(searchProps);
-		params.setUserPropertiesAsIntersectionSearch(true);
-		params.setStatus(Identity.STATUS_VISIBLE_LIMIT);
-		
-		long count = securityManager.countIdentitiesByPowerSearch(params);
-		if(count > 501) {
-			showWarning("error.search.form.too.many");
-		} else {
-			List<Identity> identities = securityManager.getIdentitiesByPowerSearch(params, 0, 501);
-			userListCtrl.loadModel(identities);
-			mainPanel.pushContent(userListCtrl.getInitialComponent());
-		}
+		userListCtrl.search(params);
+		mainPanel.pushContent(userListCtrl.getInitialComponent());
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/repository/RepositoryManager.java b/src/main/java/org/olat/repository/RepositoryManager.java
index 7e15e2e783c0677a019731797c013a6d089230db..87b558ec2dad0939c46feecdd8d17ddc5dae3618 100644
--- a/src/main/java/org/olat/repository/RepositoryManager.java
+++ b/src/main/java/org/olat/repository/RepositoryManager.java
@@ -1200,7 +1200,7 @@ public class RepositoryManager extends BasicManager {
 	 * @param roles
 	 * @return
 	 */
-	public static boolean appendAccessSubSelects(StringBuilder sb, Identity identity, Roles roles) {
+	public static boolean appendAccessSubSelects(StringBuilder sb, IdentityRef identity, Roles roles) {
 		sb.append("(v.access >= ");
 		if (roles.isAuthor()) {
 			sb.append(RepositoryEntry.ACC_OWNERS_AUTHORS);
diff --git a/src/main/java/org/olat/repository/model/RepositoryEntryToGroupRelation.java b/src/main/java/org/olat/repository/model/RepositoryEntryToGroupRelation.java
index 543aedf8a4d4e8f1b262d06b07bb6345e2616af3..05e971af34edb461a6ee6c66b9a7fbda47758f1c 100644
--- a/src/main/java/org/olat/repository/model/RepositoryEntryToGroupRelation.java
+++ b/src/main/java/org/olat/repository/model/RepositoryEntryToGroupRelation.java
@@ -52,8 +52,6 @@ import org.olat.repository.RepositoryEntry;
 	@NamedQuery(name="relationByRepositoryEntryAndGroup",query="select rel from repoentrytogroup as rel where rel.entry.key=:repoKey and rel.group.key=:groupKey"),
 	@NamedQuery(name="relationByRepositoryEntry", query="select rel from repoentrytogroup as rel where rel.entry.key=:repoKey"),
 	@NamedQuery(name="relationByGroup", query="select rel from repoentrytogroup as rel where rel.group.key=:groupKey")
-	
-	
 })
 public class RepositoryEntryToGroupRelation implements Persistable {
 
diff --git a/src/main/java/org/olat/restapi/repository/course/CourseWebService.java b/src/main/java/org/olat/restapi/repository/course/CourseWebService.java
index f93ab74f3a0d98a8661d50c3050f23d85faf8e78..acc02d4334b70ea8e5cfa7fa8d23571588e5c508 100644
--- a/src/main/java/org/olat/restapi/repository/course/CourseWebService.java
+++ b/src/main/java/org/olat/restapi/repository/course/CourseWebService.java
@@ -86,6 +86,7 @@ import org.olat.restapi.security.RestSecurityHelper;
 import org.olat.restapi.support.ObjectFactory;
 import org.olat.restapi.support.vo.CourseConfigVO;
 import org.olat.restapi.support.vo.CourseVO;
+import org.olat.restapi.support.vo.OlatResourceVO;
 import org.olat.user.restapi.UserVO;
 import org.olat.user.restapi.UserVOFactory;
 
@@ -207,6 +208,17 @@ public class CourseWebService {
 		return Response.ok(vo).build();
 	}
 	
+	@GET
+	@Path("resource")
+	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+	public Response getOlatResource(@Context HttpServletRequest request) {
+		if(!isAuthor(request)) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+		OlatResourceVO vo = new OlatResourceVO(course);
+		return Response.ok(vo).build();
+	}
+	
 	/**
 	 * Export the course
 	 * @response.representation.200.mediaType application/zip
@@ -464,8 +476,6 @@ public class CourseWebService {
 		
 		RepositoryManager rm = RepositoryManager.getInstance();
 		RepositoryEntry repositoryEntry = rm.lookupRepositoryEntry(course, true);
-
-
 		RepositoryService repositoryService = CoreSpringFactory.getImpl(RepositoryService.class);
 		List<Identity> owners = repositoryService.getMembers(repositoryEntry, GroupRoles.owner.name());
 		
@@ -477,6 +487,27 @@ public class CourseWebService {
 		return Response.ok(authors).build();
 	}
 	
+	@GET
+	@Path("participants")
+	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+	public Response getParticipants(@Context HttpServletRequest httpRequest) {
+		if (!isAuthorEditor(course, httpRequest)) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+		
+		RepositoryManager rm = RepositoryManager.getInstance();
+		RepositoryEntry repositoryEntry = rm.lookupRepositoryEntry(course, true);
+		RepositoryService repositoryService = CoreSpringFactory.getImpl(RepositoryService.class);
+		List<Identity> participantList = repositoryService.getMembers(repositoryEntry, GroupRoles.participant.name());
+		
+		int count = 0;
+		UserVO[] participants = new UserVO[participantList.size()];
+		for(Identity participant:participantList) {
+			participants[count++] = UserVOFactory.get(participant);
+		}
+		return Response.ok(participants).build();
+	}
+	
 	/**
 	 * Get this specific author and owner of the course
 	 * @response.representation.200.qname {http://www.example.com}userVO
diff --git a/src/main/java/org/olat/restapi/support/vo/OlatResourceVO.java b/src/main/java/org/olat/restapi/support/vo/OlatResourceVO.java
new file mode 100644
index 0000000000000000000000000000000000000000..7a8feca979cd5ac275b8d4ef5f071a516481ca58
--- /dev/null
+++ b/src/main/java/org/olat/restapi/support/vo/OlatResourceVO.java
@@ -0,0 +1,96 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.restapi.support.vo;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.olat.course.ICourse;
+import org.olat.resource.OLATResource;
+
+/**
+ * 
+ * Initial date: 01.02.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlRootElement(name = "olatResourceVO")
+public class OlatResourceVO {
+	
+	private Long key;
+	private Long resourceableId;
+	private String resourceableTypeName;
+	
+	public OlatResourceVO() {
+		//
+	}
+	
+	public OlatResourceVO(ICourse course) {
+		OLATResource resource = course.getCourseEnvironment().getCourseGroupManager()
+				.getCourseEntry().getOlatResource();
+		
+		key = resource.getKey();
+		resourceableId = resource.getResourceableId();
+		resourceableTypeName = resource.getResourceableTypeName();
+	}
+	
+	public Long getKey() {
+		return key;
+	}
+	
+	public void setKey(Long key) {
+		this.key = key;
+	}
+
+	public Long getResourceableId() {
+		return resourceableId;
+	}
+
+	public void setResourceableId(Long resourceableId) {
+		this.resourceableId = resourceableId;
+	}
+
+	public String getResourceableTypeName() {
+		return resourceableTypeName;
+	}
+
+	public void setResourceableTypeName(String resourceableTypeName) {
+		this.resourceableTypeName = resourceableTypeName;
+	}
+
+	@Override
+	public String toString() {
+		return "OlatResourceVO[key=" + key + ":name=" + resourceableTypeName + "]";
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		if(obj == this) {
+			return true;
+		}
+		if(obj instanceof OlatResourceVO) {
+			OlatResourceVO vo = (OlatResourceVO)obj;
+			return key != null && key.equals(vo.key);
+		}
+		return false;
+	}
+}
diff --git a/src/main/resources/database/mysql/alter_10_1_0_to_10_2_0.sql b/src/main/resources/database/mysql/alter_10_1_0_to_10_2_0.sql
index 38d26bb720f280a951194e701a1b1e528b78a6c0..71ab8aefa04bfc277019b22c777e4fff7df6de94 100644
--- a/src/main/resources/database/mysql/alter_10_1_0_to_10_2_0.sql
+++ b/src/main/resources/database/mysql/alter_10_1_0_to_10_2_0.sql
@@ -56,3 +56,14 @@ alter table o_as_mode_course_to_area add constraint as_modetoarea_mode_idx forei
 
 
 alter table o_repositoryentry add column allowtoleave varchar(16);
+
+-- refactoring coaching (maybe test views)
+drop view if exists o_as_eff_statement_members_strict_v;
+drop view if exists o_as_eff_statement_grouped_v;
+drop view if exists o_as_eff_statement_members_v;
+drop view if exists o_as_eff_statement_identities_v;
+-- real ones
+drop view if exists o_as_eff_statement_identity_v;
+drop view if exists o_as_eff_statement_students_v;
+drop view if exists o_as_eff_statement_courses_v;
+drop view if exists o_as_eff_statement_groups_v;
diff --git a/src/main/resources/database/mysql/refreshViews.sql b/src/main/resources/database/mysql/refreshViews.sql
index 236663c1d2f7163e4ed2a0671b0f250c48dfe466..636bc6e409e504d0ccf1a87d65398410a41a5d48 100644
--- a/src/main/resources/database/mysql/refreshViews.sql
+++ b/src/main/resources/database/mysql/refreshViews.sql
@@ -1,3 +1,14 @@
+-- drop unused views
+drop view if exists o_as_eff_statement_members_strict_v;
+drop view if exists o_as_eff_statement_grouped_v;
+drop view if exists o_as_eff_statement_members_v;
+drop view if exists o_as_eff_statement_identities_v;
+drop view if exists o_as_eff_statement_identity_v;
+drop view if exists o_as_eff_statement_students_v;
+drop view if exists o_as_eff_statement_courses_v;
+drop view if exists o_as_eff_statement_groups_v;
+
+
 -- user view
 create or replace view o_bs_identity_short_v as (
    select
@@ -200,95 +211,6 @@ create or replace view o_gp_contactext_v as (
       (bgroup.participantsintern=true and bg_member.g_role='participant')
 );
 
--- coaching
-create or replace view o_as_eff_statement_identity_v as (
-   select
-      sg_re.repositoryentry_id as re_id,
-      sg_participant.fk_identity_id as student_id,
-      sg_statement.id as st_id,
-      (case when sg_statement.passed = 1 then 1 else 0 end) as st_passed,
-      (case when sg_statement.passed = 0 then 1 else 0 end) as st_failed,
-      (case when sg_statement.passed is null then 1 else 0 end) as st_not_attempted,
-      sg_statement.score as st_score,
-      pg_initial_launch.id as pg_id
-   from o_repositoryentry as sg_re
-   inner join o_re_to_group as togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id)
-   inner join o_bs_group_member as sg_participant on (sg_participant.fk_group_id=togroup.fk_group_id and sg_participant.g_role='participant')
-   left join o_as_eff_statement as sg_statement on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource)
-   left join o_as_user_course_infos as pg_initial_launch on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id)
-   group by sg_re.repositoryentry_id, sg_participant.fk_identity_id,
-      sg_statement.id, sg_statement.passed, sg_statement.score, pg_initial_launch.id
-);
-
-create or replace view o_as_eff_statement_students_v as (
-   select
-      sg_re.repositoryentry_id as re_id,
-      sg_coach.fk_identity_id as tutor_id,
-      sg_participant.fk_identity_id as student_id,
-      sg_statement.id as st_id,
-      (case when sg_statement.passed = 1 then 1 else 0 end) as st_passed,
-      (case when sg_statement.passed = 0 then 1 else 0 end) as st_failed,
-      (case when sg_statement.passed is null then 1 else 0 end) as st_not_attempted,
-      sg_statement.score as st_score,
-      pg_initial_launch.id as pg_id
-   from o_repositoryentry as sg_re
-   inner join o_re_to_group as togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id)
-   inner join o_bs_group_member as sg_coach on (sg_coach.fk_group_id=togroup.fk_group_id and sg_coach.g_role in ('owner','coach'))
-   inner join o_bs_group_member as sg_participant on (sg_participant.fk_group_id=sg_coach.fk_group_id and sg_participant.g_role='participant')
-   left join o_as_eff_statement as sg_statement on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource)
-   left join o_as_user_course_infos as pg_initial_launch on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id)
-   group by sg_re.repositoryentry_id, sg_coach.fk_identity_id, sg_participant.fk_identity_id,
-      sg_statement.id, sg_statement.passed, sg_statement.score, pg_initial_launch.id
-);
-
-create or replace view o_as_eff_statement_courses_v as (
-   select
-      sg_re.repositoryentry_id as re_id,
-      sg_re.displayname as re_name,
-      sg_coach.fk_identity_id as tutor_id,
-      sg_participant.fk_identity_id as student_id,
-      sg_statement.id as st_id,
-      (case when sg_statement.passed = 1 then 1 else 0 end) as st_passed,
-      (case when sg_statement.passed = 0 then 1 else 0 end) as st_failed,
-      (case when sg_statement.passed is null then 1 else 0 end) as st_not_attempted,
-      sg_statement.score as st_score,
-      pg_initial_launch.id as pg_id
-   from o_repositoryentry as sg_re
-   inner join o_re_to_group as togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id)
-   inner join o_bs_group_member as sg_coach on (sg_coach.fk_group_id=togroup.fk_group_id and sg_coach.g_role in ('owner','coach'))
-   inner join o_bs_group_member as sg_participant on (sg_participant.fk_group_id=sg_coach.fk_group_id and sg_participant.g_role='participant')
-   left join o_as_eff_statement as sg_statement on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource)
-   left join o_as_user_course_infos as pg_initial_launch on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id)
-   group by sg_re.repositoryentry_id, sg_re.displayname, sg_coach.fk_identity_id, sg_participant.fk_identity_id,
-      sg_statement.id, sg_statement.passed, sg_statement.score, pg_initial_launch.id
-);
-
-create or replace view o_as_eff_statement_groups_v as (
-   select
-      sg_re.repositoryentry_id as re_id,
-      sg_re.displayname as re_name,
-      sg_bg.group_id as bg_id,
-      sg_bg.groupname as bg_name,
-      sg_coach.fk_identity_id as tutor_id,
-      sg_participant.fk_identity_id as student_id,
-      sg_statement.id as st_id,
-      (case when sg_statement.passed = 1 then 1 else 0 end) as st_passed,
-      (case when sg_statement.passed = 0 then 1 else 0 end) as st_failed,
-      (case when sg_statement.passed is null then 1 else 0 end) as st_not_attempted,
-      sg_statement.score as st_score,
-      pg_initial_launch.id as pg_id
-   from o_repositoryentry as sg_re
-   inner join o_re_to_group as togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id)
-   inner join o_gp_business as sg_bg on (sg_bg.fk_group_id=togroup.fk_group_id)
-   inner join o_bs_group_member as sg_coach on (sg_coach.fk_group_id=togroup.fk_group_id and sg_coach.g_role in ('owner','coach'))
-   inner join o_bs_group_member as sg_participant on (sg_participant.fk_group_id=sg_coach.fk_group_id and sg_participant.g_role='participant')
-   left join o_as_eff_statement as sg_statement on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource)
-   left join o_as_user_course_infos as pg_initial_launch on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id)
-   group by sg_re.repositoryentry_id, sg_re.displayname, sg_bg.group_id, sg_bg.groupname,
-      sg_coach.fk_identity_id, sg_participant.fk_identity_id,
-      sg_statement.id, sg_statement.passed, sg_statement.score, pg_initial_launch.id
-);
-
 -- instant messaging
 create or replace view o_im_roster_entry_v as (
    select
diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql
index ac878825d8e63f0afb414966176a4b761978f8a6..2b23c942a732d8f1c7b2f6da0f4e1f8c90de1348 100644
--- a/src/main/resources/database/mysql/setupDatabase.sql
+++ b/src/main/resources/database/mysql/setupDatabase.sql
@@ -1568,94 +1568,6 @@ create view o_gp_contactext_v as (
       (bgroup.participantsintern=true and bg_member.g_role='participant')
 );
 
--- coaching
-create or replace view o_as_eff_statement_identity_v as (
-   select
-      sg_re.repositoryentry_id as re_id,
-      sg_participant.fk_identity_id as student_id,
-      sg_statement.id as st_id,
-      (case when sg_statement.passed = 1 then 1 else 0 end) as st_passed,
-      (case when sg_statement.passed = 0 then 1 else 0 end) as st_failed,
-      (case when sg_statement.passed is null then 1 else 0 end) as st_not_attempted,
-      sg_statement.score as st_score,
-      pg_initial_launch.id as pg_id
-   from o_repositoryentry as sg_re
-   inner join o_re_to_group as togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id)
-   inner join o_bs_group_member as sg_participant on (sg_participant.fk_group_id=togroup.fk_group_id and sg_participant.g_role='participant')
-   left join o_as_eff_statement as sg_statement on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource)
-   left join o_as_user_course_infos as pg_initial_launch on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id)
-   group by sg_re.repositoryentry_id, sg_participant.fk_identity_id,
-      sg_statement.id, sg_statement.passed, sg_statement.score, pg_initial_launch.id
-);
-
-create or replace view o_as_eff_statement_students_v as (
-   select
-      sg_re.repositoryentry_id as re_id,
-      sg_coach.fk_identity_id as tutor_id,
-      sg_participant.fk_identity_id as student_id,
-      sg_statement.id as st_id,
-      (case when sg_statement.passed = 1 then 1 else 0 end) as st_passed,
-      (case when sg_statement.passed = 0 then 1 else 0 end) as st_failed,
-      (case when sg_statement.passed is null then 1 else 0 end) as st_not_attempted,
-      sg_statement.score as st_score,
-      pg_initial_launch.id as pg_id
-   from o_repositoryentry as sg_re
-   inner join o_re_to_group as togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id)
-   inner join o_bs_group_member as sg_coach on (sg_coach.fk_group_id=togroup.fk_group_id and sg_coach.g_role in ('owner','coach'))
-   inner join o_bs_group_member as sg_participant on (sg_participant.fk_group_id=sg_coach.fk_group_id and sg_participant.g_role='participant')
-   left join o_as_eff_statement as sg_statement on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource)
-   left join o_as_user_course_infos as pg_initial_launch on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id)
-   group by sg_re.repositoryentry_id, sg_coach.fk_identity_id, sg_participant.fk_identity_id,
-      sg_statement.id, sg_statement.passed, sg_statement.score, pg_initial_launch.id
-);
-
-create or replace view o_as_eff_statement_courses_v as (
-   select
-      sg_re.repositoryentry_id as re_id,
-      sg_re.displayname as re_name,
-      sg_coach.fk_identity_id as tutor_id,
-      sg_participant.fk_identity_id as student_id,
-      sg_statement.id as st_id,
-      (case when sg_statement.passed = 1 then 1 else 0 end) as st_passed,
-      (case when sg_statement.passed = 0 then 1 else 0 end) as st_failed,
-      (case when sg_statement.passed is null then 1 else 0 end) as st_not_attempted,
-      sg_statement.score as st_score,
-      pg_initial_launch.id as pg_id
-   from o_repositoryentry as sg_re
-   inner join o_re_to_group as togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id)
-   inner join o_bs_group_member as sg_coach on (sg_coach.fk_group_id=togroup.fk_group_id and sg_coach.g_role in ('owner','coach'))
-   inner join o_bs_group_member as sg_participant on (sg_participant.fk_group_id=sg_coach.fk_group_id and sg_participant.g_role='participant')
-   left join o_as_eff_statement as sg_statement on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource)
-   left join o_as_user_course_infos as pg_initial_launch on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id)
-   group by sg_re.repositoryentry_id, sg_re.displayname, sg_coach.fk_identity_id, sg_participant.fk_identity_id,
-      sg_statement.id, sg_statement.passed, sg_statement.score, pg_initial_launch.id
-);
-
-create or replace view o_as_eff_statement_groups_v as (
-   select
-      sg_re.repositoryentry_id as re_id,
-      sg_re.displayname as re_name,
-      sg_bg.group_id as bg_id,
-      sg_bg.groupname as bg_name,
-      sg_coach.fk_identity_id as tutor_id,
-      sg_participant.fk_identity_id as student_id,
-      sg_statement.id as st_id,
-      (case when sg_statement.passed = 1 then 1 else 0 end) as st_passed,
-      (case when sg_statement.passed = 0 then 1 else 0 end) as st_failed,
-      (case when sg_statement.passed is null then 1 else 0 end) as st_not_attempted,
-      sg_statement.score as st_score,
-      pg_initial_launch.id as pg_id
-   from o_repositoryentry as sg_re
-   inner join o_re_to_group as togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id)
-   inner join o_gp_business as sg_bg on (sg_bg.fk_group_id=togroup.fk_group_id)
-   inner join o_bs_group_member as sg_coach on (sg_coach.fk_group_id=togroup.fk_group_id and sg_coach.g_role in ('owner','coach'))
-   inner join o_bs_group_member as sg_participant on (sg_participant.fk_group_id=sg_coach.fk_group_id and sg_participant.g_role='participant')
-   left join o_as_eff_statement as sg_statement on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource)
-   left join o_as_user_course_infos as pg_initial_launch on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id)
-   group by sg_re.repositoryentry_id, sg_re.displayname, sg_bg.group_id, sg_bg.groupname,
-      sg_coach.fk_identity_id, sg_participant.fk_identity_id,
-      sg_statement.id, sg_statement.passed, sg_statement.score, pg_initial_launch.id
-);
 
 -- instant messaging
 create or replace view o_im_roster_entry_v as (
diff --git a/src/main/resources/database/oracle/alter_10_1_0_to_10_2_0.sql b/src/main/resources/database/oracle/alter_10_1_0_to_10_2_0.sql
index 4ea7d27979dcf4fdb5864be862dc99fd0d420982..d0dcb35f39b8733bbd9b553a9b91d1ee68887e1c 100644
--- a/src/main/resources/database/oracle/alter_10_1_0_to_10_2_0.sql
+++ b/src/main/resources/database/oracle/alter_10_1_0_to_10_2_0.sql
@@ -54,4 +54,11 @@ create index idx_as_modetoarea_area_idx on o_as_mode_course_to_area (fk_area_id)
 create index idx_as_modetoarea_mode_idx on o_as_mode_course_to_area (fk_assessment_mode_id);
 
 
-alter table o_repositoryentry add allowtoleave varchar2(16 char);
\ No newline at end of file
+alter table o_repositoryentry add allowtoleave varchar2(16 char);
+
+
+-- refactoring coaching
+drop view o_as_eff_statement_identity_v;
+drop view o_as_eff_statement_students_v;
+drop view o_as_eff_statement_courses_v;
+drop view o_as_eff_statement_groups_v;
\ No newline at end of file
diff --git a/src/main/resources/database/oracle/setupDatabase.sql b/src/main/resources/database/oracle/setupDatabase.sql
index a32cdb8d57d090f4a43a182467e653f62bb7313b..687497f4af938c142c85990198960229ae97622b 100644
--- a/src/main/resources/database/oracle/setupDatabase.sql
+++ b/src/main/resources/database/oracle/setupDatabase.sql
@@ -1620,93 +1620,6 @@ create view o_gp_contactext_v as (
       (bgroup.participantsintern>0 and bg_member.g_role='participant')
 );
 
-create view o_as_eff_statement_identity_v as (
-   select
-      sg_re.repositoryentry_id as re_id,
-      sg_participant.fk_identity_id as student_id,
-      sg_statement.id as st_id,
-      (case when sg_statement.passed = 1 then 1 else 0 end) as st_passed,
-      (case when sg_statement.passed = 0 then 1 else 0 end) as st_failed,
-      (case when sg_statement.passed is null then 1 else 0 end) as st_not_attempted,
-      sg_statement.score as st_score,
-      pg_initial_launch.id as pg_id
-   from o_repositoryentry sg_re
-   inner join o_re_to_group togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id)
-   inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=togroup.fk_group_id and sg_participant.g_role='participant')
-   left join o_as_eff_statement sg_statement on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource)
-   left join o_as_user_course_infos pg_initial_launch on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id)
-   group by sg_re.repositoryentry_id, sg_participant.fk_identity_id,
-      sg_statement.passed, sg_statement.id, sg_statement.score, pg_initial_launch.id
-);
-
-create view o_as_eff_statement_students_v as (
-   select
-      sg_re.repositoryentry_id as re_id,
-      sg_coach.fk_identity_id as tutor_id,
-      sg_participant.fk_identity_id as student_id,
-      sg_statement.id as st_id,
-      (case when sg_statement.passed > 0 then 1 else 0 end) as st_passed,
-      (case when sg_statement.passed = 0 then 1 else 0 end) as st_failed,
-      (case when sg_statement.passed is null then 1 else 0 end) as st_not_attempted,
-      sg_statement.score as st_score,
-      pg_initial_launch.id as pg_id
-   from o_repositoryentry sg_re
-   inner join o_re_to_group togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id)
-   inner join o_bs_group_member sg_coach on (sg_coach.fk_group_id=togroup.fk_group_id and sg_coach.g_role in ('owner','coach'))
-   inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=sg_coach.fk_group_id and sg_participant.g_role='participant')
-   left join o_as_eff_statement sg_statement on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource)
-   left join o_as_user_course_infos pg_initial_launch on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id)
-   group by sg_re.repositoryentry_id, sg_coach.fk_identity_id, sg_participant.fk_identity_id,
-      sg_statement.passed, sg_statement.id, sg_statement.score, pg_initial_launch.id
-);
-
-create view o_as_eff_statement_courses_v as (
-   select
-      sg_re.repositoryentry_id as re_id,
-      sg_re.displayname as re_name,
-      sg_coach.fk_identity_id as tutor_id,
-      sg_participant.fk_identity_id as student_id,
-      sg_statement.id as st_id,
-      (case when sg_statement.passed > 0 then 1 else 0 end) as st_passed,
-      (case when sg_statement.passed = 0 then 1 else 0 end) as st_failed,
-      (case when sg_statement.passed is null then 1 else 0 end) as st_not_attempted,
-      sg_statement.score as st_score,
-      pg_initial_launch.id as pg_id
-   from o_repositoryentry sg_re
-   inner join o_re_to_group togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id)
-   inner join o_bs_group_member sg_coach on (sg_coach.fk_group_id=togroup.fk_group_id and sg_coach.g_role in ('owner','coach'))
-   inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=sg_coach.fk_group_id and sg_participant.g_role='participant')
-   left join o_as_eff_statement sg_statement on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource)
-   left join o_as_user_course_infos pg_initial_launch on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id)
-   group by sg_re.repositoryentry_id, sg_re.displayname, sg_coach.fk_identity_id, sg_participant.fk_identity_id,
-      sg_statement.passed, sg_statement.id, sg_statement.score, pg_initial_launch.id
-);
-
-create view o_as_eff_statement_groups_v as (
-   select
-      sg_re.repositoryentry_id as re_id,
-      sg_re.displayname as re_name,
-      sg_bg.group_id as bg_id,
-      sg_bg.groupname as bg_name,
-      sg_coach.fk_identity_id as tutor_id,
-      sg_participant.fk_identity_id as student_id,
-      sg_statement.id as st_id,
-      (case when sg_statement.passed > 0 then 1 else 0 end) as st_passed,
-      (case when sg_statement.passed = 0 then 1 else 0 end) as st_failed,
-      (case when sg_statement.passed is null then 1 else 0 end) as st_not_attempted,
-      sg_statement.score as st_score,
-      pg_initial_launch.id as pg_id
-   from o_repositoryentry sg_re
-   inner join o_re_to_group togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id)
-   inner join o_gp_business sg_bg on (sg_bg.fk_group_id=togroup.fk_group_id)
-   inner join o_bs_group_member sg_coach on (sg_coach.fk_group_id=togroup.fk_group_id and sg_coach.g_role in ('owner','coach'))
-   inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=sg_coach.fk_group_id and sg_participant.g_role='participant')
-   left join o_as_eff_statement sg_statement on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource)
-   left join o_as_user_course_infos pg_initial_launch on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id)
-   group by sg_re.repositoryentry_id, sg_re.displayname, sg_bg.group_id, sg_bg.groupname,
-      sg_coach.fk_identity_id, sg_participant.fk_identity_id,
-      sg_statement.passed, sg_statement.id, sg_statement.score, pg_initial_launch.id
-);
 
 create or replace view o_im_roster_entry_v as (
    select
diff --git a/src/main/resources/database/postgresql/alter_10_1_0_to_10_2_0.sql b/src/main/resources/database/postgresql/alter_10_1_0_to_10_2_0.sql
index d241ba99af0b10f5a335df29eded8b44fbd80284..768a4c5520c6b646acaf91474c3d7cd31bef0263 100644
--- a/src/main/resources/database/postgresql/alter_10_1_0_to_10_2_0.sql
+++ b/src/main/resources/database/postgresql/alter_10_1_0_to_10_2_0.sql
@@ -54,4 +54,10 @@ create index idx_as_modetoarea_area_idx on o_as_mode_course_to_area (fk_area_id)
 create index idx_as_modetoarea_mode_idx on o_as_mode_course_to_area (fk_assessment_mode_id);
 
 
-alter table o_repositoryentry add column allowtoleave varchar(16);
\ No newline at end of file
+alter table o_repositoryentry add column allowtoleave varchar(16);
+
+-- refactoring coaching
+drop view if exists o_as_eff_statement_identity_v;
+drop view if exists o_as_eff_statement_students_v;
+drop view if exists o_as_eff_statement_courses_v;
+drop view if exists o_as_eff_statement_groups_v;
\ No newline at end of file
diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql
index c49b999046a89c453c19da5dc8489aeb027f1173..d23214d2bd3886cc4c9f38137161e39c2e1e0a16 100644
--- a/src/main/resources/database/postgresql/setupDatabase.sql
+++ b/src/main/resources/database/postgresql/setupDatabase.sql
@@ -1569,94 +1569,6 @@ create view o_gp_contactext_v as (
       (bgroup.participantsintern=true and bg_member.g_role='participant')
 );
 
--- coaching
-create view o_as_eff_statement_identity_v as (
-   select
-      sg_re.repositoryentry_id as re_id,
-      sg_participant.fk_identity_id as student_id,
-      sg_statement.id as st_id,
-      (case when sg_statement.passed = true then 1 else 0 end) as st_passed,
-      (case when sg_statement.passed = false then 1 else 0 end) as st_failed,
-      (case when sg_statement.passed is null then 1 else 0 end) as st_not_attempted,
-      sg_statement.score as st_score,
-      pg_initial_launch.id as pg_id
-   from o_repositoryentry as sg_re
-   inner join o_re_to_group as togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id)
-   inner join o_bs_group_member as sg_participant on (sg_participant.fk_group_id=togroup.fk_group_id and sg_participant.g_role='participant')
-   left join o_as_eff_statement as sg_statement on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource)
-   left join o_as_user_course_infos as pg_initial_launch on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id)
-   group by sg_re.repositoryentry_id, sg_participant.fk_identity_id,
-      sg_statement.id, sg_statement.passed, sg_statement.score, pg_initial_launch.id
-);
-
-create view o_as_eff_statement_students_v as (
-   select
-      sg_re.repositoryentry_id as re_id,
-      sg_coach.fk_identity_id as tutor_id,
-      sg_participant.fk_identity_id as student_id,
-      sg_statement.id as st_id,
-      (case when sg_statement.passed = true then 1 else 0 end) as st_passed,
-      (case when sg_statement.passed = false then 1 else 0 end) as st_failed,
-      (case when sg_statement.passed is null then 1 else 0 end) as st_not_attempted,
-      sg_statement.score as st_score,
-      pg_initial_launch.id as pg_id
-   from o_repositoryentry as sg_re
-   inner join o_re_to_group as togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id)
-   inner join o_bs_group_member as sg_coach on (sg_coach.fk_group_id=togroup.fk_group_id and sg_coach.g_role in ('owner','coach'))
-   inner join o_bs_group_member as sg_participant on (sg_participant.fk_group_id=sg_coach.fk_group_id and sg_participant.g_role='participant')
-   left join o_as_eff_statement as sg_statement on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource)
-   left join o_as_user_course_infos as pg_initial_launch on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id)
-   group by sg_re.repositoryentry_id, sg_coach.fk_identity_id, sg_participant.fk_identity_id,
-      sg_statement.id, sg_statement.passed, sg_statement.score, pg_initial_launch.id
-);
-
-create view o_as_eff_statement_courses_v as (
-   select
-      sg_re.repositoryentry_id as re_id,
-      sg_re.displayname as re_name,
-      sg_coach.fk_identity_id as tutor_id,
-      sg_participant.fk_identity_id as student_id,
-      sg_statement.id as st_id,
-      (case when sg_statement.passed = true then 1 else 0 end) as st_passed,
-      (case when sg_statement.passed = false then 1 else 0 end) as st_failed,
-      (case when sg_statement.passed is null then 1 else 0 end) as st_not_attempted,
-      sg_statement.score as st_score,
-      pg_initial_launch.id as pg_id
-   from o_repositoryentry as sg_re
-   inner join o_re_to_group as togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id)
-   inner join o_bs_group_member as sg_coach on (sg_coach.fk_group_id=togroup.fk_group_id and sg_coach.g_role in ('owner','coach'))
-   inner join o_bs_group_member as sg_participant on (sg_participant.fk_group_id=sg_coach.fk_group_id and sg_participant.g_role='participant')
-   left join o_as_eff_statement as sg_statement on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource)
-   left join o_as_user_course_infos as pg_initial_launch on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id)
-   group by sg_re.repositoryentry_id, sg_re.displayname, sg_coach.fk_identity_id, sg_participant.fk_identity_id,
-      sg_statement.id, sg_statement.passed, sg_statement.score, pg_initial_launch.id
-);
-
-create view o_as_eff_statement_groups_v as (
-   select
-      sg_re.repositoryentry_id as re_id,
-      sg_re.displayname as re_name,
-      sg_bg.group_id as bg_id,
-      sg_bg.groupname as bg_name,
-      sg_coach.fk_identity_id as tutor_id,
-      sg_participant.fk_identity_id as student_id,
-      sg_statement.id as st_id,
-      (case when sg_statement.passed = true then 1 else 0 end) as st_passed,
-      (case when sg_statement.passed = false then 1 else 0 end) as st_failed,
-      (case when sg_statement.passed is null then 1 else 0 end) as st_not_attempted,
-      sg_statement.score as st_score,
-      pg_initial_launch.id as pg_id
-   from o_repositoryentry as sg_re
-   inner join o_re_to_group as togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id)
-   inner join o_gp_business as sg_bg on (sg_bg.fk_group_id=togroup.fk_group_id)
-   inner join o_bs_group_member as sg_coach on (sg_coach.fk_group_id=togroup.fk_group_id and sg_coach.g_role in ('owner','coach'))
-   inner join o_bs_group_member as sg_participant on (sg_participant.fk_group_id=sg_coach.fk_group_id and sg_participant.g_role='participant')
-   left join o_as_eff_statement as sg_statement on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource)
-   left join o_as_user_course_infos as pg_initial_launch on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id)
-   group by sg_re.repositoryentry_id, sg_re.displayname, sg_bg.group_id, sg_bg.groupname,
-      sg_coach.fk_identity_id, sg_participant.fk_identity_id,
-      sg_statement.id, sg_statement.passed, sg_statement.score, pg_initial_launch.id
-);
 
 -- instant messaging
 create or replace view o_im_roster_entry_v as (
diff --git a/src/test/java/org/olat/modules/coach/CoachingDAOTest.java b/src/test/java/org/olat/modules/coach/CoachingDAOTest.java
deleted file mode 100644
index ae8b7376a095b012ba6b2f3bb4fbdba0ca6dfa5e..0000000000000000000000000000000000000000
--- a/src/test/java/org/olat/modules/coach/CoachingDAOTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.modules.coach;
-
-import java.io.File;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.util.List;
-import java.util.UUID;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.olat.basesecurity.GroupRoles;
-import org.olat.core.commons.persistence.DB;
-import org.olat.core.id.Identity;
-import org.olat.course.CourseFactory;
-import org.olat.course.ICourse;
-import org.olat.modules.coach.manager.CoachingDAO;
-import org.olat.modules.coach.model.StudentStatEntry;
-import org.olat.repository.RepositoryEntry;
-import org.olat.repository.RepositoryService;
-import org.olat.test.JunitTestHelper;
-import org.olat.test.OlatTestCase;
-import org.springframework.beans.factory.annotation.Autowired;
-
-/**
- * 
- * Initial date: 24.07.2014<br>
- * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
- *
- */
-public class CoachingDAOTest extends OlatTestCase {
-	
-	@Autowired
-	private DB dbInstance;
-	@Autowired
-	private CoachingDAO coachingDAO;
-	@Autowired
-	private RepositoryService repositoryService;
-	
-	@Test
-	public void getStudents()
-	throws URISyntaxException {
-		URL courseWithForumsUrl = CoachingDAOTest.class.getResource("CoachingCourse.zip");
-		File courseWithForums = new File(courseWithForumsUrl.toURI());
-		String softKey = UUID.randomUUID().toString();
-		RepositoryEntry re = CourseFactory.deployCourseFromZIP(courseWithForums, softKey, 4);
-		Assert.assertNotNull(re);
-
-		dbInstance.commitAndCloseSession();
-		
-		ICourse course = CourseFactory.loadCourse(re.getOlatResource().getResourceableId());			
-		boolean enabled =course.getCourseEnvironment().getCourseConfig().isEfficencyStatementEnabled();
-		Assert.assertTrue(enabled);
-		
-		Identity coach = JunitTestHelper.createAndPersistIdentityAsAuthor("Coach-1-" + UUID.randomUUID());
-		repositoryService.addRole(coach, re, GroupRoles.coach.name());
-		Identity participant1 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-1");
-		repositoryService.addRole(participant1, re, GroupRoles.participant.name());
-		Identity participant2 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-2");
-		repositoryService.addRole(participant2, re, GroupRoles.participant.name());
-		dbInstance.commitAndCloseSession();
-		
-		
-		List<StudentStatEntry> stats = coachingDAO.getStudentsStatistics(coach);
-		Assert.assertNotNull(stats);
-		Assert.assertEquals(2, stats.size());
-	}
-
-}
diff --git a/src/test/java/org/olat/modules/coach/CoachingServiceTest.java b/src/test/java/org/olat/modules/coach/CoachingLargeTest.java
similarity index 77%
rename from src/test/java/org/olat/modules/coach/CoachingServiceTest.java
rename to src/test/java/org/olat/modules/coach/CoachingLargeTest.java
index 8726a3316befca800de3f8351c019ee02a85f59b..8ad875c5898bbe8d703fa7fef328952295aa2dc9 100644
--- a/src/test/java/org/olat/modules/coach/CoachingServiceTest.java
+++ b/src/test/java/org/olat/modules/coach/CoachingLargeTest.java
@@ -19,13 +19,11 @@
  */
 package org.olat.modules.coach;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
 
+import java.io.File;
+import java.net.URL;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -36,34 +34,37 @@ import java.util.concurrent.ConcurrentHashMap;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
-import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.GroupRoles;
-import org.olat.basesecurity.IdentityRef;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.id.Identity;
-import org.olat.course.ICourse;
+import org.olat.course.CourseFactory;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupService;
 import org.olat.group.manager.BusinessGroupRelationDAO;
+import org.olat.modules.coach.manager.CoachingDAO;
 import org.olat.modules.coach.model.CourseStatEntry;
 import org.olat.modules.coach.model.EfficiencyStatementEntry;
 import org.olat.modules.coach.model.GroupStatEntry;
+import org.olat.modules.coach.model.SearchCoachedIdentityParams;
 import org.olat.modules.coach.model.StudentStatEntry;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryManager;
 import org.olat.repository.RepositoryService;
-import org.olat.restapi.repository.course.CoursesWebService;
 import org.olat.test.JunitTestHelper;
 import org.olat.test.OlatTestCase;
 import org.springframework.beans.factory.annotation.Autowired;
 
 /**
+ * This is mainly a test with a large number of courses and groups.
+ * It check if the rights courses are seen, but not details of the
+ * statistics.
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class CoachingServiceTest extends OlatTestCase {
+public class CoachingLargeTest extends OlatTestCase {
 	
 	private static boolean isInitialized = false;
+	private static final Random rnd = new Random();
 	
 	private static int NUM_OF_COURSES = 5;
 	private static int NUM_OF_STUDENTS = 15;
@@ -83,26 +84,24 @@ public class CoachingServiceTest extends OlatTestCase {
 	@Autowired
 	private DB dbInstance;
 	@Autowired
+	private CoachingDAO coachingDao;
+	@Autowired
 	private CoachingService coachingService;
 	@Autowired
 	private RepositoryManager repositoryManager;
 	@Autowired
 	private RepositoryService repositoryService;
 	@Autowired
-	private BaseSecurity securityManager;
+	private BusinessGroupService businessGroupService;
 	@Autowired
 	private BusinessGroupRelationDAO businessGroupRelationDao;
-	@Autowired
-	private BusinessGroupService businessGroupService;
-	
-
 	
 	@Before
 	public void setUp() throws Exception {
 		if(isInitialized) return;
 		
 		//author
-		author = JunitTestHelper.createAndPersistIdentityAsAuthor("author_" + getUUID());
+		author = JunitTestHelper.createAndPersistIdentityAsAuthor("author_" + UUID.randomUUID());
 		//r1 set of coach
 		coach10 = JunitTestHelper.createAndPersistIdentityAsRndUser("coach-10");
 		coach11 = JunitTestHelper.createAndPersistIdentityAsRndUser("coach-11");
@@ -131,8 +130,11 @@ public class CoachingServiceTest extends OlatTestCase {
 
 		//create courses with members
 		for(int i=0; i<NUM_OF_COURSES; i++) {
-			ICourse course = CoursesWebService.createEmptyCourse(author, "Coaching - " + i, "Coaching - " + i, null);
-			RepositoryEntry re = repositoryManager.lookupRepositoryEntry(course, false);
+			
+			URL courseWithForumsUrl = CoachingLargeTest.class.getResource("CoachingCourse.zip");
+			File courseWithForums = new File(courseWithForumsUrl.toURI());
+			String softKey = UUID.randomUUID().toString();
+			RepositoryEntry re = CourseFactory.deployCourseFromZIP(courseWithForums, softKey, 3);
 			if(i == 0) {
 				course10 = re;
 			}
@@ -170,8 +172,11 @@ public class CoachingServiceTest extends OlatTestCase {
 		
 		//create courses with members
 		for(int i=0; i<NUM_OF_COURSES; i++) {
-			ICourse course = CoursesWebService.createEmptyCourse(author, "Coaching - " + i, "Coaching - " + i, null);
-			RepositoryEntry re = repositoryManager.lookupRepositoryEntry(course, false);
+			
+			URL courseWithForumsUrl = CoachingLargeTest.class.getResource("CoachingCourse.zip");
+			File courseWithForums = new File(courseWithForumsUrl.toURI());
+			String softKey = UUID.randomUUID().toString();
+			RepositoryEntry re = CourseFactory.deployCourseFromZIP(courseWithForums, softKey, 3);
 			// create groups without waiting list
 			BusinessGroup g1 = businessGroupService.createBusinessGroup(author, "coach-g1", null, new Integer(0), new Integer(10), false, false, re);
 			BusinessGroup g2 = businessGroupService.createBusinessGroup(author, "coach-g2", null, new Integer(0), new Integer(10), false, false, re);
@@ -236,7 +241,7 @@ public class CoachingServiceTest extends OlatTestCase {
 		if(!coachToGroupCourseMap.containsKey(coachKey)) {
 			coachToGroupCourseMap.put(coachKey, new ArrayList<Long>());
 		}
-		coachToGroupCourseMap.get(coachKey).add(re.getKey());
+		coachToGroupCourseMap.get(coachKey).add(group.getKey());
 	}
 	
 	private void addStudentToCourse(Identity student, RepositoryEntry re) {
@@ -255,8 +260,6 @@ public class CoachingServiceTest extends OlatTestCase {
 		studentToCourseMap.get(student).add(re);
 	}
 	
-	private Random rnd = new Random();
-	
 	public List<Identity> reservoirSample(Iterable<Identity> items, int m) {   
 		List<Identity> res = new ArrayList<Identity>(m);   
 		int count = 0;   
@@ -273,75 +276,83 @@ public class CoachingServiceTest extends OlatTestCase {
 		return res;
 	}
 	
-	@Test
-	public void testManagers() {
-		assertNotNull(coachingService);
-		assertNotNull(repositoryManager);
-		assertNotNull(securityManager);
-		assertNotNull(businessGroupService);
-	}
-	
 	@Test
 	public void getStudentsStatistics() {
 		List<StudentStatEntry> statEntries = coachingService.getStudentsStatistics(coach10);
-		assertNotNull(statEntries);
+		Assert.assertNotNull(statEntries);
 	}
 	
 	@Test
 	public void getCoursesStatistics() {
-		List<CourseStatEntry> statEntries = coachingService.getCoursesStatistics(coach10);
-		assertNotNull(statEntries);
-		List<Long> myCourses = coachToCourseMap.get(coach10.getKey());
-		assertNotNull(myCourses);
-		assertEquals(myCourses.size(), statEntries.size());
+		List<CourseStatEntry> courseStatEntries = coachingService.getCoursesStatistics(coach10);
+		Assert.assertNotNull(courseStatEntries);
+		List<Long> coachedCourses = coachToCourseMap.get(coach10.getKey());
+		Assert.assertNotNull(coachedCourses);
+		Assert.assertEquals(coachedCourses.size(), courseStatEntries.size());
+		
+		List<Long> courseStatsKeys = new ArrayList<>();
+		for(CourseStatEntry statEntry:courseStatEntries) {
+			courseStatsKeys.add(statEntry.getRepoKey());
+		}
+		Assert.assertTrue(courseStatsKeys.containsAll(coachedCourses));
+		Assert.assertTrue(coachedCourses.containsAll(courseStatsKeys));
 	}
 	
 	@Test
 	public void getGroupsStatistics() {
-		List<GroupStatEntry> statEntries = coachingService.getGroupsStatistics(coach10);
-		assertNotNull(statEntries);
-		List<Long> myCourses = coachToGroupCourseMap.get(coach10.getKey());
-		assertNotNull(myCourses);
+		List<GroupStatEntry> groupStatEntries = coachingService.getGroupsStatistics(coach10);
+		Assert.assertNotNull(groupStatEntries);
+		List<Long> coachedGroups = coachToGroupCourseMap.get(coach10.getKey());
+		Assert.assertNotNull(coachedGroups);
+		Assert.assertEquals(coachedGroups.size(), groupStatEntries.size());
 		
-		assertEquals(myCourses.size(), statEntries.size());
+		List<Long> groupStatsKeys = new ArrayList<>();
+		for(GroupStatEntry statEntry:groupStatEntries) {
+			groupStatsKeys.add(statEntry.getGroupKey());
+		}
+		
+		Assert.assertTrue(groupStatsKeys.containsAll(coachedGroups));
+		Assert.assertTrue(coachedGroups.containsAll(groupStatsKeys));
 	}
 	
 	@Test
 	public void getCourse() {
-		List<Long> myCourses = coachToCourseMap.get(coach10.getKey());
-		assertNotNull(myCourses);
+		List<Long> coachedCourses = coachToCourseMap.get(coach10.getKey());
+		Assert.assertNotNull(coachedCourses);
 
 		List<EfficiencyStatementEntry> statEntries = coachingService.getCourse(coach10, course10);
-		assertNotNull(statEntries);
-		assertFalse(statEntries.isEmpty());
-		assertTrue(myCourses.contains(course10.getKey()));
+		Assert.assertNotNull(statEntries);
+		Assert.assertFalse(statEntries.isEmpty());
+		Assert.assertTrue(coachedCourses.contains(course10.getKey()));
 
 		for(EfficiencyStatementEntry statEntry:statEntries) {
-			assertNotNull(statEntry.getCourse());
-			assertEquals(course10.getKey(), statEntry.getCourse().getKey());
+			Assert.assertNotNull(statEntry.getCourse());
+			Assert.assertEquals(course10.getKey(), statEntry.getCourse().getKey());
 		}
 	}
 	
 	@Test
 	public void getStudentsCourses() {
-		List<RepositoryEntry> courses = coachingService.getStudentsCourses(coach10, student10, 0, -1);
-		assertNotNull(courses);
+		List<RepositoryEntry> courses = coachingService.getStudentsCourses(coach10, student10);
+		Assert.assertNotNull(courses);
 		
 		List<Long> myCourses = coachToCourseMap.get(coach10.getKey());
-		assertNotNull(myCourses);
+		Assert.assertNotNull(myCourses);
 	}
 	
 	@Test
 	public void getUserCourses() {
-		List<RepositoryEntry> courses = coachingService.getUserCourses(student10, 0, -1);
+		List<RepositoryEntry> courses = coachingService.getUserCourses(student10);
 		Assert.assertNotNull(courses);
 		Assert.assertEquals(studentToCourseMap.get(student10).size(), courses.size());
 	}
 	
 	@Test
 	public void getUsersStatistics() {
-		List<IdentityRef> identities = Collections.<IdentityRef>singletonList(student10);
-		List<StudentStatEntry> statEntries = coachingService.getUsersStatistics(identities);
+		SearchCoachedIdentityParams params = new SearchCoachedIdentityParams();
+		params.setLogin(student10.getName());
+		
+		List<StudentStatEntry> statEntries = coachingService.getUsersStatistics(params);
 		Assert.assertNotNull(statEntries);
 		Assert.assertEquals(1, statEntries.size());
 		
@@ -349,9 +360,4 @@ public class CoachingServiceTest extends OlatTestCase {
 		Assert.assertEquals(student10.getKey(), statEntry.getStudentKey());
 		Assert.assertEquals(studentToCourseMap.get(student10).size(), statEntry.getCountRepo());
 	}
-	
-	private String getUUID() {
-		return UUID.randomUUID().toString().replace("-", "");
-	}
-
-}
+}
\ No newline at end of file
diff --git a/src/test/java/org/olat/modules/coach/manager/CoachingDAOTest.java b/src/test/java/org/olat/modules/coach/manager/CoachingDAOTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..9609cf432f255128533286a26e15c537f825c0a2
--- /dev/null
+++ b/src/test/java/org/olat/modules/coach/manager/CoachingDAOTest.java
@@ -0,0 +1,1036 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.coach.manager;
+
+import java.io.File;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.olat.basesecurity.BaseSecurity;
+import org.olat.basesecurity.GroupRoles;
+import org.olat.basesecurity.IdentityRef;
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.id.Identity;
+import org.olat.core.id.User;
+import org.olat.core.id.UserConstants;
+import org.olat.core.util.CodeHelper;
+import org.olat.course.CourseFactory;
+import org.olat.course.ICourse;
+import org.olat.course.assessment.EfficiencyStatementManager;
+import org.olat.course.assessment.manager.UserCourseInformationsManager;
+import org.olat.group.BusinessGroup;
+import org.olat.group.BusinessGroupRef;
+import org.olat.group.BusinessGroupService;
+import org.olat.group.manager.BusinessGroupRelationDAO;
+import org.olat.modules.coach.CoachingLargeTest;
+import org.olat.modules.coach.model.CourseStatEntry;
+import org.olat.modules.coach.model.GroupStatEntry;
+import org.olat.modules.coach.model.SearchCoachedIdentityParams;
+import org.olat.modules.coach.model.StudentStatEntry;
+import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryEntryRef;
+import org.olat.repository.RepositoryService;
+import org.olat.test.JunitTestHelper;
+import org.olat.test.OlatTestCase;
+import org.olat.user.UserManager;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 24.07.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CoachingDAOTest extends OlatTestCase {
+	
+	@Autowired
+	private DB dbInstance;
+	@Autowired
+	private CoachingDAO coachingDAO;
+	@Autowired
+	private UserManager userManager;
+	@Autowired
+	private BaseSecurity securityManager;
+	@Autowired
+	private RepositoryService repositoryService;
+	@Autowired
+	private BusinessGroupService businessGroupService;
+	@Autowired
+	private BusinessGroupRelationDAO businessGroupRelationDao;
+	@Autowired
+	private UserCourseInformationsManager userCourseInformationsManager;
+	@Autowired
+	private EfficiencyStatementManager effManager;
+	
+	/**
+	 * 
+	 * 1 course with 2 groups.
+	 * 
+	 * @throws URISyntaxException
+	 */
+	@Test
+	public void getStatistics_duplicateInGroups()
+	throws URISyntaxException {
+		URL courseWithForumsUrl = CoachingLargeTest.class.getResource("CoachingCourse.zip");
+		File courseWithForums = new File(courseWithForumsUrl.toURI());
+		String softKey = UUID.randomUUID().toString();
+		RepositoryEntry re = CourseFactory.deployCourseFromZIP(courseWithForums, softKey, 4);
+		Assert.assertNotNull(re);
+
+		dbInstance.commitAndCloseSession();
+		
+		ICourse course = CourseFactory.loadCourse(re.getOlatResource().getResourceableId());			
+		boolean enabled = course.getCourseEnvironment().getCourseConfig().isEfficencyStatementEnabled();
+		Assert.assertTrue(enabled);
+		
+		//re -> owner,coach, p1, p2
+		//  -> group 1 p1
+		//  -> group 2 p2
+		
+		//members of courses
+		Identity coach = JunitTestHelper.createAndPersistIdentityAsAuthor("Coach-1-" + UUID.randomUUID());
+		repositoryService.addRole(coach, re, GroupRoles.owner.name());
+		repositoryService.addRole(coach, re, GroupRoles.coach.name());
+		Identity participant1 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-1");
+		repositoryService.addRole(participant1, re, GroupRoles.participant.name());
+		Identity participant2 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-2");
+		repositoryService.addRole(participant2, re, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		
+		//members of 2 groups
+		BusinessGroup group1 = businessGroupService.createBusinessGroup(coach, "Coaching-grp-1", "tg", null, null, false, false, re);
+	    businessGroupRelationDao.addRole(participant1, group1, GroupRoles.participant.name());
+	    BusinessGroup group2 = businessGroupService.createBusinessGroup(coach, "Coaching-grp-2", "tg", null, null, false, false, re);
+	    businessGroupRelationDao.addRole(participant1, group2, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		
+		//make statements
+	    effManager.createUserEfficiencyStatement(new Date(), 6.0f, true, participant1, re.getOlatResource());
+	    effManager.createUserEfficiencyStatement(new Date(), 2.0f, false, participant2, re.getOlatResource());
+		dbInstance.commitAndCloseSession();
+		//make user infos
+		userCourseInformationsManager.updateUserCourseInformations(course.getResourceableId(), participant1, true);
+		dbInstance.commitAndCloseSession();
+		
+		
+		//native
+		List<CourseStatEntry> nativeStats = coachingDAO.getCoursesStatisticsNative(coach);
+		Assert.assertNotNull(nativeStats);
+		Assert.assertEquals(1, nativeStats.size());
+		CourseStatEntry nativeStat = nativeStats.get(0);
+		Assert.assertEquals(2, nativeStat.getCountStudents());
+		Assert.assertEquals(1, nativeStat.getCountPassed());
+		Assert.assertEquals(1, nativeStat.getCountFailed());
+		Assert.assertEquals(1, nativeStat.getInitialLaunch());
+		Assert.assertEquals(4.0f, nativeStat.getAverageScore(), 0.0001);
+
+		
+		//user native
+		List<StudentStatEntry> nativeUserStats = coachingDAO.getStudentsStatisticsNative(coach);
+		Assert.assertNotNull(nativeUserStats);
+		Assert.assertEquals(2, nativeUserStats.size());
+		//participant1
+		StudentStatEntry entryParticipant1 = getStudentStatEntry(participant1, nativeUserStats);
+		Assert.assertNotNull(entryParticipant1);
+		Assert.assertEquals(1, entryParticipant1.getCountPassed());
+		Assert.assertEquals(0, entryParticipant1.getCountFailed());
+		Assert.assertEquals(0, entryParticipant1.getCountNotAttempted());
+		Assert.assertEquals(1, entryParticipant1.getInitialLaunch());
+		//participant2
+		StudentStatEntry entryParticipant2 = getStudentStatEntry(participant2, nativeUserStats);
+		Assert.assertNotNull(entryParticipant2);
+		Assert.assertEquals(0, entryParticipant2.getCountPassed());
+		Assert.assertEquals(1, entryParticipant2.getCountFailed());
+		Assert.assertEquals(0, entryParticipant2.getCountNotAttempted());
+		Assert.assertEquals(0, entryParticipant2.getInitialLaunch());
+
+		
+		//group native
+		List<GroupStatEntry> nativeGroupStats = coachingDAO.getGroupsStatisticsNative(coach);
+		Assert.assertNotNull(nativeGroupStats);
+		Assert.assertEquals(2, nativeGroupStats.size());
+		//group 1
+		GroupStatEntry entryGroup1 = getGroupStatEntry(group1, nativeGroupStats);
+		Assert.assertNotNull(entryGroup1);
+		Assert.assertEquals(1, entryGroup1.getCountCourses());
+		Assert.assertEquals(1, entryGroup1.getCountPassed());
+		Assert.assertEquals(0, entryGroup1.getCountFailed());
+		Assert.assertEquals(0, entryGroup1.getCountNotAttempted());
+		Assert.assertEquals(1, entryGroup1.getInitialLaunch());
+		Assert.assertEquals(6.0f, entryGroup1.getAverageScore(), 0.0001f);
+		//group 2
+		GroupStatEntry entryGroup2 = getGroupStatEntry(group1, nativeGroupStats);
+		Assert.assertNotNull(entryGroup2);
+		Assert.assertEquals(1, entryGroup2.getCountCourses());
+		Assert.assertEquals(1, entryGroup2.getCountPassed());
+		Assert.assertEquals(0, entryGroup2.getCountFailed());
+		Assert.assertEquals(0, entryGroup2.getCountNotAttempted());
+		Assert.assertEquals(1, entryGroup2.getInitialLaunch());
+		Assert.assertEquals(6.0f, entryGroup2.getAverageScore(), 0.0001f);
+	}
+	
+	/**
+	 * 3 courses in the same business group
+	 * 
+	 * @throws URISyntaxException
+	 */
+	@Test
+	public void getStatistics_notAttempted()
+	throws URISyntaxException {
+		URL coachingCourseUrl = CoachingLargeTest.class.getResource("CoachingCourse.zip");
+		File coachingCourseFile = new File(coachingCourseUrl.toURI());
+		RepositoryEntry re1 = CourseFactory.deployCourseFromZIP(coachingCourseFile, UUID.randomUUID().toString(), 4);
+		RepositoryEntry re2 = CourseFactory.deployCourseFromZIP(coachingCourseFile, UUID.randomUUID().toString(), 4);
+		RepositoryEntry re3 = CourseFactory.deployCourseFromZIP(coachingCourseFile, UUID.randomUUID().toString(), 4);
+		dbInstance.commitAndCloseSession();
+		
+		
+		//members of courses
+		Identity coach = JunitTestHelper.createAndPersistIdentityAsAuthor("Coach-1-" + UUID.randomUUID());
+		repositoryService.addRole(coach, re1, GroupRoles.owner.name());
+		repositoryService.addRole(coach, re1, GroupRoles.coach.name());
+		repositoryService.addRole(coach, re2, GroupRoles.coach.name());
+		repositoryService.addRole(coach, re3, GroupRoles.coach.name());
+		
+		
+		Identity participant1 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-1");
+		repositoryService.addRole(participant1, re2, GroupRoles.participant.name());
+		Identity participant2 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-2");
+		repositoryService.addRole(participant2, re1, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		
+		//members of 2 groups
+		BusinessGroup group= businessGroupService.createBusinessGroup(coach, "Coaching-grp-1", "tg", null, null, false, false, re1);
+		businessGroupService.addResourceTo(group, re2);
+		businessGroupService.addResourceTo(group, re3);
+		businessGroupRelationDao.addRole(participant1, group, GroupRoles.participant.name());
+		businessGroupRelationDao.addRole(participant2, group, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		
+		//make statements participant 1
+	    effManager.createUserEfficiencyStatement(new Date(), 6.0f, true, participant1, re1.getOlatResource());
+	    effManager.createUserEfficiencyStatement(new Date(), 4.0f, false, participant1, re2.getOlatResource());
+	    effManager.createUserEfficiencyStatement(new Date(), 2.0f, false, participant1, re3.getOlatResource());
+
+		//make statements participant 2
+	    effManager.createUserEfficiencyStatement(new Date(), 6.0f, true, participant2, re1.getOlatResource());
+	    effManager.createUserEfficiencyStatement(new Date(), null, null, participant2, re2.getOlatResource());
+		dbInstance.commitAndCloseSession();
+		
+		//make user infos
+		userCourseInformationsManager.updateUserCourseInformations(re1.getOlatResource().getResourceableId(), participant1, true);
+		userCourseInformationsManager.updateUserCourseInformations(re2.getOlatResource().getResourceableId(), participant1, true);
+		userCourseInformationsManager.updateUserCourseInformations(re3.getOlatResource().getResourceableId(), participant1, true);
+		userCourseInformationsManager.updateUserCourseInformations(re1.getOlatResource().getResourceableId(), participant2, true);
+		userCourseInformationsManager.updateUserCourseInformations(re2.getOlatResource().getResourceableId(), participant2, true);
+		dbInstance.commitAndCloseSession();
+		
+		//check course
+		List<CourseStatEntry> nativeStats = coachingDAO.getCoursesStatisticsNative(coach);
+		Assert.assertNotNull(nativeStats);
+		Assert.assertEquals(3, nativeStats.size());
+		CourseStatEntry entryRe1 = getCourseStatEntry(re1, nativeStats);
+		Assert.assertEquals(2, entryRe1.getCountStudents());
+		Assert.assertEquals(2, entryRe1.getCountPassed());
+		Assert.assertEquals(0, entryRe1.getCountFailed());
+		Assert.assertEquals(0, entryRe1.getCountNotAttempted());
+		Assert.assertEquals(2, entryRe1.getInitialLaunch());
+		Assert.assertEquals(6.0f, entryRe1.getAverageScore(), 0.0001);
+		
+		CourseStatEntry entryRe2 = getCourseStatEntry(re2, nativeStats);
+		Assert.assertEquals(2, entryRe2.getCountStudents());
+		Assert.assertEquals(0, entryRe2.getCountPassed());
+		Assert.assertEquals(1, entryRe2.getCountFailed());
+		Assert.assertEquals(1, entryRe2.getCountNotAttempted());
+		Assert.assertEquals(2, entryRe2.getInitialLaunch());
+		Assert.assertEquals(4.0f, entryRe2.getAverageScore(), 0.0001);
+		
+		CourseStatEntry entryRe3 = getCourseStatEntry(re3, nativeStats);
+		Assert.assertEquals(2, entryRe3.getCountStudents());
+		Assert.assertEquals(0, entryRe3.getCountPassed());
+		Assert.assertEquals(1, entryRe3.getCountFailed());
+		Assert.assertEquals(1, entryRe3.getCountNotAttempted());
+		Assert.assertEquals(1, entryRe3.getInitialLaunch());
+		Assert.assertEquals(2.0f, entryRe3.getAverageScore(), 0.0001);
+		
+		
+		//user native
+		List<StudentStatEntry> nativeUserStats = coachingDAO.getStudentsStatisticsNative(coach);
+		Assert.assertNotNull(nativeUserStats);
+		Assert.assertEquals(2, nativeUserStats.size());
+		//participant1
+		StudentStatEntry entryParticipant1 = getStudentStatEntry(participant1, nativeUserStats);
+		Assert.assertNotNull(entryParticipant1);
+		Assert.assertEquals(1, entryParticipant1.getCountPassed());
+		Assert.assertEquals(2, entryParticipant1.getCountFailed());
+		Assert.assertEquals(0, entryParticipant1.getCountNotAttempted());
+		Assert.assertEquals(3, entryParticipant1.getInitialLaunch());
+		Assert.assertEquals(3, entryParticipant1.getCountRepo());
+		//participant2
+		StudentStatEntry entryParticipant2 = getStudentStatEntry(participant2, nativeUserStats);
+		Assert.assertNotNull(entryParticipant2);
+		Assert.assertEquals(1, entryParticipant2.getCountPassed());
+		Assert.assertEquals(0, entryParticipant2.getCountFailed());
+		Assert.assertEquals(2, entryParticipant2.getCountNotAttempted());
+		Assert.assertEquals(2, entryParticipant2.getInitialLaunch());
+		Assert.assertEquals(3, entryParticipant1.getCountRepo());
+
+		
+		//group native
+		List<GroupStatEntry> nativeGroupStats = coachingDAO.getGroupsStatisticsNative(coach);
+		Assert.assertNotNull(nativeGroupStats);
+		Assert.assertEquals(1, nativeGroupStats.size());
+		//group 1
+		GroupStatEntry entryGroup1 = getGroupStatEntry(group, nativeGroupStats);
+		Assert.assertNotNull(entryGroup1);
+		Assert.assertEquals(6, entryGroup1.getCountStudents());
+		Assert.assertEquals(2, entryGroup1.getCountDistinctStudents());
+		Assert.assertEquals(3, entryGroup1.getCountCourses());
+		Assert.assertEquals(2, entryGroup1.getCountPassed());
+		Assert.assertEquals(2, entryGroup1.getCountFailed());
+		Assert.assertEquals(2, entryGroup1.getCountNotAttempted());
+		Assert.assertEquals(5, entryGroup1.getInitialLaunch());
+		Assert.assertEquals(4.5f, entryGroup1.getAverageScore(), 0.0001f);
+	}
+	
+	@Test
+	public void getStatistics_owner()
+	throws URISyntaxException {
+		URL coachingCourseUrl = CoachingLargeTest.class.getResource("CoachingCourse.zip");
+		File coachingCourseFile = new File(coachingCourseUrl.toURI());
+		RepositoryEntry re1 = CourseFactory.deployCourseFromZIP(coachingCourseFile, UUID.randomUUID().toString(), 4);
+		RepositoryEntry re2 = CourseFactory.deployCourseFromZIP(coachingCourseFile, UUID.randomUUID().toString(), 4);
+		RepositoryEntry re3 = CourseFactory.deployCourseFromZIP(coachingCourseFile, UUID.randomUUID().toString(), 4);
+		dbInstance.commitAndCloseSession();
+		
+		//members of courses
+		Identity coach = JunitTestHelper.createAndPersistIdentityAsAuthor("Coach-1-" + UUID.randomUUID());
+		repositoryService.addRole(coach, re1, GroupRoles.owner.name());
+		repositoryService.addRole(coach, re2, GroupRoles.owner.name());
+		repositoryService.addRole(coach, re3, GroupRoles.coach.name());
+		
+		Identity participant1 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-1");
+		repositoryService.addRole(participant1, re1, GroupRoles.participant.name());
+		Identity participant2 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-2");
+		repositoryService.addRole(participant2, re1, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		
+		//members of group of re 2
+		BusinessGroup group2 = businessGroupService.createBusinessGroup(null, "Coaching-grp-1", "tg", null, null, false, false, re2);
+		Identity participant3 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-3");
+		businessGroupRelationDao.addRole(participant3, group2, GroupRoles.participant.name());
+		Identity participant4 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-4");
+		businessGroupRelationDao.addRole(participant4, group2, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		
+		//members of group of re 3
+		BusinessGroup group3 = businessGroupService.createBusinessGroup(null, "Coaching-grp-1", "tg", null, null, false, false, re3);
+		Identity participant5 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-5");
+		businessGroupRelationDao.addRole(participant5, group3, GroupRoles.participant.name());
+		Identity participant6 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-6");
+		businessGroupRelationDao.addRole(participant6, group3, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		
+		//make statements participant 1
+	    effManager.createUserEfficiencyStatement(new Date(), 6.0f, true, participant1, re1.getOlatResource());
+	    effManager.createUserEfficiencyStatement(new Date(), 4.0f, false, participant2, re1.getOlatResource());
+	    effManager.createUserEfficiencyStatement(new Date(), 5.5f, true, participant3, re2.getOlatResource());
+	    effManager.createUserEfficiencyStatement(new Date(), null, null, participant4, re2.getOlatResource());
+	    effManager.createUserEfficiencyStatement(new Date(), 4.0f, true, participant5, re3.getOlatResource());
+	    effManager.createUserEfficiencyStatement(new Date(), 3.0f, false, participant6, re3.getOlatResource());
+		dbInstance.commitAndCloseSession();
+		
+		//make user infos
+		userCourseInformationsManager.updateUserCourseInformations(re1.getOlatResource().getResourceableId(), participant1, true);
+		userCourseInformationsManager.updateUserCourseInformations(re2.getOlatResource().getResourceableId(), participant1, true);
+		userCourseInformationsManager.updateUserCourseInformations(re3.getOlatResource().getResourceableId(), participant1, true);
+		userCourseInformationsManager.updateUserCourseInformations(re1.getOlatResource().getResourceableId(), participant2, true);
+		userCourseInformationsManager.updateUserCourseInformations(re2.getOlatResource().getResourceableId(), participant2, true);
+		userCourseInformationsManager.updateUserCourseInformations(re2.getOlatResource().getResourceableId(), participant3, true);
+		userCourseInformationsManager.updateUserCourseInformations(re2.getOlatResource().getResourceableId(), participant4, true);
+		userCourseInformationsManager.updateUserCourseInformations(re3.getOlatResource().getResourceableId(), participant5, true);
+		userCourseInformationsManager.updateUserCourseInformations(re3.getOlatResource().getResourceableId(), participant6, true);
+		dbInstance.commitAndCloseSession();
+		
+		//owner can see participant 1,2,3 and 4
+		// p1 has 1 assessment in re1
+		// p2 has 1 assessment in re1
+		// p3 has 2 assessments in re1 and re2
+		// p4 has 1 assessment in re2
+		// 5 and p6 has 1 assessment in re3
+		
+		List<GroupStatEntry> nativeGroupStats = coachingDAO.getGroupsStatisticsNative(coach);
+		Assert.assertNotNull(nativeGroupStats);
+		Assert.assertEquals(1, nativeGroupStats.size());
+		GroupStatEntry entryGroup2 = getGroupStatEntry(group2, nativeGroupStats);
+		Assert.assertNotNull(entryGroup2);
+		Assert.assertEquals(2, entryGroup2.getCountDistinctStudents());
+		Assert.assertEquals(2, entryGroup2.getInitialLaunch());
+		Assert.assertEquals(1, entryGroup2.getCountPassed());
+		Assert.assertEquals(0, entryGroup2.getCountFailed());
+		Assert.assertEquals(1, entryGroup2.getCountNotAttempted());
+		Assert.assertEquals(5.5f, entryGroup2.getAverageScore(), 0.0001f);
+		
+
+		//re 3 is removed because coach has no visible participants within
+		List<CourseStatEntry> nativeCourseStats = coachingDAO.getCoursesStatisticsNative(coach);
+		Assert.assertNotNull(nativeCourseStats);
+		Assert.assertEquals(2, nativeCourseStats.size());
+		//re 1
+		CourseStatEntry entryCourse1 = getCourseStatEntry(re1, nativeCourseStats);
+		Assert.assertNotNull(entryCourse1);
+		Assert.assertEquals(2, entryCourse1.getCountStudents());
+		Assert.assertEquals(2, entryCourse1.getInitialLaunch());
+		Assert.assertEquals(1, entryCourse1.getCountPassed());
+		Assert.assertEquals(1, entryCourse1.getCountFailed());
+		Assert.assertEquals(0, entryCourse1.getCountNotAttempted());
+		Assert.assertEquals(5.0f, entryCourse1.getAverageScore(), 0.0001f);
+		//re 2
+		CourseStatEntry entryCourse2 = getCourseStatEntry(re2, nativeCourseStats);
+		Assert.assertNotNull(entryCourse2);
+		Assert.assertEquals(2, entryCourse2.getCountStudents());
+		Assert.assertEquals(2, entryCourse2.getInitialLaunch());
+		Assert.assertEquals(1, entryCourse2.getCountPassed());
+		Assert.assertEquals(0, entryCourse2.getCountFailed());
+		Assert.assertEquals(1, entryCourse2.getCountNotAttempted());
+		Assert.assertEquals(5.5f, entryCourse2.getAverageScore(), 0.0001f);
+		
+		//user native
+		List<StudentStatEntry> nativeUserStats = coachingDAO.getStudentsStatisticsNative(coach);
+		Assert.assertNotNull(nativeUserStats);
+	
+		Assert.assertEquals(4, nativeUserStats.size());
+		//participant1 is only in re 1
+		StudentStatEntry entryParticipant1 = getStudentStatEntry(participant1, nativeUserStats);
+		Assert.assertNotNull(entryParticipant1);
+		Assert.assertEquals(1, entryParticipant1.getCountPassed());
+		Assert.assertEquals(0, entryParticipant1.getCountFailed());
+		Assert.assertEquals(0, entryParticipant1.getCountNotAttempted());
+		Assert.assertEquals(1, entryParticipant1.getInitialLaunch());
+		Assert.assertEquals(1, entryParticipant1.getCountRepo());
+		//participant2 is only in re 1
+		StudentStatEntry entryParticipant2 = getStudentStatEntry(participant2, nativeUserStats);
+		Assert.assertNotNull(entryParticipant2);
+		Assert.assertEquals(0, entryParticipant2.getCountPassed());
+		Assert.assertEquals(1, entryParticipant2.getCountFailed());
+		Assert.assertEquals(0, entryParticipant2.getCountNotAttempted());
+		Assert.assertEquals(1, entryParticipant2.getInitialLaunch());
+		Assert.assertEquals(1, entryParticipant2.getCountRepo());
+		//participant3 is in re 2 ( via group 2)
+		StudentStatEntry entryParticipant3 = getStudentStatEntry(participant3, nativeUserStats);
+		Assert.assertNotNull(entryParticipant3);
+		Assert.assertEquals(1, entryParticipant3.getCountPassed());
+		Assert.assertEquals(0, entryParticipant3.getCountFailed());
+		Assert.assertEquals(0, entryParticipant3.getCountNotAttempted());
+		Assert.assertEquals(1, entryParticipant3.getInitialLaunch());
+		Assert.assertEquals(1, entryParticipant3.getCountRepo());
+		//participant4 is in re 2 ( via group 2)
+		StudentStatEntry entryParticipant4 = getStudentStatEntry(participant4, nativeUserStats);
+		Assert.assertNotNull(entryParticipant4);
+		Assert.assertEquals(0, entryParticipant4.getCountPassed());
+		Assert.assertEquals(0, entryParticipant4.getCountFailed());
+		Assert.assertEquals(1, entryParticipant4.getCountNotAttempted());
+		Assert.assertEquals(1, entryParticipant4.getInitialLaunch());
+		Assert.assertEquals(1, entryParticipant4.getCountRepo());
+	}
+	
+	/**
+	 * Check the access permissions on course (coach can only see courses with memebrsOnly, or access >= 3)
+	 * 
+	 * @throws URISyntaxException
+	 */
+	@Test
+	public void getStatistics_permissionOnCourses()
+	throws URISyntaxException {
+		URL coachingCourseUrl = CoachingLargeTest.class.getResource("CoachingCourse.zip");
+		File coachingCourseFile = new File(coachingCourseUrl.toURI());
+		RepositoryEntry re1 = CourseFactory.deployCourseFromZIP(coachingCourseFile, UUID.randomUUID().toString(), 1);
+		RepositoryEntry re2 = CourseFactory.deployCourseFromZIP(coachingCourseFile, UUID.randomUUID().toString(), 2);
+		RepositoryEntry re3 = CourseFactory.deployCourseFromZIP(coachingCourseFile, UUID.randomUUID().toString(), 3);
+		dbInstance.commitAndCloseSession();
+		
+		//members of courses
+		Identity courseCoach = JunitTestHelper.createAndPersistIdentityAsAuthor("Coach-1-" + UUID.randomUUID());
+		Identity groupCoach = JunitTestHelper.createAndPersistIdentityAsAuthor("Coach-1-" + UUID.randomUUID());
+		repositoryService.addRole(courseCoach, re1, GroupRoles.coach.name());
+		repositoryService.addRole(courseCoach, re2, GroupRoles.coach.name());
+		repositoryService.addRole(courseCoach, re3, GroupRoles.coach.name());
+		
+		//add participants to courses
+		Identity participant1 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-1");
+		repositoryService.addRole(participant1, re1, GroupRoles.participant.name());
+		Identity participant11 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-11");
+		repositoryService.addRole(participant11, re1, GroupRoles.participant.name());
+		Identity participant2 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-2");
+		repositoryService.addRole(participant2, re2, GroupRoles.participant.name());
+		Identity participant21 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-21");
+		repositoryService.addRole(participant21, re2, GroupRoles.participant.name());
+		Identity participant3 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-3");
+		repositoryService.addRole(participant3, re3, GroupRoles.participant.name());
+		Identity participant31 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-31");
+		repositoryService.addRole(participant31, re3, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		
+		//members of group of re 1
+		BusinessGroup group1 = businessGroupService.createBusinessGroup(groupCoach, "Coaching-grp-1", "tg", null, null, false, false, re1);
+		Identity participantG1 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-g1");
+		businessGroupRelationDao.addRole(participantG1, group1, GroupRoles.participant.name());
+		Identity participantG11 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-g11");
+		businessGroupRelationDao.addRole(participantG11, group1, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+
+		//members of group of re 2
+		BusinessGroup group2 = businessGroupService.createBusinessGroup(groupCoach, "Coaching-grp-2", "tg", null, null, false, false, re2);
+		Identity participantG2 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-g2");
+		businessGroupRelationDao.addRole(participantG2, group2, GroupRoles.participant.name());
+		Identity participantG21 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-g22");
+		businessGroupRelationDao.addRole(participantG21, group2, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		
+		//members of group of re 3
+		BusinessGroup group3 = businessGroupService.createBusinessGroup(groupCoach, "Coaching-grp-3", "tg", null, null, false, false, re3);
+		Identity participantG3 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-g3");
+		businessGroupRelationDao.addRole(participantG3, group3, GroupRoles.participant.name());
+		Identity participantG31 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-g33");
+		businessGroupRelationDao.addRole(participantG31, group3, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		
+		//make statements participants
+	    effManager.createUserEfficiencyStatement(new Date(), 6.230429f, true, participant1, re1.getOlatResource());
+	    effManager.createUserEfficiencyStatement(new Date(), 4.182317f, false, participant11, re1.getOlatResource());
+	    effManager.createUserEfficiencyStatement(new Date(), 4.095833f, false, participantG1, re1.getOlatResource());
+	    effManager.createUserEfficiencyStatement(new Date(), 4.578924f, false, participantG11, re1.getOlatResource());
+	    
+	    effManager.createUserEfficiencyStatement(new Date(), 2.2894727f, true, participant2, re2.getOlatResource());
+	    effManager.createUserEfficiencyStatement(new Date(), null, null, participant21, re2.getOlatResource());
+	    effManager.createUserEfficiencyStatement(new Date(), 5.2347774f, true, participantG2, re2.getOlatResource());
+	    effManager.createUserEfficiencyStatement(new Date(), null, null, participantG21, re2.getOlatResource());
+	    
+	    effManager.createUserEfficiencyStatement(new Date(), 4.0f, true, participant3, re3.getOlatResource());
+	    effManager.createUserEfficiencyStatement(new Date(), 3.0f, false, participant31, re3.getOlatResource());
+	    effManager.createUserEfficiencyStatement(new Date(), 5.5f, true, participantG3, re3.getOlatResource());
+	    effManager.createUserEfficiencyStatement(new Date(), 1.0f, false, participantG31, re3.getOlatResource());
+		dbInstance.commitAndCloseSession();
+		
+		//make user infos
+		userCourseInformationsManager.updateUserCourseInformations(re1.getOlatResource().getResourceableId(), participant1, true);
+		userCourseInformationsManager.updateUserCourseInformations(re1.getOlatResource().getResourceableId(), participant11, true);
+		userCourseInformationsManager.updateUserCourseInformations(re1.getOlatResource().getResourceableId(), participantG1, true);
+		userCourseInformationsManager.updateUserCourseInformations(re1.getOlatResource().getResourceableId(), participantG11, true);
+		
+		userCourseInformationsManager.updateUserCourseInformations(re2.getOlatResource().getResourceableId(), participant2, true);
+		userCourseInformationsManager.updateUserCourseInformations(re2.getOlatResource().getResourceableId(), participant21, true);
+		userCourseInformationsManager.updateUserCourseInformations(re2.getOlatResource().getResourceableId(), participantG2, true);
+		userCourseInformationsManager.updateUserCourseInformations(re2.getOlatResource().getResourceableId(), participantG21, true);
+		
+		userCourseInformationsManager.updateUserCourseInformations(re3.getOlatResource().getResourceableId(), participant3, true);
+		userCourseInformationsManager.updateUserCourseInformations(re3.getOlatResource().getResourceableId(), participant31, true);
+		userCourseInformationsManager.updateUserCourseInformations(re3.getOlatResource().getResourceableId(), participantG3, true);
+		userCourseInformationsManager.updateUserCourseInformations(re3.getOlatResource().getResourceableId(), participantG31, true);
+		dbInstance.commitAndCloseSession();
+		
+
+		//course coach cannot see groups
+		List<GroupStatEntry> courseCoachGroupStats = coachingDAO.getGroupsStatisticsNative(courseCoach);
+		Assert.assertNotNull(courseCoachGroupStats);
+		Assert.assertEquals(0, courseCoachGroupStats.size());
+
+		List<GroupStatEntry> groupCoachGroupStats = coachingDAO.getGroupsStatisticsNative(groupCoach);
+		Assert.assertNotNull(groupCoachGroupStats);
+		Assert.assertEquals(1, groupCoachGroupStats.size());
+		GroupStatEntry entryGroup3 = getGroupStatEntry(group3, groupCoachGroupStats);
+		Assert.assertNotNull(entryGroup3);
+		Assert.assertEquals(2, entryGroup3.getCountDistinctStudents());
+		Assert.assertEquals(2, entryGroup3.getInitialLaunch());
+		Assert.assertEquals(1, entryGroup3.getCountPassed());
+		Assert.assertEquals(1, entryGroup3.getCountFailed());
+		Assert.assertEquals(0, entryGroup3.getCountNotAttempted());
+		Assert.assertEquals(3.25f, entryGroup3.getAverageScore(), 0.0001f);
+		
+
+		//course statistics
+		List<CourseStatEntry> courseCoachCourseStats = coachingDAO.getCoursesStatisticsNative(courseCoach);
+		Assert.assertNotNull(courseCoachCourseStats);
+		Assert.assertEquals(1, courseCoachCourseStats.size());
+		CourseStatEntry entryCourse3 = getCourseStatEntry(re3, courseCoachCourseStats);
+		Assert.assertNotNull(entryCourse3);
+		Assert.assertEquals(2, entryCourse3.getCountStudents());
+		Assert.assertEquals(2, entryCourse3.getInitialLaunch());
+		Assert.assertEquals(1, entryCourse3.getCountPassed());
+		Assert.assertEquals(1, entryCourse3.getCountFailed());
+		Assert.assertEquals(0, entryCourse3.getCountNotAttempted());
+		Assert.assertEquals(3.5f, entryCourse3.getAverageScore(), 0.0001f);
+		//group coach can see course 3
+		List<CourseStatEntry> groupCoachCourseStats = coachingDAO.getCoursesStatisticsNative(groupCoach);
+		Assert.assertNotNull(groupCoachCourseStats);
+		Assert.assertEquals(1, groupCoachCourseStats.size());
+		CourseStatEntry entryCourse3g = getCourseStatEntry(re3, groupCoachCourseStats);
+		Assert.assertEquals(2, entryCourse3g.getCountStudents());
+		Assert.assertEquals(2, entryCourse3g.getInitialLaunch());
+		Assert.assertEquals(1, entryCourse3g.getCountPassed());
+		Assert.assertEquals(1, entryCourse3g.getCountFailed());
+		Assert.assertEquals(0, entryCourse3g.getCountNotAttempted());
+		Assert.assertEquals(3.25f, entryCourse3g.getAverageScore(), 0.0001f);
+	
+		
+		//user native
+		List<StudentStatEntry> courseCoachUserStats = coachingDAO.getStudentsStatisticsNative(courseCoach);
+		Assert.assertNotNull(courseCoachUserStats);
+		Assert.assertEquals(2, courseCoachUserStats.size());
+		//participant3 is only in re 1
+		StudentStatEntry entryParticipant3 = getStudentStatEntry(participant3, courseCoachUserStats);
+		Assert.assertNotNull(entryParticipant3);
+		Assert.assertEquals(1, entryParticipant3.getCountPassed());
+		Assert.assertEquals(0, entryParticipant3.getCountFailed());
+		Assert.assertEquals(0, entryParticipant3.getCountNotAttempted());
+		Assert.assertEquals(1, entryParticipant3.getInitialLaunch());
+		Assert.assertEquals(1, entryParticipant3.getCountRepo());
+		//participant31 is only in re 1
+		StudentStatEntry entryParticipant31 = getStudentStatEntry(participant31, courseCoachUserStats);
+		Assert.assertNotNull(entryParticipant31);
+		Assert.assertEquals(0, entryParticipant31.getCountPassed());
+		Assert.assertEquals(1, entryParticipant31.getCountFailed());
+		Assert.assertEquals(0, entryParticipant31.getCountNotAttempted());
+		Assert.assertEquals(1, entryParticipant31.getInitialLaunch());
+		Assert.assertEquals(1, entryParticipant31.getCountRepo());
+		
+		//group coach
+		List<StudentStatEntry> groupCoachUserStats = coachingDAO.getStudentsStatisticsNative(groupCoach);
+		Assert.assertNotNull(groupCoachUserStats);
+		Assert.assertEquals(2, groupCoachUserStats.size());
+
+		//participantG3 is in re 3 ( via group 3)
+		StudentStatEntry entryParticipantG3 = getStudentStatEntry(participantG3, groupCoachUserStats);
+		Assert.assertNotNull(entryParticipantG3);
+		Assert.assertEquals(1, entryParticipantG3.getCountPassed());
+		Assert.assertEquals(0, entryParticipantG3.getCountFailed());
+		Assert.assertEquals(0, entryParticipantG3.getCountNotAttempted());
+		Assert.assertEquals(1, entryParticipantG3.getInitialLaunch());
+		Assert.assertEquals(1, entryParticipantG3.getCountRepo());
+		//participantG3 is in re 3 ( via group 3)
+		StudentStatEntry entryParticipantG31 = getStudentStatEntry(participantG31, groupCoachUserStats);
+		Assert.assertNotNull(entryParticipantG31);
+		Assert.assertEquals(0, entryParticipantG31.getCountPassed());
+		Assert.assertEquals(1, entryParticipantG31.getCountFailed());
+		Assert.assertEquals(0, entryParticipantG31.getCountNotAttempted());
+		Assert.assertEquals(1, entryParticipantG31.getInitialLaunch());
+		Assert.assertEquals(1, entryParticipantG31.getCountRepo());
+	}
+	
+	/**
+	 * This is an important test to check if the return values of the statistics
+	 * are correctly handled because some of them can be null or 0.
+	 * 
+	 * @throws URISyntaxException
+	 */
+	@Test
+	public void getStatistics_emptyStatements_emptyCourseInfos()
+	throws URISyntaxException {
+		URL coachingCourseUrl = CoachingLargeTest.class.getResource("CoachingCourse.zip");
+		File coachingCourseFile = new File(coachingCourseUrl.toURI());
+		RepositoryEntry re1 = CourseFactory.deployCourseFromZIP(coachingCourseFile, UUID.randomUUID().toString(), 4);
+		RepositoryEntry re2 = CourseFactory.deployCourseFromZIP(coachingCourseFile, UUID.randomUUID().toString(), 4);
+		dbInstance.commitAndCloseSession();
+		
+		//members of courses
+		Identity coach = JunitTestHelper.createAndPersistIdentityAsAuthor("Coach-1-" + UUID.randomUUID());
+		repositoryService.addRole(coach, re1, GroupRoles.owner.name());
+		repositoryService.addRole(coach, re2, GroupRoles.coach.name());
+		
+		Identity participant1 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-1");
+		repositoryService.addRole(participant1, re1, GroupRoles.participant.name());
+		Identity participant2 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-2");
+		repositoryService.addRole(participant2, re1, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		
+		//groups
+		BusinessGroup group1 = businessGroupService.createBusinessGroup(null, "Coaching-grp-1", "tg", null, null, false, false, re1);
+		Identity participant3 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-3");
+		businessGroupRelationDao.addRole(participant3, group1, GroupRoles.participant.name());
+		Identity participant4 = JunitTestHelper.createAndPersistIdentityAsRndUser("Coaching-Part-4");
+		businessGroupRelationDao.addRole(participant4, group1, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		
+		//check groups statistics
+		List<GroupStatEntry> nativeGroupStats = coachingDAO.getGroupsStatisticsNative(coach);
+		Assert.assertNotNull(nativeGroupStats);
+		Assert.assertEquals(1, nativeGroupStats.size());
+		GroupStatEntry entryGroup1 = getGroupStatEntry(group1, nativeGroupStats);
+		Assert.assertNotNull(entryGroup1);
+		Assert.assertEquals(2, entryGroup1.getCountDistinctStudents());
+		Assert.assertEquals(0, entryGroup1.getInitialLaunch());
+		Assert.assertEquals(0, entryGroup1.getCountPassed());
+		Assert.assertEquals(0, entryGroup1.getCountFailed());
+		Assert.assertEquals(2, entryGroup1.getCountNotAttempted());
+		Assert.assertNull(entryGroup1.getAverageScore());
+		
+		//courses
+		List<CourseStatEntry> nativeCourseStats = coachingDAO.getCoursesStatisticsNative(coach);
+		Assert.assertNotNull(nativeCourseStats);
+		Assert.assertEquals(1, nativeCourseStats.size());
+		//re 1
+		CourseStatEntry entryCourse1 = getCourseStatEntry(re1, nativeCourseStats);
+		Assert.assertNotNull(entryCourse1);
+		Assert.assertEquals(4, entryCourse1.getCountStudents());
+		Assert.assertEquals(0, entryCourse1.getInitialLaunch());
+		Assert.assertEquals(0, entryCourse1.getCountPassed());
+		Assert.assertEquals(0, entryCourse1.getCountFailed());
+		Assert.assertEquals(4, entryCourse1.getCountNotAttempted());
+		Assert.assertNull(entryCourse1.getAverageScore());
+
+		
+		//user native
+		List<StudentStatEntry> nativeUserStats = coachingDAO.getStudentsStatisticsNative(coach);
+		Assert.assertNotNull(nativeUserStats);
+		Assert.assertEquals(4, nativeUserStats.size());
+		//participants have all the same statistics
+		Identity[] participants = new Identity[]{ participant1, participant2, participant3, participant4};
+		for(Identity participant:participants) {
+			StudentStatEntry entryParticipant = getStudentStatEntry(participant, nativeUserStats);
+			Assert.assertNotNull(entryParticipant);
+			Assert.assertEquals(0, entryParticipant.getCountPassed());
+			Assert.assertEquals(0, entryParticipant.getCountFailed());
+			Assert.assertEquals(1, entryParticipant.getCountNotAttempted());
+			Assert.assertEquals(0, entryParticipant.getInitialLaunch());
+			Assert.assertEquals(1, entryParticipant.getCountRepo());
+		}
+	}
+	
+	/**
+	 * This is an important test to check if the return values of the statistics
+	 * are correctly handled because some of them can be null or 0.
+	 * 
+	 * @throws URISyntaxException
+	 */
+	@Test
+	public void getStatistics_empty()
+	throws URISyntaxException {
+		URL coachingCourseUrl = CoachingLargeTest.class.getResource("CoachingCourse.zip");
+		File coachingCourseFile = new File(coachingCourseUrl.toURI());
+		RepositoryEntry re1 = CourseFactory.deployCourseFromZIP(coachingCourseFile, UUID.randomUUID().toString(), 4);
+		RepositoryEntry re2 = CourseFactory.deployCourseFromZIP(coachingCourseFile, UUID.randomUUID().toString(), 4);
+		dbInstance.commitAndCloseSession();
+		
+		//members of courses
+		Identity coach = JunitTestHelper.createAndPersistIdentityAsAuthor("Coach-1-" + UUID.randomUUID());
+		repositoryService.addRole(coach, re1, GroupRoles.owner.name());
+		repositoryService.addRole(coach, re2, GroupRoles.coach.name());
+		//groups
+		BusinessGroup group = businessGroupService.createBusinessGroup(null, "Coaching-grp-1", "tg", null, null, false, false, re1);
+		dbInstance.commitAndCloseSession();
+		Assert.assertNotNull(group);
+
+		//groups (method doesn't return courses without participant)
+		List<GroupStatEntry> nativeGroupStats = coachingDAO.getGroupsStatisticsNative(coach);
+		Assert.assertNotNull(nativeGroupStats);
+		Assert.assertEquals(0, nativeGroupStats.size());
+		
+		//courses (method doesn't return courses without participant)
+		List<CourseStatEntry> nativeCourseStats = coachingDAO.getCoursesStatisticsNative(coach);
+		Assert.assertNotNull(nativeCourseStats);
+		Assert.assertEquals(0, nativeCourseStats.size());
+
+		//user native
+		List<StudentStatEntry> nativeUserStats = coachingDAO.getStudentsStatisticsNative(coach);
+		Assert.assertNotNull(nativeUserStats);
+		Assert.assertEquals(0, nativeUserStats.size());
+	}
+	
+	@Test
+	public void getUsers()
+	throws URISyntaxException {
+		URL coachingCourseUrl = CoachingLargeTest.class.getResource("CoachingCourse.zip");
+		File coachingCourseFile = new File(coachingCourseUrl.toURI());
+		RepositoryEntry re1 = CourseFactory.deployCourseFromZIP(coachingCourseFile, UUID.randomUUID().toString(), 4);
+		RepositoryEntry re2 = CourseFactory.deployCourseFromZIP(coachingCourseFile, UUID.randomUUID().toString(), 4);
+		RepositoryEntry re3 = CourseFactory.deployCourseFromZIP(coachingCourseFile, UUID.randomUUID().toString(), 4);
+		dbInstance.commitAndCloseSession();
+		
+		//members of courses
+		Identity participant = JunitTestHelper.createAndPersistIdentityAsRndUser("User-Part-1");
+		repositoryService.addRole(participant, re1, GroupRoles.participant.name());
+		repositoryService.addRole(participant, re2, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		// groups
+		BusinessGroup group2 = businessGroupService.createBusinessGroup(null, "Coaching-grp-1", "tg", null, null, false, false, re2);
+		businessGroupRelationDao.addRole(participant, group2, GroupRoles.participant.name());
+		BusinessGroup group3 = businessGroupService.createBusinessGroup(null, "Coaching-grp-1", "tg", null, null, false, false, re3);
+		businessGroupRelationDao.addRole(participant, group3, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+
+		//make statements participant 1
+	    effManager.createUserEfficiencyStatement(new Date(), 6.0f, true, participant, re1.getOlatResource());
+	    effManager.createUserEfficiencyStatement(new Date(), 4.0f, false, participant, re2.getOlatResource());
+	    effManager.createUserEfficiencyStatement(new Date(), 2.0f, false, participant, re3.getOlatResource());
+		dbInstance.commitAndCloseSession();
+		
+		//make user infos
+		userCourseInformationsManager.updateUserCourseInformations(re1.getOlatResource().getResourceableId(), participant, true);
+		userCourseInformationsManager.updateUserCourseInformations(re2.getOlatResource().getResourceableId(), participant, true);
+		userCourseInformationsManager.updateUserCourseInformations(re3.getOlatResource().getResourceableId(), participant, true);
+		dbInstance.commitAndCloseSession();
+
+		//update props
+		User partUser = participant.getUser();
+		partUser.setProperty(UserConstants.FIRSTNAME, "Rei");
+		partUser.setProperty(UserConstants.LASTNAME, "Ayanami");
+		partUser.setProperty(UserConstants.EMAIL, "rei.ayanami@openolat.com");
+		partUser = userManager.updateUser(partUser);
+		dbInstance.commitAndCloseSession();
+		
+		
+		//search by first name
+		SearchCoachedIdentityParams params = new SearchCoachedIdentityParams();
+		Map<String,String> props = new HashMap<>();
+		props.put(UserConstants.FIRSTNAME, "re");
+		params.setUserProperties(props);
+		List<StudentStatEntry> stats = coachingDAO.getUsersStatisticsNative(params);
+		Assert.assertNotNull(stats);
+		Assert.assertFalse(stats.isEmpty());
+		
+		//check participant
+		StudentStatEntry entryStat = getStudentStatEntry(participant, stats);
+		Assert.assertNotNull(entryStat);
+		Assert.assertEquals(3, entryStat.getCountRepo());
+		Assert.assertEquals(3, entryStat.getInitialLaunch());
+		Assert.assertEquals(1, entryStat.getCountPassed());
+		Assert.assertEquals(2, entryStat.getCountFailed());
+		Assert.assertEquals(0, entryStat.getCountNotAttempted());
+
+
+		//search by user name
+		SearchCoachedIdentityParams loginParams = new SearchCoachedIdentityParams();
+		loginParams.setLogin(participant.getName());
+		List<StudentStatEntry> loginStats = coachingDAO.getUsersStatisticsNative(loginParams);
+		Assert.assertNotNull(loginStats);
+		Assert.assertEquals(1, loginStats.size());
+		
+		//check participant
+		StudentStatEntry loginStat = loginStats.get(0);
+		Assert.assertNotNull(loginStat);
+		Assert.assertEquals(3, loginStat.getCountRepo());
+		Assert.assertEquals(3, loginStat.getInitialLaunch());
+		Assert.assertEquals(1, loginStat.getCountPassed());
+		Assert.assertEquals(2, loginStat.getCountFailed());
+		Assert.assertEquals(0, loginStat.getCountNotAttempted());
+	}
+	
+	@Test
+	public void getStudents_coach_course() throws URISyntaxException {
+		URL coachingCourseUrl = CoachingLargeTest.class.getResource("CoachingCourse.zip");
+		File coachingCourseFile = new File(coachingCourseUrl.toURI());
+		RepositoryEntry re = CourseFactory.deployCourseFromZIP(coachingCourseFile, UUID.randomUUID().toString(), 4);
+		dbInstance.commitAndCloseSession();
+		
+		//members of courses
+		Identity coach = JunitTestHelper.createAndPersistIdentityAsRndUser("User-Part-1");
+		Identity participant1 = JunitTestHelper.createAndPersistIdentityAsRndUser("User-Part-1");
+		Identity participant2 = JunitTestHelper.createAndPersistIdentityAsRndUser("User-Part-2");
+		Identity participant3 = JunitTestHelper.createAndPersistIdentityAsRndUser("User-Part-3");
+		
+		repositoryService.addRole(coach, re, GroupRoles.coach.name());
+		repositoryService.addRole(participant1, re, GroupRoles.participant.name());
+		repositoryService.addRole(participant2, re, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		// groups
+		BusinessGroup group2 = businessGroupService.createBusinessGroup(coach, "Coaching-grp-1", "tg", null, null, false, false, re);
+		businessGroupRelationDao.addRole(participant2, group2, GroupRoles.participant.name());
+		BusinessGroup group3 = businessGroupService.createBusinessGroup(coach, "Coaching-grp-1", "tg", null, null, false, false, re);
+		businessGroupRelationDao.addRole(participant3, group3, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		
+		List<Long> identityKeys = coachingDAO.getStudents(coach, re);
+		Assert.assertNotNull(identityKeys);
+		Assert.assertEquals(3, identityKeys.size());
+		Assert.assertTrue(identityKeys.contains(participant1.getKey()));
+		Assert.assertTrue(identityKeys.contains(participant2.getKey()));
+		Assert.assertTrue(identityKeys.contains(participant3.getKey()));
+	}
+	
+	@Test
+	public void getStudents_owner_course() throws URISyntaxException {
+		URL coachingCourseUrl = CoachingLargeTest.class.getResource("CoachingCourse.zip");
+		File coachingCourseFile = new File(coachingCourseUrl.toURI());
+		RepositoryEntry re = CourseFactory.deployCourseFromZIP(coachingCourseFile, UUID.randomUUID().toString(), 4);
+		dbInstance.commitAndCloseSession();
+		
+		//members of courses
+		Identity owner = JunitTestHelper.createAndPersistIdentityAsRndUser("Owner-1");
+		Identity groupCoach = JunitTestHelper.createAndPersistIdentityAsRndUser("Group coach-1");
+		Identity participant1 = JunitTestHelper.createAndPersistIdentityAsRndUser("Part-1");
+		Identity participant2 = JunitTestHelper.createAndPersistIdentityAsRndUser("Part-2");
+		Identity participant3 = JunitTestHelper.createAndPersistIdentityAsRndUser("Part-3");
+		Identity participant4 = JunitTestHelper.createAndPersistIdentityAsRndUser("Part-4");
+		
+		repositoryService.addRole(owner, re, GroupRoles.owner.name());
+		repositoryService.addRole(participant1, re, GroupRoles.participant.name());
+		repositoryService.addRole(participant2, re, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		// groups
+		BusinessGroup group2 = businessGroupService.createBusinessGroup(groupCoach, "Coaching-grp-1", "tg", null, null, false, false, re);
+		businessGroupRelationDao.addRole(participant2, group2, GroupRoles.participant.name());
+		BusinessGroup group3 = businessGroupService.createBusinessGroup(groupCoach, "Coaching-grp-1", "tg", null, null, false, false, re);
+		businessGroupRelationDao.addRole(participant3, group3, GroupRoles.participant.name());
+		businessGroupRelationDao.addRole(participant4, group3, GroupRoles.participant.name());
+		dbInstance.commitAndCloseSession();
+		
+		//owner
+		List<Long> ownerIdentityKeys = coachingDAO.getStudents(owner, re);
+		Assert.assertNotNull(ownerIdentityKeys);
+		Assert.assertEquals(4, ownerIdentityKeys.size());
+		Assert.assertTrue(ownerIdentityKeys.contains(participant1.getKey()));
+		Assert.assertTrue(ownerIdentityKeys.contains(participant2.getKey()));
+		Assert.assertTrue(ownerIdentityKeys.contains(participant3.getKey()));
+		Assert.assertTrue(ownerIdentityKeys.contains(participant4.getKey()));
+		
+		//groups coach
+		List<Long> coachedIdentityKeys = coachingDAO.getStudents(groupCoach, re);
+		Assert.assertEquals(3, coachedIdentityKeys.size());
+		Assert.assertTrue(coachedIdentityKeys.contains(participant2.getKey()));
+		Assert.assertTrue(coachedIdentityKeys.contains(participant3.getKey()));
+		Assert.assertTrue(coachedIdentityKeys.contains(participant4.getKey()));
+	}
+
+	@Test
+	public void isCoach_owner() throws URISyntaxException {
+		URL coachingCourseUrl = CoachingLargeTest.class.getResource("CoachingCourse.zip");
+		File coachingCourseFile = new File(coachingCourseUrl.toURI());
+		RepositoryEntry re = CourseFactory.deployCourseFromZIP(coachingCourseFile, UUID.randomUUID().toString(), 4);
+		dbInstance.commitAndCloseSession();
+	
+		//members of courses
+		Identity coach = JunitTestHelper.createAndPersistIdentityAsRndUser("Owner-1-");
+		repositoryService.addRole(coach, re, GroupRoles.owner.name());
+		dbInstance.commitAndCloseSession();
+		
+		boolean canCoach = coachingDAO.isCoach(coach);
+		Assert.assertTrue(canCoach);
+	}
+	
+	@Test
+	public void isCoach_coach() throws URISyntaxException {
+		URL coachingCourseUrl = CoachingLargeTest.class.getResource("CoachingCourse.zip");
+		File coachingCourseFile = new File(coachingCourseUrl.toURI());
+		RepositoryEntry re = CourseFactory.deployCourseFromZIP(coachingCourseFile, UUID.randomUUID().toString(), 4);
+		dbInstance.commitAndCloseSession();
+	
+		//coach of course
+		Identity courseCoach = JunitTestHelper.createAndPersistIdentityAsRndUser("Coach-1");
+		repositoryService.addRole(courseCoach, re, GroupRoles.coach.name());
+		dbInstance.commitAndCloseSession();
+
+		//coach in a group of the course
+		Identity groupCoach = JunitTestHelper.createAndPersistIdentityAsRndUser("Coach-2");
+		BusinessGroup group = businessGroupService.createBusinessGroup(groupCoach, "Coaching-grp-1", "tg", null, null, false, false, re);
+		Assert.assertNotNull(group);
+		dbInstance.commitAndCloseSession();
+		
+		//check if coaching tool is enabled
+		boolean canCourseCoach = coachingDAO.isCoach(courseCoach);
+		Assert.assertTrue(canCourseCoach);
+		boolean canGroupCoach = coachingDAO.isCoach(groupCoach);
+		Assert.assertTrue(canGroupCoach);
+	}
+	
+	@Test
+	public void isCoach_notPermitted() throws URISyntaxException {
+		URL coachingCourseUrl = CoachingLargeTest.class.getResource("CoachingCourse.zip");
+		File coachingCourseFile = new File(coachingCourseUrl.toURI());
+		RepositoryEntry re = CourseFactory.deployCourseFromZIP(coachingCourseFile, UUID.randomUUID().toString(), 1);
+		dbInstance.commitAndCloseSession();
+	
+		//owner of course
+		Identity courseOwner = JunitTestHelper.createAndPersistIdentityAsRndUser("Coach-1");
+		repositoryService.addRole(courseOwner, re, GroupRoles.owner.name());
+		dbInstance.commitAndCloseSession();
+
+		//coach in a group of the course
+		Identity groupCoach = JunitTestHelper.createAndPersistIdentityAsRndUser("Coach-2");
+		BusinessGroup group = businessGroupService.createBusinessGroup(groupCoach, "Coaching-grp-1", "tg", null, null, false, false, re);
+		Assert.assertNotNull(group);
+		dbInstance.commitAndCloseSession();
+		
+		//check if coaching tool is enabled
+		boolean canCourseCoach = coachingDAO.isCoach(courseOwner);
+		Assert.assertTrue(canCourseCoach);
+		boolean canGroupCoach = coachingDAO.isCoach(groupCoach);
+		Assert.assertFalse(canGroupCoach);
+	}
+	
+	private StudentStatEntry getStudentStatEntry(IdentityRef identity, List<StudentStatEntry> entries) {
+		StudentStatEntry entry = null;
+		for(StudentStatEntry e:entries) {
+			if(e.getStudentKey().equals(identity.getKey())) {
+				entry = e;
+			}
+		}
+		return entry;
+	}
+	
+	private GroupStatEntry getGroupStatEntry(BusinessGroupRef group, List<GroupStatEntry> entries) {
+		GroupStatEntry entry = null;
+		for(GroupStatEntry e:entries) {
+			if(e.getGroupKey().equals(group.getKey())) {
+				entry = e;
+			}
+		}
+		return entry;
+	}
+	
+	private CourseStatEntry getCourseStatEntry(RepositoryEntryRef re, List<CourseStatEntry> entries) {
+		CourseStatEntry entry = null;
+		for(CourseStatEntry e:entries) {
+			if(e.getRepoKey().equals(re.getKey())) {
+				entry = e;
+			}
+		}
+		return entry;
+	}
+	
+	/**
+	 * To test performance against an external database ( of a customer ).
+	 */
+	@Test
+	@Ignore
+	public void testExtern() {
+		Identity coach = securityManager.loadIdentityByKey(46268418l);
+		if(coach != null) {
+			long start = System.nanoTime();
+			coachingDAO.getCoursesStatisticsNative(coach);
+			CodeHelper.printNanoTime(start, "Courses");
+			
+			start = System.nanoTime();
+			coachingDAO.getGroupsStatisticsNative(coach);
+			CodeHelper.printNanoTime(start, "Groups");
+			
+			start = System.nanoTime();
+			coachingDAO.getStudentsStatisticsNative(coach);
+			CodeHelper.printNanoTime(start, "Students");
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java
index ebf8b3b0debd6722d53d7a9592b7e46cf9c9cab0..151319e3458690840ef94eadeaca78fc462b0ad2 100644
--- a/src/test/java/org/olat/test/AllTestsJunit4.java
+++ b/src/test/java/org/olat/test/AllTestsJunit4.java
@@ -134,8 +134,8 @@ import org.junit.runners.Suite;
 	org.olat.modules.wiki.WikiUnitTest.class,//ok
 	org.olat.modules.wiki.versioning.diff.CookbookDiffTest.class,//ok
 	org.olat.modules.wiki.gui.components.wikiToHtml.FilterUtilTest.class,
-	org.olat.modules.coach.CoachingDAOTest.class,//ok
-	org.olat.modules.coach.CoachingServiceTest.class,//ok
+	org.olat.modules.coach.manager.CoachingDAOTest.class,//ok
+	org.olat.modules.coach.CoachingLargeTest.class,//ok
 	org.olat.properties.PropertyTest.class,//ok
 	org.olat.search.service.document.file.FileDocumentFactoryTest.class,
 	org.olat.search.service.document.file.PDFDocumentTest.class,