diff --git a/src/main/java/org/olat/admin/user/course/CourseOverviewController.java b/src/main/java/org/olat/admin/user/course/CourseOverviewController.java
index 0ed25decf6b7d36c1f155b61d30539631e0a0984..aebefce97e907b793574abc2062eaca8c284a786 100644
--- a/src/main/java/org/olat/admin/user/course/CourseOverviewController.java
+++ b/src/main/java/org/olat/admin/user/course/CourseOverviewController.java
@@ -70,7 +70,6 @@ import org.olat.group.BusinessGroupMembership;
 import org.olat.group.BusinessGroupService;
 import org.olat.group.BusinessGroupShort;
 import org.olat.group.model.BGRepositoryEntryRelation;
-import org.olat.group.ui.main.BusinessGroupTableModelWithType;
 import org.olat.group.ui.main.CourseMembership;
 import org.olat.group.ui.main.EditSingleMembershipController;
 import org.olat.group.ui.main.MemberPermissionChangeEvent;
@@ -123,7 +122,7 @@ public class CourseOverviewController extends BasicController  {
 	private BusinessGroupService businessGroupService;
 	
 	public CourseOverviewController(UserRequest ureq, WindowControl wControl, Identity identity) {
-		super(ureq, wControl, Util.createPackageTranslator(BusinessGroupTableModelWithType.class, ureq.getLocale()));
+		super(ureq, wControl, Util.createPackageTranslator(CourseMembership.class, ureq.getLocale()));
 		this.setTranslator(Util.createPackageTranslator(RepositoryService.class, getLocale(), getTranslator()));
 
 		editedIdentity = identity;
diff --git a/src/main/java/org/olat/group/ui/main/BusinessGroupNameColumnDescriptor.java b/src/main/java/org/olat/admin/user/groups/BusinessGroupNameColumnDescriptor.java
similarity index 92%
rename from src/main/java/org/olat/group/ui/main/BusinessGroupNameColumnDescriptor.java
rename to src/main/java/org/olat/admin/user/groups/BusinessGroupNameColumnDescriptor.java
index 731479d3e727ec3c8e2b09eaadf1aa0b9ea0eeb6..91c68316143fff14e63b2408023062880a8bd124 100644
--- a/src/main/java/org/olat/group/ui/main/BusinessGroupNameColumnDescriptor.java
+++ b/src/main/java/org/olat/admin/user/groups/BusinessGroupNameColumnDescriptor.java
@@ -17,14 +17,15 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.group.ui.main;
+package org.olat.admin.user.groups;
 
 import java.util.Locale;
 
+import org.olat.admin.user.groups.BusinessGroupTableModelWithType.Cols;
 import org.olat.core.gui.components.table.ColumnDescriptor;
 import org.olat.core.gui.components.table.CustomRenderColumnDescriptor;
 import org.olat.group.BusinessGroupShort;
-import org.olat.group.ui.main.BusinessGroupTableModelWithType.Cols;
+import org.olat.group.ui.main.BusinessGroupNameCellRenderer;
 
 /**
  * Show and sort business group name decorated
diff --git a/src/main/java/org/olat/admin/user/groups/BusinessGroupTableModelWithType.java b/src/main/java/org/olat/admin/user/groups/BusinessGroupTableModelWithType.java
new file mode 100644
index 0000000000000000000000000000000000000000..7c0ee26aca1f6522fd207d6defcdfda2d418ef5f
--- /dev/null
+++ b/src/main/java/org/olat/admin/user/groups/BusinessGroupTableModelWithType.java
@@ -0,0 +1,146 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <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
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <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>
+* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
+* University of Zurich, Switzerland.
+* <hr>
+* <a href="http://www.openolat.org">
+* OpenOLAT - Online Learning and Training</a><br>
+* This file has been modified by the OpenOLAT community. Changes are licensed
+* under the Apache 2.0 license as the original file.
+*/
+
+package org.olat.admin.user.groups;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.table.DefaultTableDataModel;
+import org.olat.core.gui.translator.Translator;
+import org.olat.group.BusinessGroupManagedFlag;
+import org.olat.group.BusinessGroupMembership;
+
+/**
+ * @author gnaegi
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+class BusinessGroupTableModelWithType extends DefaultTableDataModel<GroupOverviewRow> {
+	private final int columnCount;
+	private final Translator trans;
+
+	/**
+	 * @param owned list of business groups
+	 */
+	public BusinessGroupTableModelWithType(Translator trans, int columnCount) {
+		super(new ArrayList<GroupOverviewRow>());
+		this.trans = trans;
+		this.columnCount = columnCount;
+	}
+
+	/**
+	 * @see org.olat.core.gui.components.table.TableDataModel#getColumnCount()
+	 */
+	public int getColumnCount() {
+		return columnCount;
+	}
+
+	/**
+	 * @see org.olat.core.gui.components.table.TableDataModel#getValueAt(int, int)
+	 */
+	public Object getValueAt(int row, int col) {
+		GroupOverviewRow wrapped = objects.get(row);
+		switch (Cols.values()[col]) {
+			case name:
+				return wrapped;
+			case allowLeave: {
+				Boolean allowed = wrapped.getAllowLeave();
+				if(allowed != null && allowed.booleanValue()) {
+					//check managed groups
+					if(BusinessGroupManagedFlag.isManaged(wrapped.getManagedFlags(), BusinessGroupManagedFlag.membersmanagement)) {
+						return Boolean.FALSE;
+					}
+				}
+				return allowed;
+			}
+			case role:
+				return wrapped.getMembership();
+			case firstTime: {
+				BusinessGroupMembership membership = wrapped.getMembership();
+				return membership == null ? null : membership.getCreationDate();
+			}
+			case lastTime: {
+				BusinessGroupMembership membership = wrapped.getMembership();
+				return membership == null ? null : membership.getLastModified();
+			}
+			case key:
+				return wrapped.getKey().toString();
+			default:
+				return "ERROR";
+		}
+	}
+	
+	@Override
+	public Object createCopyWithEmptyList() {
+		return new BusinessGroupTableModelWithType(trans, columnCount);
+	}
+	
+	public boolean filterEditableGroupKeys(UserRequest ureq, List<Long> groupKeys) {
+		if(ureq.getUserSession().getRoles().isOLATAdmin() || ureq.getUserSession().getRoles().isGroupManager()) {
+			return false;
+		}
+		
+		int countBefore = groupKeys.size();
+		
+		for(GroupOverviewRow item:getObjects()) {
+			Long groupKey = item.getKey();
+			if(groupKeys.contains(groupKey)) {
+				BusinessGroupMembership membership = item.getMembership();
+				if(membership == null || !membership.isOwner()) {
+					groupKeys.remove(groupKey);
+				}
+			}
+		}
+		
+		return groupKeys.size() != countBefore;
+	}
+
+	/**
+	 * @param owned
+	 */
+	public void setEntries(List<GroupOverviewRow> owned) {
+		setObjects(owned);
+	}
+	
+	public enum Cols {
+		name("table.header.bgname"),
+		key("table.header.key"),
+		firstTime("table.header.firstTime"),
+		lastTime("table.header.lastTime"),
+		role("table.header.role"),
+		allowLeave("table.header.leave");
+		
+		private final String i18n;
+		
+		private Cols(String i18n) {
+			this.i18n = i18n;
+		}
+		
+		public String i18n() {
+			return i18n;
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/admin/user/groups/GroupOverviewController.java b/src/main/java/org/olat/admin/user/groups/GroupOverviewController.java
index 5a5c6f1ce18b8c5141879d58c1de4de81060d954..2f9fe6b93fc594a98f1f0654f0454e24023e0991 100644
--- a/src/main/java/org/olat/admin/user/groups/GroupOverviewController.java
+++ b/src/main/java/org/olat/admin/user/groups/GroupOverviewController.java
@@ -26,6 +26,7 @@ import java.util.List;
 import java.util.Map;
 
 import org.olat.NewControllerFactory;
+import org.olat.admin.user.groups.BusinessGroupTableModelWithType.Cols;
 import org.olat.basesecurity.GroupRoles;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.UserRequest;
@@ -61,10 +62,6 @@ import org.olat.group.model.AddToGroupsEvent;
 import org.olat.group.model.BusinessGroupMembershipChange;
 import org.olat.group.model.SearchBusinessGroupParams;
 import org.olat.group.ui.main.BGRoleCellRenderer;
-import org.olat.group.ui.main.BGTableItem;
-import org.olat.group.ui.main.BusinessGroupNameColumnDescriptor;
-import org.olat.group.ui.main.BusinessGroupTableModelWithType;
-import org.olat.group.ui.main.BusinessGroupTableModelWithType.Cols;
 
 /**
  * Description:<br>
@@ -156,10 +153,10 @@ public class GroupOverviewController extends BasicController {
 			memberships.put(membership.getGroupKey(), membership);
 		}
 
-		List<BGTableItem> items = new ArrayList<BGTableItem>();
+		List<GroupOverviewRow> items = new ArrayList<GroupOverviewRow>();
 		for(BusinessGroup group:groups) {
 			BusinessGroupMembership membership =  memberships.get(group.getKey());
-			BGTableItem tableItem = new BGTableItem(group, false, membership, Boolean.TRUE, Boolean.FALSE, null);
+			GroupOverviewRow tableItem = new GroupOverviewRow(group, membership, Boolean.TRUE);
 			items.add(tableItem);
 		}
 		tableDataModel.setEntries(items);
@@ -198,8 +195,8 @@ public class GroupOverviewController extends BasicController {
 		if (source == groupListCtr){
 			if (event.getCommand().equals(Table.COMMANDLINK_ROWACTION_CLICKED)) {
 				TableEvent te = (TableEvent) event;
-				BGTableItem item = tableDataModel.getObject(te.getRowId());
-				BusinessGroup currBusinessGroup = businessGroupService.loadBusinessGroup(item.getBusinessGroupKey());
+				GroupOverviewRow item = tableDataModel.getObject(te.getRowId());
+				BusinessGroup currBusinessGroup = businessGroupService.loadBusinessGroup(item.getKey());
 				if (currBusinessGroup==null) {
 					//group seems to be removed meanwhile, reload table and show error
 					showError("group.removed");
@@ -211,7 +208,7 @@ public class GroupOverviewController extends BasicController {
 				}
 			} else if (event instanceof TableMultiSelectEvent) {
 				TableMultiSelectEvent mse = (TableMultiSelectEvent)event;
-				List<BGTableItem> items = tableDataModel.getObjects(mse.getSelection());
+				List<GroupOverviewRow> items = tableDataModel.getObjects(mse.getSelection());
 				if (TABLE_ACTION_UNSUBSCRIBE.equals(mse.getAction())){
 					List<BusinessGroup> groups = toBusinessGroups(items);
 					doLeave(ureq, groups);
@@ -341,10 +338,10 @@ public class GroupOverviewController extends BasicController {
 		showInfo("unsubscribe.successful", groupNames.toString());	
 	}
 	
-	private List<BusinessGroup> toBusinessGroups(List<BGTableItem> items) {
+	private List<BusinessGroup> toBusinessGroups(List<GroupOverviewRow> items) {
 		List<Long> groupKeys = new ArrayList<Long>();
-		for(BGTableItem item:items) {
-			groupKeys.add(item.getBusinessGroupKey());
+		for(GroupOverviewRow item:items) {
+			groupKeys.add(item.getKey());
 		}
 		List<BusinessGroup> groups = businessGroupService.loadBusinessGroups(groupKeys);
 		return groups;
diff --git a/src/main/java/org/olat/admin/user/groups/GroupOverviewRow.java b/src/main/java/org/olat/admin/user/groups/GroupOverviewRow.java
new file mode 100644
index 0000000000000000000000000000000000000000..f65df499e1fa62740f0af4ec56c9d6aa35aba4f1
--- /dev/null
+++ b/src/main/java/org/olat/admin/user/groups/GroupOverviewRow.java
@@ -0,0 +1,98 @@
+/**
+ * <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.admin.user.groups;
+
+import org.olat.core.util.resource.OresHelper;
+import org.olat.group.BusinessGroup;
+import org.olat.group.BusinessGroupManagedFlag;
+import org.olat.group.BusinessGroupMembership;
+import org.olat.group.BusinessGroupShort;
+
+/**
+ * 
+ * Initial date: 05.10.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class GroupOverviewRow implements BusinessGroupShort {
+	private final BusinessGroupMembership member;
+	private final Boolean allowLeave;
+	private final Long key;
+	private final String name;
+	private final BusinessGroupManagedFlag[] managedflags;
+
+	public GroupOverviewRow(BusinessGroup businessGroup, BusinessGroupMembership member, Boolean allowLeave) {
+		key = businessGroup.getKey();
+		name = businessGroup.getName();
+		managedflags = businessGroup.getManagedFlags();
+		this.member = member;
+		this.allowLeave = allowLeave;
+	}
+
+	@Override
+	public Long getKey() {
+		return key;
+	}
+
+	@Override
+	public String getResourceableTypeName() {
+		return OresHelper.calculateTypeName(BusinessGroup.class);
+	}
+
+	@Override
+	public Long getResourceableId() {
+		return key;
+	}
+
+	@Override
+	public String getName() {
+		return name;
+	}
+
+	@Override
+	public BusinessGroupManagedFlag[] getManagedFlags() {
+		return managedflags;
+	}
+
+	public BusinessGroupMembership getMembership() {
+		return member;
+	}
+
+	public Boolean getAllowLeave() {
+		return allowLeave;
+	}
+
+	@Override
+	public int hashCode() {
+		return key.hashCode();
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		if(this == obj) {
+			return true;
+		}
+		if(obj instanceof GroupOverviewRow) {
+			GroupOverviewRow item = (GroupOverviewRow)obj;
+			return key != null && key.equals(item.key);
+		}
+		return false;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java
index 77de296d43abe1cccf20776f13387df1e4c0e6d9..2f7384ee522385f05c4c80871017e880463d3f2a 100644
--- a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java
+++ b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java
@@ -66,7 +66,6 @@ import org.olat.core.util.Util;
 import org.olat.core.util.coordinate.CoordinatorManager;
 import org.olat.core.util.coordinate.SyncerCallback;
 import org.olat.core.util.resource.OresHelper;
-import org.olat.group.BusinessGroupImpl;
 import org.olat.login.LoginModule;
 import org.olat.portfolio.manager.InvitationDAO;
 import org.olat.resource.OLATResource;
@@ -1073,7 +1072,7 @@ public class BaseSecurityManager implements BaseSecurity {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select ident from ").append(IdentityImpl.class.getName()).append(" as ident ")
 		  .append(" where not exists (")
-		  .append("   select bgroup from ").append(BusinessGroupImpl.class.getName()).append(" bgroup, bgroupmember as me")
+		  .append("   select bgroup from businessgroup bgroup, bgroupmember as me")
 		  .append("   where  me.group=bgroup.baseGroup and me.identity=ident")
 		  .append(" )");
 		if (status != null) {
diff --git a/src/main/java/org/olat/core/commons/persistence/PersistenceHelper.java b/src/main/java/org/olat/core/commons/persistence/PersistenceHelper.java
index 7bffea6fd258d3cd531329a9671aa3822526c22f..e10ea7d998b4d6c56ca5d7774e1c5bf0fafd35b2 100644
--- a/src/main/java/org/olat/core/commons/persistence/PersistenceHelper.java
+++ b/src/main/java/org/olat/core/commons/persistence/PersistenceHelper.java
@@ -146,16 +146,16 @@ public class PersistenceHelper {
 	
 	/**
 	 * Helper method that replaces * with % and appends and
-	 * prepends % to the string to make fuzzy SQL match when using like 
+	 * prepends % to the string to make fuzzy SQL match when using like.
+	 * Use "" to disable this feature and use exact match
 	 * @param email
 	 * @return fuzzized string
 	 */
 	public static final String makeFuzzyQueryString(String string) {
-		// By default only fuzzyfy at the end. Usually it makes no sense to do a
+		// By default only fuzzy at the end. Usually it makes no sense to do a
 		// fuzzy search with % at the beginning, but it makes the query very very
 		// slow since it can not use any index and must perform a fulltext search.
 		// User can always use * to make it a really fuzzy search query
-		// fxdiff FXOLAT-252: use "" to disable this feature and use exact match
 		if (string.length() > 1 && string.startsWith("\"") && string.endsWith("\"")) {			
 			string = string.substring(1, string.length()-1);
 		} else {
@@ -170,6 +170,19 @@ public class PersistenceHelper {
 		return string.toLowerCase();
 	}
 	
+	public static String makeEndFuzzyQueryString(String string) {
+		// By default only fuzzy at the end. Usually it makes no sense to do a
+		// fuzzy search with % at the beginning, but it makes the query very very
+		// slow since it can not use any index and must perform a fulltext search.
+		// User can always use * to make it a really fuzzy search query
+		string = string.replace('*', '%');
+		string = string + "%";
+		// with 'LIKE' the character '_' is a wildcard which matches exactly one character.
+		// To test for literal instances of '_', we have to escape it.
+		string = string.replace("_", "\\_");
+		return string.toLowerCase();
+	}
+	
 
 
 	/**
diff --git a/src/main/java/org/olat/course/assessment/manager/AssessmentModeDAO.java b/src/main/java/org/olat/course/assessment/manager/AssessmentModeDAO.java
index 69093aed32622d29669bf0492154037403c4c8de..e10d273222e762c73ee75e528a55624b92509024 100644
--- a/src/main/java/org/olat/course/assessment/manager/AssessmentModeDAO.java
+++ b/src/main/java/org/olat/course/assessment/manager/AssessmentModeDAO.java
@@ -41,7 +41,6 @@ import org.olat.course.assessment.AssessmentMode.Status;
 import org.olat.course.assessment.model.AssessmentModeImpl;
 import org.olat.course.assessment.model.SearchAssessmentModeParams;
 import org.olat.course.nodes.CourseNode;
-import org.olat.group.BusinessGroupImpl;
 import org.olat.group.BusinessGroupRef;
 import org.olat.group.area.BGtoAreaRelationImpl;
 import org.olat.repository.RepositoryEntryRef;
@@ -190,17 +189,17 @@ public class AssessmentModeDAO {
 		  .append(" left join mode.areas as modeToArea")
 		  .append(" where mode.key in (:modeKeys)")
 		  .append("  and ((mode.targetAudienceString in ('").append(AssessmentMode.Target.courseAndGroups.name()).append("','").append(AssessmentMode.Target.groups.name()).append("')")
-		  .append("   and (exists (select businessGroup from ").append(BusinessGroupImpl.class.getName()).append(" as businessGroup, bgroupmember as membership")
-		  .append("     where modeToGroup.businessGroup=businessGroup and membership.group=businessGroup.baseGroup and membership.identity.key=:identityKey")
+		  .append("   and (exists (select businessGroup from businessgroup as businessGroup, bgroupmember as membership")
+		  .append("     where modeToGroup.businessGroup.key=businessGroup.key and membership.group.key=businessGroup.baseGroup.key and membership.identity.key=:identityKey")
 		  .append("     and (membership.role='").append(GroupRoles.participant.name()).append("' or ")
 		  .append("       (mode.applySettingsForCoach=true and membership.role='").append(GroupRoles.coach.name()).append("'))")
-		  .append("   ) or exists (select areaToGroup from ").append(BGtoAreaRelationImpl.class.getName()).append(" as areaToGroup,").append(BusinessGroupImpl.class.getName()).append(" as businessGroupArea, bgroupmember as membership")
+		  .append("   ) or exists (select areaToGroup from ").append(BGtoAreaRelationImpl.class.getName()).append(" as areaToGroup,businessgroup as businessGroupArea, bgroupmember as membership")
 		  .append("     where modeToArea.area=areaToGroup.groupArea and areaToGroup.businessGroup=businessGroupArea and membership.group=businessGroupArea.baseGroup and membership.identity.key=:identityKey")
 		  .append("     and (membership.role='").append(GroupRoles.participant.name()).append("' or ")
 		  .append("       (mode.applySettingsForCoach=true and membership.role='").append(GroupRoles.coach.name()).append("'))")
 		  .append("  ))) or (mode.targetAudienceString in ('").append(AssessmentMode.Target.courseAndGroups.name()).append("','").append(AssessmentMode.Target.course.name()).append("')")
 		  .append("   and exists (select rel from repoentrytogroup as rel,  bgroupmember as membership ")
-		  .append("     where mode.repositoryEntry=rel.entry and membership.group=rel.group and rel.defaultGroup=true and membership.identity.key=:identityKey")
+		  .append("     where mode.repositoryEntry.key=rel.entry.key and membership.group.key=rel.group.key and rel.defaultGroup=true and membership.identity.key=:identityKey")
 		  .append("     and (membership.role='").append(GroupRoles.participant.name()).append("' or ")
 		  .append("       (mode.applySettingsForCoach=true and membership.role='").append(GroupRoles.coach.name()).append("'))")
 		  .append("  ))")
diff --git a/src/main/java/org/olat/course/member/CourseBusinessGroupListController.java b/src/main/java/org/olat/course/member/CourseBusinessGroupListController.java
index c17a3b03ef93c39118e5ecdc894b6f7807f13213..9030fa13bb9384194d87bb8e6c5c44da24a26cec 100644
--- a/src/main/java/org/olat/course/member/CourseBusinessGroupListController.java
+++ b/src/main/java/org/olat/course/member/CourseBusinessGroupListController.java
@@ -19,9 +19,11 @@
  */
 package org.olat.course.member;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
+import org.olat.core.commons.services.mark.Mark;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.EscapeMode;
 import org.olat.core.gui.components.form.flexible.FormItem;
@@ -47,8 +49,11 @@ import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
 import org.olat.core.util.StringHelper;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupManagedFlag;
+import org.olat.group.BusinessGroupMembership;
+import org.olat.group.model.BusinessGroupQueryParams;
+import org.olat.group.model.BusinessGroupRow;
 import org.olat.group.model.BusinessGroupSelectionEvent;
-import org.olat.group.model.SearchBusinessGroupParams;
+import org.olat.group.model.StatisticsBusinessGroupRow;
 import org.olat.group.ui.main.AbstractBusinessGroupListController;
 import org.olat.group.ui.main.BGAccessControlledCellRenderer;
 import org.olat.group.ui.main.BGResourcesCellRenderer;
@@ -156,6 +161,28 @@ public class CourseBusinessGroupListController extends AbstractBusinessGroupList
 		return columnsModel;
 	}
 
+	@Override
+	protected List<BGTableItem> searchTableItems(BusinessGroupQueryParams params) {
+		List<StatisticsBusinessGroupRow> rows = businessGroupService.findBusinessGroupsFromRepositoryEntry(params, getResource());
+		List<BGTableItem> items = new ArrayList<>(rows.size());
+		for(StatisticsBusinessGroupRow row:rows) {
+			BusinessGroupMembership membership = row.getMember();
+			Boolean allowLeave =  membership != null;
+			Boolean allowDelete = isAdmin() ? Boolean.TRUE : (membership == null ? null : new Boolean(membership.isOwner()));
+			
+			FormLink markLink = uifactory.addFormLink("mark_" + row.getKey(), "mark", "", null, null, Link.NONTRANSLATED);
+			markLink.setIconLeftCSS(row.isMarked() ? Mark.MARK_CSS_LARGE : Mark.MARK_ADD_CSS_LARGE);
+			
+			BGTableItem item = new BGTableItem(row, markLink, allowLeave, allowDelete);
+			item.setNumOfOwners(row.getNumOfCoaches());
+			item.setNumOfParticipants(row.getNumOfParticipants());
+			item.setNumWaiting(row.getNumWaiting());
+			item.setNumOfPendings(row.getNumPending());
+			items.add(item);
+		}
+		return items;
+	}
+
 	@Override
 	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
 		if(source == createGroup) {
@@ -163,7 +190,7 @@ public class CourseBusinessGroupListController extends AbstractBusinessGroupList
 		} else if (source == addGroup) {
 			doSelectGroups(ureq);
 		} else if(source == removeGroups) {
-			List<BGTableItem> selectedItems = getSelectedItems();
+			List<BusinessGroupRow> selectedItems = getSelectedItems();
 			if(selectedItems.isEmpty()) {
 				showWarning("error.select.one");
 			} else {
@@ -205,7 +232,7 @@ public class CourseBusinessGroupListController extends AbstractBusinessGroupList
 		} else if (source == confirmRemoveMultiResource) {
 			if (DialogBoxUIFactory.isYesEvent(event)) { // yes case
 				@SuppressWarnings("unchecked")
-				List<BGTableItem> selectedItems = (List<BGTableItem>)confirmRemoveMultiResource.getUserObject();
+				List<BusinessGroupRow> selectedItems = (List<BusinessGroupRow>)confirmRemoveMultiResource.getUserObject();
 				List<BusinessGroup> groups = toBusinessGroups(ureq, selectedItems, false);
 				doRemoveBusinessGroups(groups);
 			}
@@ -215,9 +242,9 @@ public class CourseBusinessGroupListController extends AbstractBusinessGroupList
 	}
 
 	@Override
-	protected void doCreate(UserRequest ureq, WindowControl wControl, RepositoryEntry re) {
+	protected void doCreate(UserRequest ureq, WindowControl wControl, RepositoryEntry entry) {
 		ureq.getUserSession().putEntry("wild_card_new", Boolean.TRUE);
-		super.doCreate(ureq, wControl, re);
+		super.doCreate(ureq, wControl, entry);
 	}
 
 	@Override
@@ -253,11 +280,11 @@ public class CourseBusinessGroupListController extends AbstractBusinessGroupList
 		}
 	}
 
-	private void doConfirmRemove(UserRequest ureq, List<BGTableItem> selectedItems) {
+	private void doConfirmRemove(UserRequest ureq, List<BusinessGroupRow> selectedItems) {
 		StringBuilder sb = new StringBuilder();
 		StringBuilder managedSb = new StringBuilder();
-		for(BGTableItem item:selectedItems) {
-			String gname = item.getBusinessGroupName() == null ? "???" : StringHelper.escapeHtml(item.getBusinessGroupName());
+		for(BusinessGroupRow item:selectedItems) {
+			String gname = item.getName() == null ? "???" : StringHelper.escapeHtml(item.getName());
 			if(BusinessGroupManagedFlag.isManaged(item.getManagedFlags(), BusinessGroupManagedFlag.resources)) {
 				if(managedSb.length() > 0) managedSb.append(", ");
 				managedSb.append(gname);
@@ -310,13 +337,13 @@ public class CourseBusinessGroupListController extends AbstractBusinessGroupList
 	}
 	
 	@Override
-	protected SearchBusinessGroupParams getSearchParams(SearchEvent event) {
-		return new SearchBusinessGroupParams();
+	protected BusinessGroupQueryParams getSearchParams(SearchEvent event) {
+		return new BusinessGroupQueryParams();
 	}
 
 	@Override
-	protected SearchBusinessGroupParams getDefaultSearchParams() {
-		return new SearchBusinessGroupParams();
+	protected BusinessGroupQueryParams getDefaultSearchParams() {
+		return new BusinessGroupQueryParams();
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/course/member/RemoveActionColumnDescriptor.java b/src/main/java/org/olat/course/member/RemoveActionColumnDescriptor.java
deleted file mode 100644
index c336295255948dc6269c9c6cf6faeb9c4ffe6933..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/course/member/RemoveActionColumnDescriptor.java
+++ /dev/null
@@ -1,78 +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.course.member;
-
-import org.olat.core.gui.components.table.DefaultColumnDescriptor;
-import org.olat.core.gui.render.Renderer;
-import org.olat.core.gui.render.StringOutput;
-import org.olat.core.gui.translator.Translator;
-import org.olat.group.BusinessGroupManagedFlag;
-import org.olat.group.ui.main.BGTableItem;
-import org.olat.group.ui.main.BusinessGroupTableModelWithType;
-
-/**
- * The remove link appear only if the group is not managed
- * 
- * Initial date: 10.07.2013<br>
- * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
- *
- */
-public class RemoveActionColumnDescriptor extends DefaultColumnDescriptor {
-
-	private final Translator translator;
-	
-	public RemoveActionColumnDescriptor(final String headerKey, final int dataColumn, final Translator translator) {
-		super(headerKey, dataColumn, null, translator.getLocale());
-		this.translator = translator;
-	}
-
-	@Override
-	public String getAction(int row) {
-		int sortedRow = table.getSortedRow(row);
-		
-		Object memberObj = table.getTableDataModel().getValueAt(sortedRow, BusinessGroupTableModelWithType.Cols.wrapper.ordinal());
-		if(memberObj instanceof BGTableItem) {
-			//owner, participant, or in waiting list can leave
-			BGTableItem item = (BGTableItem)memberObj;
-			boolean managed = BusinessGroupManagedFlag.isManaged(item.getManagedFlags(), BusinessGroupManagedFlag.resources);
-			if(managed) {
-				return null;
-			}
-		}
-		return CourseBusinessGroupListController.TABLE_ACTION_UNLINK;
-	}
-
-	@Override
-	public void renderValue(StringOutput sb, int row, Renderer renderer) {
-		int sortedRow = table.getSortedRow(row);
-		Object memberObj = table.getTableDataModel().getValueAt(sortedRow, BusinessGroupTableModelWithType.Cols.wrapper.ordinal());
-		
-		boolean managed = false;
-		if(memberObj instanceof BGTableItem) {
-			//owner, participant, or in waiting list can leave
-			BGTableItem item = (BGTableItem)memberObj;
-			managed = BusinessGroupManagedFlag.isManaged(item.getManagedFlags(), BusinessGroupManagedFlag.resources);
-		}
-		
-		if(!managed) {
-			sb.append(translator.translate(getHeaderKey()));
-		}
-	}
-}
diff --git a/src/main/java/org/olat/course/nodes/en/EnrollmentManager.java b/src/main/java/org/olat/course/nodes/en/EnrollmentManager.java
index e37070805e07eab5067739e8653d3b860c0d3fb9..9ed3db87ca0aa1a658b0bec75109f4379fda9ba4 100644
--- a/src/main/java/org/olat/course/nodes/en/EnrollmentManager.java
+++ b/src/main/java/org/olat/course/nodes/en/EnrollmentManager.java
@@ -52,7 +52,6 @@ import org.olat.course.groupsandrights.CourseGroupManager;
 import org.olat.course.nodes.ENCourseNode;
 import org.olat.course.properties.CoursePropertyManager;
 import org.olat.group.BusinessGroup;
-import org.olat.group.BusinessGroupImpl;
 import org.olat.group.BusinessGroupService;
 import org.olat.group.area.BGAreaManager;
 import org.olat.group.model.BGMembership;
@@ -284,7 +283,7 @@ public class EnrollmentManager extends BasicManager {
 		  .append("  and meWaiting.identity.key=:identityKey")
 		  .append(" ) as numOfMeWaiting")
 		  
-		  .append(" from ").append(BusinessGroupImpl.class.getName()).append(" grp ")
+		  .append(" from businessgroup grp ")
 		  .append(" inner join grp.baseGroup as baseGroup ")
 		  .append(" where grp.key in (:groupKeys)");
 		
diff --git a/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java b/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java
index 4bb494e93694baaec8e1ff57cd278a47d3372219..7ac15f3483f05caf2c39985addf78fe8d39bd6a7 100644
--- a/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java
+++ b/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java
@@ -61,7 +61,6 @@ import org.olat.course.nodes.gta.model.TaskListImpl;
 import org.olat.course.nodes.gta.ui.SubmitEvent;
 import org.olat.course.run.environment.CourseEnvironment;
 import org.olat.group.BusinessGroup;
-import org.olat.group.BusinessGroupImpl;
 import org.olat.group.BusinessGroupRef;
 import org.olat.group.BusinessGroupService;
 import org.olat.group.DeletableGroupData;
@@ -558,7 +557,7 @@ public class GTAManagerImpl implements GTAManager, DeletableGroupData {
 		  .append(" inner join tasklist.entry rentry ")
 		  .append(" where tasklist.entry.key=:entryKey and tasklist.courseNodeIdent=:courseNodeIdent and (task.identity.key=:identityKey ")
 		  .append(" or task.businessGroup.key in (")
-		  .append("   select bgroup.key from ").append(BusinessGroupImpl.class.getName()).append(" as bgroup ")
+		  .append("   select bgroup.key from businessgroup as bgroup ")
 		  .append("     inner join bgroup.baseGroup as baseGroup")
 		  .append("     inner join baseGroup.members as membership")
 		  .append("     where membership.identity.key=:identityKey and membership.role='").append(GroupRoles.participant.name()).append("'")
diff --git a/src/main/java/org/olat/group/BusinessGroupImpl.hbm.xml b/src/main/java/org/olat/group/BusinessGroupImpl.hbm.xml
deleted file mode 100644
index 884901a0a1cfba3b51989f3ecaf5da1561259689..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/group/BusinessGroupImpl.hbm.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE hibernate-mapping PUBLIC
-	"-//Hibernate/Hibernate Mapping DTD//EN"
-	"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
-
-<hibernate-mapping default-lazy="false">
-	<class name="org.olat.group.BusinessGroupImpl" table="o_gp_business">
-		<!--
-		key (see Interface org.olat.core.commons.persistence.Persistable),
-		lastModified (see Interface org.olat.core.commons.persistence.Auditable)
-		and creationDate (see Interface org.olat.core.commons.persistence.Auditable)
-		are attributes inherited from the abstract class
-		org.olat.core.commons.persistence.PersistentObject
-		-->
-		<id name="key" 
-			type="long" 
-			column="group_id" 
-			unsaved-value="null">
-			<generator class="hilo"/>
-		</id>
-		<property name="version" access="field" column="version" type="int"/>
-		<property name="lastModified" column="lastmodified" type="timestamp" />
-		<property name="creationDate" column="creationdate" type="timestamp" />
-  		
-  		<!--
-  		lastUsage helps the SYSTEMADMIN to find the BusinessGroups
-  		which were idle for some time.
-  		-->
-  		<property name="lastUsage" column="lastusage" type="timestamp" />   	
-		<property name="externalId" column="external_id" unique="false" not-null="false" type="string"/>
-		<property name="managedFlagsString" column="managed_flags" unique="false" not-null="false" type="string"/>
-		
-		<property name="ownersVisibleIntern" column="ownersintern" unique="false" not-null="true" type="boolean"/>
-		<property name="ownersVisiblePublic" column="ownerspublic" unique="false" not-null="true" type="boolean"/>
-		<property name="participantsVisibleIntern" column="participantsintern" unique="false" not-null="true" type="boolean"/>
-		<property name="participantsVisiblePublic" column="participantspublic" unique="false" not-null="true" type="boolean"/>
-		<property name="waitingListVisibleIntern" column="waitingintern" unique="false" not-null="true" type="boolean"/>
-		<property name="waitingListVisiblePublic" column="waitingpublic" unique="false" not-null="true" type="boolean"/>
-		<property name="downloadMembersLists" column="downloadmembers" unique="false" not-null="true" type="boolean"/>
-		<property name="allowToLeave" column="allowtoleave" unique="false" not-null="true" type="boolean"/>
-			 		
-		<property name="name" type="string" column="groupname" unique="false" length="255" index="gp_name_idx"/>	
-		<property name="description" type="string" column="descr" length="16777210" not-null="false"/>
-		<property name="minParticipants" column="minparticipants" not-null="false"/>
-		<property name="maxParticipants" column="maxparticipants" not-null="false"/>
-		<property name="waitingListEnabled" type="boolean" column="waitinglist_enabled" unique="false" not-null="false"/>	
-		<property name="autoCloseRanksEnabled" type="boolean" column="autocloseranks_enabled" unique="false" not-null="false"/>	
-		
-		<many-to-one name="resource" class="org.olat.resource.OLATResourceImpl"
-    		outer-join="true" cascade="none" lazy="false">
-			<column name="fk_resource" not-null="false" unique="true" />
-    	</many-to-one>
-
-		<many-to-one name="baseGroup"
-    		class="org.olat.basesecurity.model.GroupImpl"
-    		outer-join="true"
-    		cascade="persist,delete">
-			<column name="fk_group_id" not-null="false" unique="true" />
-    	</many-to-one>
-	</class>
-
-	<class name="org.olat.group.model.BusinessGroupShortImpl" table="o_gp_business" mutable="false">
-		<id name="key" type="long" column="group_id" unsaved-value="null">
-			<generator class="hilo"/>
-		</id>
-
-  		<property name="name" type="string" column="groupname" unique="false" length="255"/>
-		<property name="managedFlagsString" column="managed_flags" unique="false" not-null="false" type="string"/>
-	</class>
-</hibernate-mapping>
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/BusinessGroupImpl.java b/src/main/java/org/olat/group/BusinessGroupImpl.java
index 4b0b1040f37c3999153461b1b161ceaac575283c..f6e1a01427de85fae1a8a7da6bcf87015d8fba4f 100644
--- a/src/main/java/org/olat/group/BusinessGroupImpl.java
+++ b/src/main/java/org/olat/group/BusinessGroupImpl.java
@@ -27,13 +27,29 @@ package org.olat.group;
 
 import java.util.Date;
 
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.persistence.Version;
+
+import org.hibernate.annotations.GenericGenerator;
 import org.olat.basesecurity.Group;
-import org.olat.core.commons.persistence.PersistentObject;
+import org.olat.basesecurity.model.GroupImpl;
+import org.olat.core.id.ModifiedInfo;
+import org.olat.core.id.Persistable;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.resource.OLATResource;
+import org.olat.resource.OLATResourceImpl;
 
 /**
  * Description: <br>
@@ -43,33 +59,76 @@ import org.olat.resource.OLATResource;
  * 
  * @author patrick
  */
-
-public class BusinessGroupImpl extends PersistentObject implements BusinessGroup {
+@Entity(name="businessgroup")
+@Table(name="o_gp_business")
+public class BusinessGroupImpl implements Persistable, ModifiedInfo, BusinessGroup {
 
 	private static final long serialVersionUID = -6977108696910447781L;
 	private static final OLog log = Tracing.createLoggerFor(BusinessGroupImpl.class);
 	
+	@Id
+	@GeneratedValue(generator = "system-uuid")
+	@GenericGenerator(name = "system-uuid", strategy = "hilo")
+	@Column(name="group_id", nullable=false, unique=true, insertable=true, updatable=false)
+	private Long key;
+	@Version
+	private int version = 0;
+	
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="creationdate", nullable=false, insertable=true, updatable=false)
+	private Date creationDate;
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="lastmodified", nullable=false, insertable=true, updatable=true)
+	private Date lastModified;
+
+	@Column(name="descr", nullable=true, insertable=true, updatable=true)
 	private String description;
+	@Column(name="groupname", nullable=true, insertable=true, updatable=true)
 	private String name;
+	
+	@Column(name="external_id", nullable=true, insertable=true, updatable=true)
 	private String externalId;
+	@Column(name="managed_flags", nullable=true, insertable=true, updatable=true)
 	private String managedFlagsString;
+	
+	@Column(name="minparticipants", nullable=true, insertable=true, updatable=true)
 	private Integer minParticipants;
+	@Column(name="maxparticipants", nullable=true, insertable=true, updatable=true)
 	private Integer maxParticipants;
-	private OLATResource resource;
-	private Group baseGroup;
-	
-	private Date lastUsage;
+	@Column(name="waitinglist_enabled", nullable=true, insertable=true, updatable=true)
 	private Boolean waitingListEnabled;
+	@Column(name="autocloseranks_enabled", nullable=true, insertable=true, updatable=true)
 	private Boolean autoCloseRanksEnabled;
-	private Date lastModified;
+
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="lastusage", nullable=true, insertable=true, updatable=true)
+	private Date lastUsage;
+
+	@Column(name="ownersintern", nullable=true, insertable=true, updatable=true)
 	private boolean ownersVisibleIntern;
+	@Column(name="participantsintern", nullable=true, insertable=true, updatable=true)
 	private boolean participantsVisibleIntern;
+	@Column(name="waitingintern", nullable=true, insertable=true, updatable=true)
 	private boolean waitingListVisibleIntern;
+	@Column(name="ownerspublic", nullable=true, insertable=true, updatable=true)
 	private boolean ownersVisiblePublic;
+	@Column(name="participantspublic", nullable=true, insertable=true, updatable=true)
 	private boolean participantsVisiblePublic;
+	@Column(name="waitingpublic", nullable=true, insertable=true, updatable=true)
 	private boolean waitingListVisiblePublic;
+
+	@Column(name="downloadmembers", nullable=true, insertable=true, updatable=true)
 	private boolean downloadMembersLists;
+	@Column(name="allowtoleave", nullable=true, insertable=true, updatable=true)
 	private boolean allowToLeave;
+	
+	@ManyToOne(targetEntity=OLATResourceImpl.class,fetch=FetchType.LAZY, optional=true)
+	@JoinColumn(name="fk_resource", nullable=true, insertable=true, updatable=true)
+	private OLATResource resource;
+	
+	@ManyToOne(targetEntity=GroupImpl.class,fetch=FetchType.LAZY,optional=false)
+	@JoinColumn(name="fk_group_id", nullable=false, insertable=true, updatable=false)
+	private Group baseGroup;
 
 	/**
 	 * constructs an unitialised BusinessGroup, use setXXX for setting attributes
@@ -94,6 +153,27 @@ public class BusinessGroupImpl extends PersistentObject implements BusinessGroup
 		setLastUsage(new Date());
 		setLastModified(new Date());
 	}
+	
+	@Override
+	public Long getKey() {
+		return key;
+	}
+
+	@Override
+	public Date getCreationDate() {
+		return creationDate;
+	}
+
+	@Override
+	public Date getLastModified() {
+		return lastModified;
+	}
+
+	@Override
+	public void setLastModified(Date date) {
+		this.lastModified = date;
+	}
+
 
 	/**
 	 * @param groupName
@@ -337,25 +417,13 @@ public class BusinessGroupImpl extends PersistentObject implements BusinessGroup
 		return false;
 	}
 	
+	@Override
+	public boolean equalsByPersistableKey(Persistable persistable) {
+		return equals(persistable);
+	}
+	
 	@Override
 	public int hashCode() {
 		return getKey() == null ? 2901 : getKey().hashCode();
 	}
-
-	/**
-	 * 
-	 * @see org.olat.core.id.ModifiedInfo#getLastModified()
-	 */
-	public Date getLastModified() {
-		return lastModified;
-	}
-
-	/**
-	 * 
-	 * @see org.olat.core.id.ModifiedInfo#setLastModified(java.util.Date)
-	 */
-	public void setLastModified(Date date) {
-		this.lastModified = date;
-	}
-
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/BusinessGroupService.java b/src/main/java/org/olat/group/BusinessGroupService.java
index e7d8213f76a6945478685e9cf1cd79d37adfccd5..a964004eebc20743fb093e69dfc5f046722f23b2 100644
--- a/src/main/java/org/olat/group/BusinessGroupService.java
+++ b/src/main/java/org/olat/group/BusinessGroupService.java
@@ -35,9 +35,13 @@ import org.olat.group.area.BGArea;
 import org.olat.group.model.BGRepositoryEntryRelation;
 import org.olat.group.model.BusinessGroupEnvironment;
 import org.olat.group.model.BusinessGroupMembershipChange;
+import org.olat.group.model.BusinessGroupQueryParams;
+import org.olat.group.model.BusinessGroupRow;
 import org.olat.group.model.EnrollState;
 import org.olat.group.model.LeaveOption;
 import org.olat.group.model.MembershipModification;
+import org.olat.group.model.OpenBusinessGroupRow;
+import org.olat.group.model.StatisticsBusinessGroupRow;
 import org.olat.group.model.SearchBusinessGroupParams;
 import org.olat.repository.LeavingStatusList;
 import org.olat.repository.RepositoryEntry;
@@ -267,7 +271,7 @@ public interface BusinessGroupService {
 	public List<BusinessGroup> findBusinessGroups(SearchBusinessGroupParams params, RepositoryEntryRef resource, int firstResult, int maxResults, BusinessGroupOrder... ordering);
 	
 	/**
-	 * Find business groups (the view)
+	 * Find my favorite business groups with some additional useful informations
 	 * @param params
 	 * @param resource
 	 * @param firstResult
@@ -275,14 +279,48 @@ public interface BusinessGroupService {
 	 * @param ordering
 	 * @return
 	 */
-	public List<BusinessGroupView> findBusinessGroupViews(SearchBusinessGroupParams params, RepositoryEntryRef resource, int firstResult, int maxResults, BusinessGroupOrder... ordering);
+	public List<BusinessGroupRow> findBusinessGroupsWithMemberships(BusinessGroupQueryParams params, IdentityRef identity);
 	
 	/**
-	 * Find all groups within resources where the identity is author.
-	 * @param author
+	 * Retrieve the business groups of a repository entry with the number of coaches, participants,
+	 * user in waiting list and reservation in each groups. For each groups, there is as additional
+	 * informations the courses linked to them, and the list of offers.
+	 *  
+	 * @param params
+	 * @param entryRef
+	 * @return
+	 */
+	public List<StatisticsBusinessGroupRow> findBusinessGroupsFromRepositoryEntry(BusinessGroupQueryParams params, RepositoryEntryRef entry);
+	
+	/**
+	 * Retrieve the business groups of a repository entry with the number of coaches, participants,
+	 * user in waiting list and reservation in each groups. For each groups, there is as additional
+	 * informations the courses linked to them, the list of offers, and the book mark flag for the
+	 * specified identity.
+	 * 
+	 * @param params
+	 * @param identity
+	 * @return
+	 */
+	public List<StatisticsBusinessGroupRow> findBusinessGroupsForSelection(BusinessGroupQueryParams params, IdentityRef identity);
+	
+	/**
+	 * Retrieve the business groups of a repository entry with the number of coaches, participants,
+	 * user in waiting list and reservation in each groups.
+	 * 
+	 * @param params
+	 * @return
+	 */
+	public List<StatisticsBusinessGroupRow> findBusinessGroupsStatistics(BusinessGroupQueryParams params);
+	
+	/**
+	 * Retrieve the published/open business groups of a repository entry with the number of participants
+	 * and reservation in each groups.
+	 * 
+	 * @param params
 	 * @return
 	 */
-	public List<BusinessGroupView> findBusinessGroupViewsWithAuthorConnection(Identity author);
+	public List<OpenBusinessGroupRow> findPublishedBusinessGroups(BusinessGroupQueryParams params, IdentityRef identity);
 	
 	public List<Long> toGroupKeys(String groupNames, RepositoryEntryRef resource);
 
diff --git a/src/main/java/org/olat/group/BusinessGroupView.java b/src/main/java/org/olat/group/BusinessGroupView.java
deleted file mode 100644
index 29b7f6824a11ca548040aa4c8f166c1342b4085a..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/group/BusinessGroupView.java
+++ /dev/null
@@ -1,107 +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>
- * 2011 by frentix GmbH, http://www.frentix.com
- * <p>
-**/
-package org.olat.group;
-
-import java.util.Date;
-
-import org.olat.core.id.CreateInfo;
-import org.olat.core.id.ModifiedInfo;
-import org.olat.core.id.OLATResourceable;
-import org.olat.core.id.Persistable;
-import org.olat.resource.OLATResource;
-
-/**
- * 
- * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
- */
-public interface BusinessGroupView extends BusinessGroupShort, Persistable, CreateInfo, ModifiedInfo, OLATResourceable {
-
-	/**
-	 * @return The group display name (not system unique)
-	 */
-	public String getName();
-
-	/**
-	 * @return The group description or NULL if none set.
-	 */
-	public String getDescription();
-	
-	/**
-	 * @return The associated resource
-	 */
-	public OLATResource getResource();
-	
-	
-	public long getNumOfRelations();
-	
-	public long getNumOfOwners();
-	
-	public long getNumOfParticipants();
-	
-	/**
-	 * Number of pending reservations
-	 * @return
-	 */
-	public long getNumOfPendings();
-	
-	public long getNumWaiting();
-	
-	/**
-	 * @return The number of offers linked to this group (absolute number)
-	 */
-	public long getNumOfOffers();
-	
-	/**
-	 * @return The number of currently valid offers
-	 */
-	public long getNumOfValidOffers();
-
-
-	/**
-	 * @return last usage of this group
-	 */
-	public Date getLastUsage();
-
-	/**
-	 * @return the maximal number of participants
-	 */
-	public Integer getMaxParticipants();
-
-	/**
-	 * @return the minimal number of participants
-	 */
-	public Integer getMinParticipants();
-	
-	/**
-	 * @return true: if the waiting list will automaticly close ranks to participant list 
-	 */
-	public Boolean getAutoCloseRanksEnabled();
-
-	/**
-	 * @return true: if waiting-list is enabled
-	 */
-	public Boolean getWaitingListEnabled();
-	
-	/**
-	 * @return The external ID
-	 */
-	public String getExternalId();
-
-}
diff --git a/src/main/java/org/olat/group/manager/BusinessGroupArchiver.java b/src/main/java/org/olat/group/manager/BusinessGroupArchiver.java
index 3878c9162789ad0cdb43ebff8f037e31480bb688..be7b7a55f4284b9d9f1799f9a71f37f500d03935 100644
--- a/src/main/java/org/olat/group/manager/BusinessGroupArchiver.java
+++ b/src/main/java/org/olat/group/manager/BusinessGroupArchiver.java
@@ -40,7 +40,6 @@ import org.olat.core.util.Util;
 import org.olat.core.util.filter.FilterFactory;
 import org.olat.core.util.i18n.I18nModule;
 import org.olat.group.BusinessGroup;
-import org.olat.group.BusinessGroupImpl;
 import org.olat.group.ui.BGControllerFactory;
 import org.olat.user.UserManager;
 import org.olat.user.propertyhandlers.UserPropertyHandler;
@@ -125,7 +124,7 @@ public class BusinessGroupArchiver {
 	
 	public List<GroupMembership> getMembers(BusinessGroup group) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select membership from ").append(BusinessGroupImpl.class.getName()).append(" as bgroup ")
+		sb.append("select membership from businessgroup as bgroup ")
 		  .append(" inner join bgroup.baseGroup as baseGroup")
 		  .append(" inner join baseGroup.members as membership")
 		  .append(" where bgroup.key=:businessGroupKey");
diff --git a/src/main/java/org/olat/group/manager/BusinessGroupDAO.java b/src/main/java/org/olat/group/manager/BusinessGroupDAO.java
index 929b0a8685cf0da6558e65fde4521fc0cf41d862..ec463a459a03b85e087dabebd2d151d8fd3962af 100644
--- a/src/main/java/org/olat/group/manager/BusinessGroupDAO.java
+++ b/src/main/java/org/olat/group/manager/BusinessGroupDAO.java
@@ -29,13 +29,14 @@ import java.util.Map;
 
 import javax.persistence.EntityManager;
 import javax.persistence.LockModeType;
-import javax.persistence.TemporalType;
 import javax.persistence.TypedQuery;
 
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.Group;
 import org.olat.basesecurity.GroupRoles;
+import org.olat.basesecurity.IdentityRef;
 import org.olat.basesecurity.manager.GroupDAO;
+import org.olat.basesecurity.model.GroupMembershipImpl;
 import org.olat.collaboration.CollaborationTools;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.commons.persistence.PersistenceHelper;
@@ -49,20 +50,25 @@ import org.olat.group.BusinessGroupMembership;
 import org.olat.group.BusinessGroupModule;
 import org.olat.group.BusinessGroupOrder;
 import org.olat.group.BusinessGroupShort;
-import org.olat.group.BusinessGroupView;
-import org.olat.group.model.BGRepositoryEntryRelation;
 import org.olat.group.model.BusinessGroupMembershipImpl;
 import org.olat.group.model.BusinessGroupMembershipViewImpl;
-import org.olat.group.model.BusinessGroupShortImpl;
-import org.olat.group.model.BusinessGroupViewImpl;
+import org.olat.group.model.BusinessGroupQueryParams;
+import org.olat.group.model.BusinessGroupRow;
+import org.olat.group.model.BusinessGroupToSearch;
 import org.olat.group.model.IdentityGroupKey;
+import org.olat.group.model.OpenBusinessGroupRow;
+import org.olat.group.model.StatisticsBusinessGroupRow;
 import org.olat.group.model.SearchBusinessGroupParams;
 import org.olat.properties.Property;
-import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryEntryRef;
+import org.olat.repository.RepositoryEntryShort;
 import org.olat.resource.OLATResource;
 import org.olat.resource.OLATResourceManager;
+import org.olat.resource.accesscontrol.model.AccessMethod;
+import org.olat.resource.accesscontrol.model.OfferAccessImpl;
 import org.olat.resource.accesscontrol.model.OfferImpl;
+import org.olat.resource.accesscontrol.model.Price;
+import org.olat.resource.accesscontrol.model.PriceMethodBundle;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -154,7 +160,7 @@ public class BusinessGroupDAO {
 	
 	public BusinessGroup load(Long key) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select bgi from ").append(BusinessGroupImpl.class.getName()).append(" bgi ")
+		sb.append("select bgi from businessgroup bgi ")
 		  .append(" left join fetch bgi.baseGroup baseGroup")
 		  .append(" left join fetch bgi.resource resource")
 		  .append(" where bgi.key=:key");
@@ -169,16 +175,12 @@ public class BusinessGroupDAO {
 		if(ids == null || ids.isEmpty()) {
 			return Collections.emptyList();
 		}
-		StringBuilder sb = new StringBuilder();
-		sb.append("select bgi from ").append(BusinessGroupShortImpl.class.getName()).append(" bgi ")
-		  .append(" where bgi.key in (:ids)");
 
-		List<BusinessGroupShort> groups = dbInstance.getCurrentEntityManager()
-				.createQuery(sb.toString(), BusinessGroupShort.class)
+		return dbInstance.getCurrentEntityManager()
+				.createNamedQuery("loadBusinessGroupShortByIds", BusinessGroupShort.class)
 				.setParameter("ids", ids)
 				.setHint("org.hibernate.cacheable", Boolean.TRUE)
 				.getResultList();
-		return groups;
 	}
 	
 	public List<BusinessGroup> load(Collection<Long> ids) {
@@ -186,7 +188,7 @@ public class BusinessGroupDAO {
 			return Collections.emptyList();
 		}
 		StringBuilder sb = new StringBuilder();
-		sb.append("select bgi from ").append(BusinessGroupImpl.class.getName()).append(" bgi ")
+		sb.append("select bgi from businessgroup bgi ")
 		  .append(" inner join fetch bgi.resource resource")
 		  .append(" where bgi.key in (:ids)");
 
@@ -199,7 +201,7 @@ public class BusinessGroupDAO {
 	
 	public List<BusinessGroup> loadAll() {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select bgi from ").append(BusinessGroupImpl.class.getName()).append(" bgi ")
+		sb.append("select bgi from businessgroup bgi ")
 		  .append(" inner join fetch bgi.resource resource");
 
 		List<BusinessGroup> groups = dbInstance.getCurrentEntityManager()
@@ -210,10 +212,9 @@ public class BusinessGroupDAO {
 	
 	public BusinessGroup loadForUpdate(Long id) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select bgi from ").append(BusinessGroupImpl.class.getName()).append(" bgi ")
+		sb.append("select bgi from businessgroup bgi ")
 			.append(" inner join fetch bgi.resource resource")
 			.append(" where bgi.key=:key");
-		
 		List<BusinessGroup> groups = dbInstance.getCurrentEntityManager()
 				.createQuery(sb.toString(), BusinessGroup.class)
 				.setParameter("key", id)
@@ -223,6 +224,23 @@ public class BusinessGroupDAO {
 		return groups.get(0);
 	}
 	
+	public BusinessGroup loadForUpdate(BusinessGroup group) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select bgi from businessgroup bgi ")
+			.append(" inner join fetch bgi.resource resource")
+			.append(" where bgi.key=:key");
+		if(dbInstance.getCurrentEntityManager().contains(group)) {
+			dbInstance.getCurrentEntityManager().detach(group);
+		}
+		List<BusinessGroup> groups = dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), BusinessGroup.class)
+				.setParameter("key", group.getKey())
+				.setLockMode(LockModeType.PESSIMISTIC_WRITE)
+				.getResultList();
+		if(groups.isEmpty()) return null;
+		return groups.get(0);
+	}
+	
 	public BusinessGroup merge(BusinessGroup group) {
 		EntityManager em = dbInstance.getCurrentEntityManager();
 		BusinessGroup mergedGroup = em.merge(group);
@@ -270,7 +288,7 @@ public class BusinessGroupDAO {
 		
 		StringBuilder sb = new StringBuilder(); 
 		sb.append("select membership.identity.key, membership.creationDate, membership.lastModified, membership.role, grp.key ")
-		  .append(" from ").append(BusinessGroupImpl.class.getName()).append(" as grp ")
+		  .append(" from businessgroup as grp ")
 		  .append(" inner join grp.baseGroup as baseGroup ")
 		  .append(" inner join baseGroup.members as membership ")
 		  .append(" where grp.key in (:groupKeys)");
@@ -366,7 +384,7 @@ public class BusinessGroupDAO {
 		}
 		
 		StringBuilder sb = new StringBuilder(); 
-		sb.append("select bgi.key from ").append(BusinessGroupImpl.class.getName()).append(" as bgi ")
+		sb.append("select bgi.key from businessgroup as bgi ")
 		  .append(" inner join bgi.baseGroup as baseGroup")
 		  .append(" inner join baseGroup.members as bmember")
 		  .append(" where bgi.key in (:groupKeys) and bmember.identity.key=:identityKey and bmember.role in (:roles)");
@@ -394,7 +412,7 @@ public class BusinessGroupDAO {
 	
 	public List<BusinessGroup> findBusinessGroup(Identity identity, int maxResults, BusinessGroupOrder... ordering) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select bgi from ").append(BusinessGroupImpl.class.getName()).append(" as bgi ")
+		sb.append("select bgi from businessgroup as bgi ")
 		  .append(" inner join fetch bgi.resource as bgResource")
 		  .append(" inner join fetch bgi.baseGroup as baseGroup")
 		  .append(" where exists (select bmember from bgroupmember as bmember")
@@ -425,7 +443,7 @@ public class BusinessGroupDAO {
 	
 	public BusinessGroup findBusinessGroup(Group baseGroup) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select bgs from ").append(BusinessGroupImpl.class.getName()).append(" as bgs ")
+		sb.append("select bgs from businessgroup as bgs ")
 		  .append(" inner join fetch bgs.resource as bgResource")
 		  .append(" inner join fetch bgs.baseGroup as baseGroup")
 		  .append(" where baseGroup=:group");
@@ -439,7 +457,7 @@ public class BusinessGroupDAO {
 	
 	public List<BusinessGroup> findBusinessGroupsWithWaitingListAttendedBy(Identity identity, RepositoryEntryRef repoEntry) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select bgs from ").append(BusinessGroupImpl.class.getName()).append(" as bgs ")
+		sb.append("select bgs from businessgroup as bgs ")
 		  .append(" inner join fetch bgs.resource as bgResource")
 		  .append(" inner join fetch bgs.baseGroup as baseGroup")
 		  .append(" inner join baseGroup.members as membership")
@@ -485,7 +503,7 @@ public class BusinessGroupDAO {
 		} else {
 			query.append("select count(bgi.key) from ");
 		}
-		query.append(org.olat.group.BusinessGroupImpl.class.getName()).append(" as bgi ");
+		query.append("businessgroup as bgi ");
 
 		//inner joins
 		if(BusinessGroup.class.equals(resultClass)) {
@@ -494,27 +512,11 @@ public class BusinessGroupDAO {
 			query.append("inner join bgi.resource bgResource ");
 		}
 
-		if(StringHelper.containsNonWhitespace(params.getOwnerName()) || params.getResources() != null ||
-				resource != null || params.isOwner() || params.isAttendee() || params.isWaiting()) {
+		if(resource != null || params.isOwner() || params.isAttendee() || params.isWaiting()) {
 			query.append(" inner join bgi.baseGroup as baseGroup");
 		}
 
 		boolean where = false;
-		if(StringHelper.containsNonWhitespace(params.getOwnerName())) {
-			where = true;
-			query.append(" inner join baseGroup.members as ownerMember on ownerMember.role='coach'")
-			     .append(" inner join ownerMember.identity as identity")
-			     .append(" inner join identity.user as user")
-			     .append(" where ");
-			//query the name in login, firstName and lastName
-
-			searchLikeUserProperty(query, "firstName", "owner");
-			query.append(" or ");
-			searchLikeUserProperty(query, "lastName", "owner");
-			query.append(" or ");
-			searchLikeAttribute(query, "identity", "name", "owner");
-		}
-
 		if(StringHelper.containsNonWhitespace(params.getExternalId())) {
 			where = where(query, where);
 			query.append("bgi.externalId=:externalId");
@@ -556,11 +558,6 @@ public class BusinessGroupDAO {
 			query.append(" exists (")
 			     .append("   select relation from repoentrytogroup as relation where relation.group=baseGroup and relation.entry.key=:resourceKey")
 			     .append(" )");
-		} else if(params.getResources() != null) {
-			where = where(query, where);
-			query.append(" ").append(params.getResources().booleanValue() ? "" : "not").append(" exists (")
-			     .append("   select relation from repoentrytogroup as relation where relation.group=baseGroup")
-			     .append(" )");
 		}
 		
 		if(StringHelper.containsNonWhitespace(params.getCourseTitle())) {
@@ -591,31 +588,6 @@ public class BusinessGroupDAO {
 			}
 		}
 		
-		if(params.getPublicGroups() != null) {
-			where = where(query, where);
-			if(params.getPublicGroups().booleanValue()) {
-		    query.append(" bgResource.key in (")
-		         .append("   select offer.resource.key from ").append(OfferImpl.class.getName()).append(" offer ")
-		         .append("     where offer.valid=true")
-		         .append("     and (offer.validFrom is null or offer.validFrom<=:atDate)")
-						 .append("     and (offer.validTo is null or offer.validTo>=:atDate)")
-						 .append(" )");
-			} else {
-		    query.append(" bgResource.key not in (")
-		         .append("   select offer.resource.key from ").append(OfferImpl.class.getName()).append(" offer ")
-		         .append("     where offer.valid=true")
-		         .append(" )");
-			}
-		}
-		
-		if(params.getMarked() != null) {
-			where = where(query, where);
-			query.append(" bgi.key ").append(params.getMarked().booleanValue() ? "" : "not").append(" in (")
-			     .append("   select mark.resId from ").append(MarkImpl.class.getName()).append(" mark ")
-			     .append("     where mark.resName='BusinessGroup' and mark.creator.key=:identId")
-			     .append(" )");
-		}
-		
 		if(StringHelper.containsNonWhitespace(params.getNameOrDesc())) {
 			where = where(query, where);
 			query.append("(");
@@ -664,12 +636,9 @@ public class BusinessGroupDAO {
 
 		TypedQuery<T> dbq = dbInstance.getCurrentEntityManager().createQuery(query.toString(), resultClass);
 		//add parameters
-		if(params.isOwner() || params.isAttendee() || params.isWaiting() || params.getMarked() != null) {
+		if(params.isOwner() || params.isAttendee() || params.isWaiting()) {
 			dbq.setParameter("identId", params.getIdentity().getKey());
 		}
-		if(params.getPublicGroups() != null && params.getPublicGroups().booleanValue()) {
-			dbq.setParameter("atDate", new Date(), TemporalType.TIMESTAMP);
-		}
 		if(params.getGroupKeys() != null && !params.getGroupKeys().isEmpty()) {
 			dbq.setParameter("groupKeys", params.getGroupKeys());
 		}
@@ -690,9 +659,6 @@ public class BusinessGroupDAO {
 		if(params.getTools() != null && !params.getTools().isEmpty()) {
 			dbq.setParameter("tools", params.getTools());
 		}
-		if(StringHelper.containsNonWhitespace(params.getOwnerName())) {
-			dbq.setParameter("owner", makeFuzzyQueryString(params.getOwnerName()));
-		}
 		if(roles != null) {
 			dbq.setParameter("roles", roles);
 		}
@@ -715,273 +681,597 @@ public class BusinessGroupDAO {
 		return dbq;
 	}
 	
-	public List<BusinessGroupView> findBusinessGroupWithAuthorConnection(Identity author) {
-		StringBuilder sb = new StringBuilder();
-		sb.append("select bgi from ").append(BusinessGroupViewImpl.class.getName()).append(" as bgi ")
-		  .append(" inner join fetch bgi.resource bgResource ")
-		  .append(" inner join fetch bgi.baseGroup as baseGroup")
-		  .append(" where baseGroup in (select baseRelGroup.group from ").append(RepositoryEntry.class.getName()).append(" as v, ")
-		  .append("   repoentrytogroup as baseRelGroup, repoentrytogroup as relGroup, bgroupmember as remembership ")
-		  .append("     where baseRelGroup.entry=v and relGroup.entry=v and relGroup.group=remembership.group ")
-		  .append("     and remembership.identity.key=:authorKey")
-		  .append("    ")
-		  .append(" )");
+	/**
+	 * 	
+	 * @param params
+	 * @param identity
+	 * @return
+	 */
+	public List<BusinessGroupRow> searchBusinessGroupsWithMemberships(BusinessGroupQueryParams params, IdentityRef identity) {
+	    StringBuilder sm = new StringBuilder();
+		sm.append("select memberships, bgi");
+		appendMarkedSubQuery(sm, params);
+		sm.append(" from businessgrouptosearch as bgi ")
+		  .append(" inner join fetch bgi.resource as bgResource ")
+		  .append(" inner join bgi.baseGroup as bGroup ");
+		filterBusinessGroupToSearch(sm, params, true);
+
+		TypedQuery<Object[]> objectsQuery = dbInstance.getCurrentEntityManager()
+				.createQuery(sm.toString(), Object[].class);
+		filterBusinessGroupToSearchParameters(objectsQuery, params, identity, true);
 		
+		List<Object[]> objects = objectsQuery.getResultList();
+		List<BusinessGroupRow> groups = new ArrayList<>(objects.size());
+		Map<Long,BusinessGroupRow> keyToGroup = new HashMap<>();
+		Map<Long,BusinessGroupRow> resourceKeyToGroup = new HashMap<>();
+		for(Object[] object:objects) {
+			BusinessGroupToSearch businessGroup = (BusinessGroupToSearch)object[1];
+			
+			BusinessGroupRow row;
+			if(keyToGroup.containsKey(businessGroup.getKey())) {
+				row = keyToGroup.get(businessGroup.getKey());
+			} else {
+				row = new BusinessGroupRow(businessGroup);
+				groups.add(row);
+				keyToGroup.put(businessGroup.getKey(), row);
+				resourceKeyToGroup.put(businessGroup.getResource().getKey(), row);
+			}
+
+			Number numOfMarks = (Number)object[2];
+			row.setMarked(numOfMarks == null ? false : numOfMarks.intValue() > 0);
+			addMembershipToRow(row, (GroupMembershipImpl)object[0]);
+		}
 		
-		// membership.identity.key=:authorKey
+		loadRelations(keyToGroup, params, identity);
+		loadOfferAccess(resourceKeyToGroup);	
+		return groups;
+	}
+	
+	public List<StatisticsBusinessGroupRow> searchBusinessGroupsForSelection(BusinessGroupQueryParams params, IdentityRef identity) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select bgi, ")
+		  .append(" (select count(nCoaches.key) from bgroupmember as nCoaches ")
+		  .append("  where nCoaches.group.key=bgi.baseGroup.key and nCoaches.role='").append(GroupRoles.coach.name()).append("'")
+		  .append(" ) as numOfCoaches,")
+		  .append(" (select count(nParticipants.key) from bgroupmember as nParticipants ")
+		  .append("  where nParticipants.group.key=bgi.baseGroup.key and nParticipants.role='").append(GroupRoles.participant.name()).append("'")
+		  .append(" ) as numOfParticipants,")
+		  .append(" (select count(nWaiting.key) from bgroupmember as nWaiting ")
+		  .append("  where bgi.waitingListEnabled=true and nWaiting.group.key=bgi.baseGroup.key and nWaiting.role='").append(GroupRoles.waiting.name()).append("'")
+		  .append(" ) as numWaiting,")
+		  .append(" (select count(reservation.key) from resourcereservation as reservation ")
+		  .append("  where reservation.resource.key=bgi.resource.key")
+		  .append(" ) as numOfReservations,")
+		  .append(" (select count(mark.key) from ").append(MarkImpl.class.getName()).append(" as mark ")
+		  .append("   where mark.creator.key=:identityKey and mark.resId=bgi.key and mark.resName='BusinessGroup'")
+		  .append(" ) as marks")
+		  .append(" from businessgrouptosearch as bgi")
+		  .append(" inner join fetch bgi.resource as bgResource ")
+		  .append(" inner join bgi.baseGroup as bGroup ");
+		filterBusinessGroupToSearch(sb, params, false);
 
-		List<BusinessGroupView> groups = dbInstance.getCurrentEntityManager()
-				.createQuery(sb.toString(), BusinessGroupView.class)
-				.setParameter("authorKey", author.getKey())
-				.getResultList();
+		TypedQuery<Object[]> objectsQuery = dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), Object[].class);
+		filterBusinessGroupToSearchParameters(objectsQuery, params, identity, true);
+		
+		List<Object[]> objects = objectsQuery.getResultList();
+		List<StatisticsBusinessGroupRow> groups = new ArrayList<>(objects.size());
+		Map<Long,BusinessGroupRow> keyToGroup = new HashMap<>();
+		for(Object[] object:objects) {
+			BusinessGroupToSearch businessGroup = (BusinessGroupToSearch)object[0];
+			Number numOfCoaches = (Number)object[1];
+			Number numOfParticipants = (Number)object[2];
+			Number numWaiting = (Number)object[3];
+			Number numPending = (Number)object[4];
+			Number marked = (Number)object[5];
+			
+			StatisticsBusinessGroupRow row
+				= new StatisticsBusinessGroupRow(businessGroup, numOfCoaches, numOfParticipants, numWaiting, numPending);
+			groups.add(row);
+			row.setMarked(marked == null ? false : marked.longValue() > 0);
+			keyToGroup.put(businessGroup.getKey(), row);
+		}
+		
+		loadRelations(keyToGroup, params, identity);
 		return groups;
 	}
+	
+	public List<StatisticsBusinessGroupRow> searchBusinessGroupsStatistics(BusinessGroupQueryParams params) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select bgi, ")
+		  .append(" (select count(nCoaches.key) from bgroupmember as nCoaches ")
+		  .append("  where nCoaches.group.key=bgi.baseGroup.key and nCoaches.role='").append(GroupRoles.coach.name()).append("'")
+		  .append(" ) as numOfCoaches,")
+		  .append(" (select count(nParticipants.key) from bgroupmember as nParticipants ")
+		  .append("  where nParticipants.group.key=bgi.baseGroup.key and nParticipants.role='").append(GroupRoles.participant.name()).append("'")
+		  .append(" ) as numOfParticipants,")
+		  .append(" (select count(nWaiting.key) from bgroupmember as nWaiting ")
+		  .append("  where bgi.waitingListEnabled=true and nWaiting.group.key=bgi.baseGroup.key and nWaiting.role='").append(GroupRoles.waiting.name()).append("'")
+		  .append(" ) as numWaiting,")
+		  .append(" (select count(reservation.key) from resourcereservation as reservation ")
+		  .append("  where reservation.resource.key=bgi.resource.key")
+		  .append(" ) as numOfReservations")
+		  .append(" from businessgrouptosearch as bgi")
+		  .append(" inner join fetch bgi.resource as bgResource ")
+		  .append(" inner join bgi.baseGroup as bGroup ");
+		filterBusinessGroupToSearch(sb, params, false);
 
-	public int countBusinessGroupViews(SearchBusinessGroupParams params, RepositoryEntryRef resource) {
-		TypedQuery<Number> query = createFindViewDBQuery(params, resource, Number.class)
-				.setHint("org.hibernate.cacheable", Boolean.TRUE);
+		TypedQuery<Object[]> objectsQuery = dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), Object[].class);
+		filterBusinessGroupToSearchParameters(objectsQuery, params, null, false);
+		
+		List<Object[]> objects = objectsQuery.getResultList();
+		List<StatisticsBusinessGroupRow> groups = new ArrayList<>(objects.size());
 
-		Number count = query.getSingleResult();
-		return count.intValue();
+		for(Object[] object:objects) {
+			BusinessGroupToSearch businessGroup = (BusinessGroupToSearch)object[0];
+			Number numOfCoaches = (Number)object[1];
+			Number numOfParticipants = (Number)object[2];
+			Number numWaiting = (Number)object[3];
+			Number numPending = (Number)object[4];
+
+			StatisticsBusinessGroupRow row
+				= new StatisticsBusinessGroupRow(businessGroup, numOfCoaches, numOfParticipants, numWaiting, numPending);
+			groups.add(row);
+		}
+		return groups;
 	}
 	
-	public List<BusinessGroupView> findBusinessGroupViews(SearchBusinessGroupParams params, RepositoryEntryRef resource,
-			int firstResult, int maxResults, BusinessGroupOrder... ordering) {
-		TypedQuery<BusinessGroupView> query = createFindViewDBQuery(params, resource, BusinessGroupView.class, ordering);
-		query.setFirstResult(firstResult);
-		if(maxResults > 0) {
-			query.setMaxResults(maxResults);
+	/**
+	 * 
+	 * @param entry
+	 * @return
+	 */
+	public List<StatisticsBusinessGroupRow> searchBusinessGroupsForRepositoryEntry(RepositoryEntryRef entry) {
+		//name, externalId, description, resources, tutors, participants, free places, waiting, access
+		
+		StringBuilder sb = new StringBuilder();
+		sb.append("select bgi, ")
+		  .append(" (select count(nCoaches.key) from bgroupmember as nCoaches ")
+		  .append("  where nCoaches.group.key=bgi.baseGroup.key and nCoaches.role='").append(GroupRoles.coach.name()).append("'")
+		  .append(" ) as numOfCoaches,")
+		  .append(" (select count(nParticipants.key) from bgroupmember as nParticipants ")
+		  .append("  where nParticipants.group.key=bgi.baseGroup.key and nParticipants.role='").append(GroupRoles.participant.name()).append("'")
+		  .append(" ) as numOfParticipants,")
+		  .append(" (select count(nWaiting.key) from bgroupmember as nWaiting ")
+		  .append("  where nWaiting.group.key=bgi.baseGroup.key and nWaiting.role='").append(GroupRoles.waiting.name()).append("'")
+		  .append(" ) as numWaiting,")
+		  .append(" (select count(reservation.key) from resourcereservation as reservation ")
+		  .append("  where reservation.resource.key=bgi.resource.key")
+		  .append(" ) as numOfReservations")
+		  .append(" from businessgrouptosearch as bgi")
+		  .append(" inner join fetch bgi.resource as bgResource ")
+		  .append(" inner join bgi.baseGroup as bGroup ")
+		  .append(" where bgi.baseGroup.key in (")
+	      .append("  select relation.group.key from repoentrytogroup relation where relation.entry.key=:resourceKey")
+	      .append(" )");
+		
+		List<Object[]> objects = dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), Object[].class)
+				.setParameter("resourceKey", entry.getKey())
+				.getResultList();
+		
+		List<StatisticsBusinessGroupRow> groups = new ArrayList<>(objects.size());
+		Map<Long,BusinessGroupRow> keyToGroup = new HashMap<>();
+		Map<Long,BusinessGroupRow> resourceKeyToGroup = new HashMap<>();
+		for(Object[] object:objects) {
+			BusinessGroupToSearch businessGroup = (BusinessGroupToSearch)object[0];
+			Number numOfCoaches = (Number)object[1];
+			Number numOfParticipants = (Number)object[2];
+			Number numWaiting = (Number)object[3];
+			Number numPending = (Number)object[4];
+			
+			
+			StatisticsBusinessGroupRow row
+				= new StatisticsBusinessGroupRow(businessGroup, numOfCoaches, numOfParticipants, numWaiting, numPending);
+			groups.add(row);
+			keyToGroup.put(businessGroup.getKey(), row);
+			resourceKeyToGroup.put(businessGroup.getResource().getKey(), row);
 		}
-		List<BusinessGroupView> groups = query.getResultList();
+		
+		loadOfferAccess(resourceKeyToGroup);
+		loadRelations(keyToGroup, null, null);
 		return groups;
 	}
 	
-	private <T> TypedQuery<T> createFindViewDBQuery(SearchBusinessGroupParams params, RepositoryEntryRef repoEntry, Class<T> resultClass, BusinessGroupOrder... ordering) {
-		StringBuilder query = new StringBuilder();
-		if(BusinessGroupView.class.equals(resultClass)) {
-			query.append("select distinct(bgi) from ");
-		} else {
-			query.append("select count(bgi.key) from ");
-		}
-		query.append(BusinessGroupViewImpl.class.getName()).append(" as bgi ");
-
-		//inner joins
-		if(BusinessGroupView.class.equals(resultClass)) {
-			query.append("inner join fetch bgi.resource as bgResource ");
-		} else {
-			query.append("inner join bgi.resource as bgResource ");
-		}
+	/**
+	 * 
+	 * @return
+	 */
+	public List<OpenBusinessGroupRow> searchPublishedBusinessGroups(BusinessGroupQueryParams params, IdentityRef identity) {
+		//need resources, access type, membership, num of pending, num of participants
+		StringBuilder sb = new StringBuilder();
+		sb.append("select bgi, ")
+		  .append(" (select count(nParticipants.key) from bgroupmember as nParticipants ")
+		  .append("  where nParticipants.group.key=bgi.baseGroup and nParticipants.role='").append(GroupRoles.participant.name()).append("'")
+		  .append(" ) as numOfParticipants,")
+		  .append(" (select count(reservation.key) from resourcereservation as reservation ")
+		  .append("  where reservation.resource.key=bgi.resource.key")
+		  .append(" ) as numOfReservations")
+		  .append(" from businessgrouptosearch as bgi ")
+		  .append(" inner join fetch bgi.resource as bgResource ")
+		  .append(" inner join fetch bgi.baseGroup as bGroup ");
+		filterBusinessGroupToSearch(sb, params, false);
 		
-		if(StringHelper.containsNonWhitespace(params.getOwnerName())
-				|| repoEntry != null || params.isOwner() || params.isAttendee() || params.isWaiting()) {
-			query.append(" inner join bgi.baseGroup as baseGroup");
+		TypedQuery<Object[]> queryObjects = dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), Object[].class);
+		filterBusinessGroupToSearchParameters(queryObjects, params, identity, false);
+		
+		List<Object[]> objects = queryObjects.getResultList();
+		List<OpenBusinessGroupRow> groups = new ArrayList<>(objects.size());
+		Map<Long, OpenBusinessGroupRow> keyToGroup = new HashMap<>();
+		Map<Long, OpenBusinessGroupRow> resourceKeyToGroup = new HashMap<>();
+		for(Object[] object:objects) {
+			BusinessGroupToSearch businessGroup = (BusinessGroupToSearch)object[0];
+			if(!keyToGroup.containsKey(businessGroup.getKey())) {
+				Long numOfParticipants = (Long)object[1];
+				Long numOfReservations = (Long)object[2];
+				
+				OpenBusinessGroupRow row = new OpenBusinessGroupRow(businessGroup, numOfParticipants, numOfReservations);
+				groups.add(row);
+				keyToGroup.put(businessGroup.getKey(), row);
+				resourceKeyToGroup.put(businessGroup.getResource().getKey(), row);
+			}
 		}
+		
+		loadRelations(keyToGroup, null, null);
+		loadOfferAccess(resourceKeyToGroup);
+		loadMemberships(identity, keyToGroup);
+		return groups;
+	}
+	
+	private void filterBusinessGroupToSearchParameters(TypedQuery<?> query, BusinessGroupQueryParams params, IdentityRef identity, boolean needIdentity) {
+		boolean memberOnly = params.isAttendee() || params.isOwner() || params.isWaiting();
 
-		boolean where = false;
-		if(StringHelper.containsNonWhitespace(params.getOwnerName())) {
-			where = true;
-			query.append(" inner join baseGroup.members as ownerMember on ownerMember.role='coach'")
-			     .append(" inner join ownerMember.identity as identity")
-			     .append(" inner join identity.user as user")
-			//query the name in login, firstName and lastName
-			     .append(" where (");
-			searchLikeUserProperty(query, "firstName", "owner");
-			query.append(" or ");
-			searchLikeUserProperty(query, "lastName", "owner");
-			query.append(" or ");
-			searchLikeAttribute(query, "identity", "name", "owner");
-			query.append(")");
+		if(memberOnly) {
+			List<String> roles = new ArrayList<>(3);
+			if(params.isOwner()) {
+				roles.add(GroupRoles.coach.name());
+			}
+			if(params.isAttendee()) {
+				roles.add(GroupRoles.participant.name());
+			}
+			if(params.isWaiting()) {
+				roles.add(GroupRoles.waiting.name());
+			}
+			query.setParameter("roles", roles);
+		}
+	
+		if(memberOnly || needIdentity || params.isMarked() || params.isAuthorConnection()) {
+			query.setParameter("identityKey", identity.getKey());
 		}
 		
-		if(params.getGroupKeys() != null && !params.getGroupKeys().isEmpty()) {
-			where = where(query, where);
-			query.append("bgi.key in (:groupKeys)");
+		if(params.getBusinessGroupKey() != null) {
+			query.setParameter("businessGroupKey", params.getBusinessGroupKey());
 		}
 		
-		if(repoEntry != null) {
-			where = where(query, where);
-			query.append(" exists (")
-			     .append("  select relation from repoentrytogroup relation where relation.group=baseGroup and relation.entry.key=:resourceKey")
-			     .append(")");
+		if(params.getRepositoryEntry() != null) {
+			query.setParameter("repoEntryKey", params.getRepositoryEntry().getKey());
 		}
 		
-		if(params.getResources() != null) {
-			where = where(query, where);
-			query.append(" bgi.numOfRelations").append(params.getResources().booleanValue() ? ">0" : "<=0");
+		//owner
+		if(StringHelper.containsNonWhitespace(params.getOwnerName())) {
+			query.setParameter("owner", PersistenceHelper.makeEndFuzzyQueryString(params.getOwnerName()));
 		}
 		
-		Long id = null;
+		//id
 		if(StringHelper.containsNonWhitespace(params.getIdRef())) {
 			if(StringHelper.isLong(params.getIdRef())) {
 				try {
-					id = new Long(params.getIdRef());
+					Long id = new Long(params.getIdRef());
+					query.setParameter("idRefLong", id);
 				} catch (NumberFormatException e) {
 					//not a real number, can be a very long numerical external id
 				}
 			}
-			where = where(query, where);
-			query.append("(bgi.externalId=:idRefString");
-			if(id != null) {
-				query.append(" or bgi.key=:idRefLong");
-			}
-			query.append(")");
-		}
-		
-		if(StringHelper.containsNonWhitespace(params.getCourseTitle())) {
-			where = where(query, where);
-			query.append(" bgi.key in (")
-			     .append("   select bgRel.relationId.groupKey from ").append(BGRepositoryEntryRelation.class.getName()).append(" bgRel ")
-			     .append("     where ");
-			searchLikeAttribute(query, "bgRel", "repositoryEntryDisplayName", "displayName");
-			query.append(" )");
+			query.setParameter("idRefString", params.getIdRef());
 		}
 		
-		List<String> roles = null;
-		if(params.isOwner() || params.isAttendee() || params.isWaiting()) {
-			where = where(query, where);
-			query.append(" exists (select bmember from bgroupmember as bmember")
-		         .append("   where bmember.identity.key=:identId and bmember.group=baseGroup and bmember.role in (:roles)")
-		         .append(" )");
-			
-			roles = new ArrayList<>(3);
-			if(params.isOwner()) {
-				roles.add(GroupRoles.coach.name());
-			}
-			if(params.isAttendee()) {
-				roles.add(GroupRoles.participant.name());
+		//name
+		if(StringHelper.containsNonWhitespace(params.getNameOrDesc())) {
+			query.setParameter("search", PersistenceHelper.makeEndFuzzyQueryString(params.getNameOrDesc()));
+		} else {
+			if(StringHelper.containsNonWhitespace(params.getName())) {
+				query.setParameter("name", PersistenceHelper.makeEndFuzzyQueryString(params.getName()));
 			}
-			if(params.isWaiting()) {
-				roles.add(GroupRoles.waiting.name());
+			if(StringHelper.containsNonWhitespace(params.getDescription())) {
+				query.setParameter("description", PersistenceHelper.makeEndFuzzyQueryString(params.getDescription()));
 			}
 		}
 		
+		//course title
+		if(StringHelper.containsNonWhitespace(params.getCourseTitle())) {
+			query.setParameter("displayName", PersistenceHelper.makeEndFuzzyQueryString(params.getCourseTitle()));
+		}
+		
+		//public group
 		if(params.getPublicGroups() != null) {
-			where = where(query, where);
 			if(params.getPublicGroups().booleanValue()) {
-		    query.append(" bgi.numOfValidOffers>0");
-			} else {
-		    query.append(" bgi.numOfOffers<=0");
+				query.setParameter("atDate", new Date());
 			}
 		}
+	}
+	
+	private void filterBusinessGroupToSearch(StringBuilder sb, BusinessGroupQueryParams params, boolean includeMemberships) {
+		boolean where = false;
+		boolean memberOnly = params.isAttendee() || params.isOwner() || params.isWaiting();
 		
-		if(params.getMarked() != null) {
-			where = where(query, where);
-			query.append(" bgi.key ").append(params.getMarked().booleanValue() ? "" : "not").append(" in (")
-			     .append("   select mark.resId from ").append(MarkImpl.class.getName()).append(" mark ")
-			     .append("     where mark.resName='BusinessGroup' and mark.creator.key=:identId")
-			     .append(" )");
+		if(memberOnly) {
+			sb.append("inner join bGroup.members as memberships on memberships.identity.key=:identityKey and memberships.role in (:roles)");	
+		} else if(includeMemberships) {
+			sb.append("left join bGroup.members as memberships on memberships.identity.key=:identityKey");	
 		}
 		
-		if(params.isHeadless()) {
-			where = where(query, where);
-			query.append(" bgi.numOfRelations=0 and bgi.numOfOwners=0 and bgi.numOfParticipants=0");
+		//coach / owner
+		if(StringHelper.containsNonWhitespace(params.getOwnerName())) {
+			where = true;
+			sb.append(" inner join bGroup.members as ownerMember on ownerMember.role='coach'")
+			  .append(" inner join ownerMember.identity as ownerIdentity")
+			  .append(" inner join ownerIdentity.user as ownerUser")
+			//query the name in login, firstName and lastName
+			  .append(" where (");
+			searchLikeOwnerUserProperty(sb, "firstName", "owner");
+			sb.append(" or ");
+			searchLikeOwnerUserProperty(sb, "lastName", "owner");
+			sb.append(" or ");
+			searchLikeAttribute(sb, "ownerIdentity", "name", "owner");
+			sb.append(")");
 		}
 		
-		if(params.getNumOfMembers() > -1) {
-			where = where(query, where);
-			if(params.isNumOfMembersBigger()) {
-				query.append(" (bgi.numOfOwners + bgi.numOfParticipants)>=").append(params.getNumOfMembers());
-			} else {
-				query.append(" (bgi.numOfOwners + bgi.numOfParticipants)<=").append(params.getNumOfMembers());
-			}	
+		if(params.getBusinessGroupKey() != null) {
+			where = PersistenceHelper.appendAnd(sb, where);
+			sb.append(" bgi.key=:businessGroupKey");
+		}
+		
+		if(params.isMarked()) {
+			where = PersistenceHelper.appendAnd(sb, where);
+			sb.append(" exists (select mark.key from ").append(MarkImpl.class.getName()).append(" as mark ")
+			  .append("  where mark.creator.key=:identityKey and mark.resId=bgi.key and mark.resName='BusinessGroup'")
+			  .append(" )");
+		}
+		
+		if(params.isAuthorConnection()) {
+			where = PersistenceHelper.appendAnd(sb, where);
+			sb.append(" bGroup.key in (select baseRelGroup.group.key from repositoryentry as v,")
+			  .append("   repoentrytogroup as baseRelGroup, repoentrytogroup as relGroup, bgroupmember as remembership")
+			  .append("     where baseRelGroup.entry.key=v.key and relGroup.entry.key=v.key and relGroup.group.key=remembership.group.key")
+			  .append("     and remembership.identity.key=:identityKey and remembership.role='owner'")
+			  .append(" )");
 		}
 		
+		//id
+		if(StringHelper.containsNonWhitespace(params.getIdRef())) {
+			where = PersistenceHelper.appendAnd(sb, where);
+			sb.append("(bgi.externalId=:idRefString");
+			if(StringHelper.isLong(params.getIdRef())) {
+				try {
+					Long.parseLong(params.getIdRef());
+					sb.append(" or bgi.key=:idRefLong");
+				} catch (NumberFormatException e) {
+					//not a real number, can be a very long numerical external id
+				}
+			}
+			sb.append(")");
+		}
+		
+		//name
 		if(StringHelper.containsNonWhitespace(params.getNameOrDesc())) {
-			where = where(query, where);
-			query.append("(");
-			searchLikeAttribute(query, "bgi", "name", "search");
-			query.append(" or ");
-			searchLikeAttribute(query, "bgi", "description", "search");
-			query.append(")");
+			where = PersistenceHelper.appendAnd(sb, where);
+			sb.append("(");
+			searchLikeAttribute(sb, "bgi", "name", "search");
+			sb.append(" or ");
+			searchLikeAttribute(sb, "bgi", "description", "search");
+			sb.append(")");
 		} else {
-			if(StringHelper.containsNonWhitespace(params.getExactName())) {
-				where = where(query, where);
-				query.append("bgi.name=:exactName");
-			}
 			if(StringHelper.containsNonWhitespace(params.getName())) {
-				where = where(query, where);
-				searchLikeAttribute(query, "bgi", "name", "name");
+				where = PersistenceHelper.appendAnd(sb, where);
+				searchLikeAttribute(sb, "bgi", "name", "name");
 			}
 			if(StringHelper.containsNonWhitespace(params.getDescription())) {
-				where = where(query, where);
-				searchLikeAttribute(query, "bgi", "description", "description");
+				where = PersistenceHelper.appendAnd(sb, where);
+				searchLikeAttribute(sb, "bgi", "description", "description");
 			}
 		}
-		
-		if(params.getTools() != null && !params.getTools().isEmpty()) {
-			where = where(query, where);
-			query.append("bgi.key in (select prop.resourceTypeId from ").append(Property.class.getName()).append(" prop")
-				.append(" where prop.category='").append(CollaborationTools.PROP_CAT_BG_COLLABTOOLS).append("'")
-				.append(" and prop.name in (:tools) and prop.stringValue='true' and prop.resourceTypeName='BusinessGroup')");
+	
+		// course title
+		if(StringHelper.containsNonWhitespace(params.getCourseTitle())) {
+			where = PersistenceHelper.appendAnd(sb, where);
+			sb.append(" bgi.baseGroup.key in (select baseRelGroup.group.key from repositoryentry as v")
+			  .append("  inner join v.groups as baseRelGroup")
+			  .append("  where baseRelGroup.entry.key=v.key and ");
+			searchLikeAttribute(sb, "v", "displayname", "displayName");
+			sb.append(" )");	
 		}
-		//order by (not for count)
-		if(BusinessGroupView.class.equals(resultClass)) {
-			query.append(" order by ");
-			if(ordering != null && ordering.length > 0) {
-				for(BusinessGroupOrder o:ordering) {
-					switch(o) {
-						case nameAsc: query.append("bgi.name,");break;
-						case nameDesc: query.append("bgi.name desc,");break;
-						case creationDateAsc: query.append("bgi.creationDate,");break;
-						case creationDateDesc: query.append("bgi.creationDate desc,");break;
-					}
-				}
+		
+		// open/public or not
+		if(params.getPublicGroups() != null) {
+			where = PersistenceHelper.appendAnd(sb, where);
+			if(params.getPublicGroups().booleanValue()) {
+				sb.append(" bgi.resource.key in (")
+		         .append("   select offer.resource.key from ").append(OfferImpl.class.getName()).append(" offer ")
+		         .append("     where offer.valid=true")
+		         .append("     and (offer.validFrom is null or offer.validFrom<=:atDate)")
+				 .append("     and (offer.validTo is null or offer.validTo>=:atDate)")
+				 .append(" )");
+				
 			} else {
-				query.append("bgi.name,");
+				sb.append(" bgi.resource.key not in (")
+		          .append("   select offer.resource.key from ").append(OfferImpl.class.getName()).append(" offer ")
+		          .append("     where offer.valid=true")
+		          .append(" )");
 			}
-			query.append("bgi.key");
-		}
-
-		TypedQuery<T> dbq = dbInstance.getCurrentEntityManager().createQuery(query.toString(), resultClass);
-		//add parameters
-		if(params.isOwner() || params.isAttendee() || params.isWaiting() || params.getMarked() != null) {
-			dbq.setParameter("identId", params.getIdentity().getKey());
 		}
-		if(params.getGroupKeys() != null && !params.getGroupKeys().isEmpty()) {
-			dbq.setParameter("groupKeys", params.getGroupKeys());
+		
+		if(params.getRepositoryEntry() != null) {
+			where = PersistenceHelper.appendAnd(sb, where);
+			sb.append(" bgi.baseGroup.key in (select entryRel.group.key from repoentrytogroup as entryRel where entryRel.entry.key=:repoEntryKey)");
 		}
-		if(StringHelper.containsNonWhitespace(params.getIdRef())) {
-			dbq.setParameter("idRefString", params.getIdRef());
-			if(id != null) {
-				dbq.setParameter("idRefLong", id);
+		
+		// in course or not
+		if(params.getResources() != null || params.isHeadless()) {
+			where = PersistenceHelper.appendAnd(sb, where);
+			if(params.getResources() != null && params.getResources().booleanValue()) {
+				sb.append(" exists (select resourceRel.key from repoentrytogroup as resourceRel where bgi.baseGroup.key=resourceRel.group.key )");
+			} else {
+				sb.append(" bgi.baseGroup.key not in (select resourceRel.group.key from repoentrytogroup as resourceRel)");
 			}
 		}
-		if (repoEntry != null) {
-			dbq.setParameter("resourceKey", repoEntry.getKey());
+		
+		// orphans
+		if(params.isHeadless()) {
+			where = PersistenceHelper.appendAnd(sb, where);
+			sb.append(" bgi.baseGroup.key not in (select headMembership.group.key from bgroupmember as headMembership")
+			  .append("   where headMembership.role in ('coach','paticipant')")
+			  .append(" )");
 		}
-		if(params.getTools() != null && !params.getTools().isEmpty()) {
-			dbq.setParameter("tools", params.getTools());
+	}
+	
+	private void loadMemberships(IdentityRef identity, Map<Long, ? extends BusinessGroupRow> keyToGroup) {
+		//memberships
+	    StringBuilder sm = new StringBuilder();
+		sm.append("select membership, bgi.key")
+		  .append(" from businessgroup as bgi ")
+		  .append(" inner join bgi.baseGroup as bGroup ")
+		  .append(" inner join bGroup.members as membership")
+		  .append(" where membership.identity.key=:identityKey");
+		
+		List<Object[]> memberships = dbInstance.getCurrentEntityManager()
+				.createQuery(sm.toString(), Object[].class)
+				.setParameter("identityKey", identity.getKey())
+				.getResultList();
+		for(Object[] membership:memberships) {
+			Long groupkey = (Long)membership[1];
+			BusinessGroupRow row = keyToGroup.get(groupkey);
+			addMembershipToRow(row, (GroupMembershipImpl)membership[0]);
 		}
-		if(StringHelper.containsNonWhitespace(params.getOwnerName())) {
-			dbq.setParameter("owner", makeFuzzyQueryString(params.getOwnerName()));
+	}
+
+	private void loadRelations(Map<Long, ? extends BusinessGroupRow> keyToGroup, BusinessGroupQueryParams params, IdentityRef identity) {
+		if(keyToGroup.isEmpty()) return;
+		
+		final int RELATIONS_IN_LIMIT = 64;
+		final boolean restrictToMembership = params != null && identity != null
+				&& (params.isAttendee() || params.isOwner() || params.isWaiting() || params.isMarked());
+		
+		//resources
+		StringBuilder sr = new StringBuilder();
+		sr.append("select entry.key, entry.displayname, bgi.key from repoentrytobusinessgroup as v")
+		  .append(" inner join v.entry entry")
+		  .append(" inner join v.businessGroup relationToGroup")
+		  .append(" inner join relationToGroup.businessGroups bgi");
+		if(restrictToMembership) {
+			sr.append(" inner join bgi.baseGroup as bGroup ")
+			  .append(" inner join bGroup.members as membership on membership.identity.key=:identityKey");
+		} else if(keyToGroup.size() < RELATIONS_IN_LIMIT) {
+			sr.append(" where bgi.key in (:businessGroupKeys)");
 		}
-		if(roles != null) {
-			dbq.setParameter("roles", roles);
+		
+		TypedQuery<Object[]> resourcesQuery = dbInstance.getCurrentEntityManager()
+				.createQuery(sr.toString(), Object[].class);
+		if(restrictToMembership) {
+			resourcesQuery.setParameter("identityKey", identity.getKey());
+		} else  if(keyToGroup.size() < RELATIONS_IN_LIMIT) {
+			List<Long> businessGroupKeys = new ArrayList<>(keyToGroup.size());
+			for(Long businessGroupKey:keyToGroup.keySet()) {
+				businessGroupKeys.add(businessGroupKey);
+			}
+			resourcesQuery.setParameter("businessGroupKeys", businessGroupKeys);
 		}
-		if(StringHelper.containsNonWhitespace(params.getNameOrDesc())) {
-			dbq.setParameter("search", makeFuzzyQueryString(params.getNameOrDesc()));
+		
+		List<Object[]> resources = resourcesQuery.getResultList();
+		for(Object[] resource:resources) {
+			Long groupKey = (Long)resource[2];
+			BusinessGroupRow row = keyToGroup.get(groupKey);
+			if(row != null) {
+				Long entryKey = (Long)resource[0];
+				String displayName = (String)resource[1];
+				REShort entry = new REShort(entryKey, displayName);
+				if(row.getResources() == null) {
+					row.setResources(new ArrayList<>(4));
+				}
+				row.getResources().add(entry);
+			}
+		}
+	}
+	
+	public void loadOfferAccess(Map<Long, ? extends BusinessGroupRow> resourceKeyToGroup) {
+		if(resourceKeyToGroup.isEmpty()) return;
+
+		final int OFFERS_IN_LIMIT = 255;
+		
+		//offers
+		StringBuilder so = new StringBuilder();
+		so.append("select access.method, resource.key, offer.price from ").append(OfferAccessImpl.class.getName()).append(" access ")
+			.append(" inner join access.offer offer")
+			.append(" inner join offer.resource resource");
+		if(resourceKeyToGroup.size() < OFFERS_IN_LIMIT) {
+			so.append(" where resource.key in (:resourceKeys)");
 		} else {
-			if(StringHelper.containsNonWhitespace(params.getExactName())) {
-				dbq.setParameter("exactName", params.getExactName());
+			so.append(" where exists (select bgi.key from businessgroup bgi where bgi.resource=resource)");
+		}
+			
+		TypedQuery<Object[]> offersQuery = dbInstance.getCurrentEntityManager()
+				.createQuery(so.toString(), Object[].class);
+				
+		if(resourceKeyToGroup.size() < OFFERS_IN_LIMIT) {
+			List<Long> resourceKeys = new ArrayList<>(resourceKeyToGroup.size());
+			for(Long resourceKey:resourceKeyToGroup.keySet()) {
+				resourceKeys.add(resourceKey);
 			}
-			if(StringHelper.containsNonWhitespace(params.getName())) {
-				dbq.setParameter("name", makeFuzzyQueryString(params.getName()));
+			offersQuery.setParameter("resourceKeys", resourceKeys);
+		}
+		
+		List<Object[]> offers = offersQuery.getResultList();
+		for(Object[] offer:offers) {
+			Long resourceKey = (Long)offer[1];
+			
+			BusinessGroupRow row = resourceKeyToGroup.get(resourceKey);
+			if(row != null) {
+				AccessMethod method = (AccessMethod)offer[0];
+				Price price = (Price)offer[2];
+				if(row.getBundles() == null) {
+					row.setBundles(new ArrayList<>(3));
+				}
+				row.getBundles().add(new PriceMethodBundle(price, method));	
 			}
-			if(StringHelper.containsNonWhitespace(params.getDescription())) {
-				dbq.setParameter("description", makeFuzzyQueryString(params.getDescription()));
+		}
+	}
+	
+	private void addMembershipToRow(BusinessGroupRow row, GroupMembershipImpl member) {
+		if(row != null && member != null) {
+			if(row.getMember() == null) {
+				row.setMember(new BusinessGroupMembershipImpl());
+			}
+			
+			String role = member.getRole();
+			BusinessGroupMembershipImpl mb = row.getMember();
+			mb.setCreationDate(member.getCreationDate());
+			mb.setLastModified(member.getLastModified());
+			if(GroupRoles.coach.name().equals(role)) {
+				mb.setOwner(true);
+			} else if(GroupRoles.participant.name().equals(role)) {
+				mb.setParticipant(true);
+			} else if(GroupRoles.waiting.name().equals(role)) {
+				mb.setWaiting(true);
 			}
 		}
-		if(StringHelper.containsNonWhitespace(params.getCourseTitle())) {
-			dbq.setParameter("displayName", makeFuzzyQueryString(params.getCourseTitle()));
+	}
+	
+	private void appendMarkedSubQuery(StringBuilder sb, BusinessGroupQueryParams params) {
+		if(params.isMarked()) {
+			sb.append(" ,1 as marks");
+		} else {
+			sb.append(" ,(select count(mark.key) from ").append(MarkImpl.class.getName()).append(" as mark ")
+			  .append("   where mark.creator.key=:identityKey and mark.resId=bgi.key and mark.resName='BusinessGroup'")
+			  .append(" ) as marks");
 		}
-		return dbq;
 	}
 	
-	private StringBuilder searchLikeUserProperty(StringBuilder sb, String key, String var) {
+	private StringBuilder searchLikeOwnerUserProperty(StringBuilder sb, String key, String var) {
 		if(dbInstance.getDbVendor().equals("mysql")) {
-			sb.append(" user.userProperties['").append(key).append("'] like :").append(var);
+			sb.append(" ownerUser.userProperties['").append(key).append("'] like :").append(var);
 		} else {
-			sb.append(" lower(user.userProperties['").append(key).append("']) like :").append(var);
+			sb.append(" lower(ownerUser.userProperties['").append(key).append("']) like :").append(var);
 			if(dbInstance.getDbVendor().equals("oracle")) {
 	 	 		sb.append(" escape '\\'");
 	 	 	}
@@ -1028,4 +1318,51 @@ public class BusinessGroupDAO {
 		else sb.append(" where ");
 		return true;
 	}
+	
+
+	private static class REShort implements RepositoryEntryShort {
+		private final Long key;
+		private final String displayname;
+		public REShort(Long entryKey, String displayname) {
+			this.key = entryKey;
+			this.displayname = displayname;
+		}
+
+		@Override
+		public Long getKey() {
+			return key;
+		}
+
+		@Override
+		public String getDisplayname() {
+			return displayname;
+		}
+
+		@Override
+		public String getResourceType() {
+			return "CourseModule";
+		}
+
+		@Override
+		public int getStatusCode() {
+			return 0;
+		}
+
+		@Override
+		public int hashCode() {
+			return key.hashCode();
+		}
+
+		@Override
+		public boolean equals(Object obj) {
+			if(this == obj) {
+				return true;
+			}
+			if(obj instanceof REShort) {
+				REShort re = (REShort)obj;
+				return key != null && key.equals(re.key);
+			}
+			return false;
+		}
+	}
 }
diff --git a/src/main/java/org/olat/group/manager/BusinessGroupRelationDAO.java b/src/main/java/org/olat/group/manager/BusinessGroupRelationDAO.java
index ffed87984854c147f7f43edc77162ec690382289..5711ed255231b75f7d9e958e82403d6698602539 100644
--- a/src/main/java/org/olat/group/manager/BusinessGroupRelationDAO.java
+++ b/src/main/java/org/olat/group/manager/BusinessGroupRelationDAO.java
@@ -82,7 +82,7 @@ public class BusinessGroupRelationDAO {
 	
 	public boolean removeRole(Identity identity, BusinessGroupRef businessGroup, String role) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select membership from ").append(BusinessGroupImpl.class.getName()).append(" as bgroup ")
+		sb.append("select membership from businessgroup as bgroup ")
 		  .append(" inner join bgroup.baseGroup as baseGroup")
 		  .append(" inner join baseGroup.members as membership")
 		  .append(" where bgroup.key=:businessGroupKey and membership.identity.key=:identityKey and membership.role=:role");
@@ -100,7 +100,7 @@ public class BusinessGroupRelationDAO {
 	
 	public Group getGroup(BusinessGroupRef businessGroup) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select baseGroup from ").append(BusinessGroupImpl.class.getName()).append(" as bgroup ")
+		sb.append("select baseGroup from businessgroup as bgroup ")
 		  .append(" inner join bgroup.baseGroup as baseGroup")
 		  .append(" where bgroup.key=:businessGroupKey");
 
@@ -111,7 +111,7 @@ public class BusinessGroupRelationDAO {
 	
 	public List<String> getRoles(IdentityRef identity, BusinessGroupRef group) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select membership.role from ").append(BusinessGroupImpl.class.getName()).append(" as bgroup ")
+		sb.append("select membership.role from businessgroup as bgroup ")
 		  .append(" inner join bgroup.baseGroup as baseGroup")
 		  .append(" inner join baseGroup.members as membership")
 		  .append(" where bgroup.key=:businessGroupKey and membership.identity.key=:identityKey");
@@ -126,7 +126,7 @@ public class BusinessGroupRelationDAO {
 		if(groups == null || groups.isEmpty()) return Collections.emptyList();
 		
 		StringBuilder sb = new StringBuilder();
-		sb.append("select membership.role from ").append(BusinessGroupImpl.class.getName()).append(" as bgroup ")
+		sb.append("select membership.role from businessgroup as bgroup ")
 		  .append(" inner join bgroup.baseGroup as baseGroup")
 		  .append(" inner join baseGroup.members as membership")
 		  .append(" where bgroup.key in (:businessGroupKeys) and membership.identity.key=:identityKey");
@@ -149,7 +149,7 @@ public class BusinessGroupRelationDAO {
 		if(groups == null || groups.isEmpty()) return Collections.emptyList();
 		
 		StringBuilder sb = new StringBuilder();
-		sb.append("select count(membership.key ), membership.identity.key from ").append(BusinessGroupImpl.class.getName()).append(" as bgroup ")
+		sb.append("select count(membership.key ), membership.identity.key from businessgroup as bgroup ")
 		  .append(" inner join bgroup.baseGroup as baseGroup")
 		  .append(" inner join baseGroup.members as membership")
 		  .append(" where bgroup.key in (:businessGroupKeys) and membership.role='participant'")
@@ -176,7 +176,7 @@ public class BusinessGroupRelationDAO {
 	
 	public int countRoles(BusinessGroupRef group, String... role) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select count(membership) from ").append(BusinessGroupImpl.class.getName()).append(" as bgroup ")
+		sb.append("select count(membership) from businessgroup as bgroup ")
 		  .append(" inner join bgroup.baseGroup as baseGroup")
 		  .append(" inner join baseGroup.members as membership")
 		  .append(" where bgroup.key=:businessGroupKey");
@@ -202,7 +202,7 @@ public class BusinessGroupRelationDAO {
 	 */
 	public int countAuthors(BusinessGroupRef group) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select count(membership) from ").append(BusinessGroupImpl.class.getName()).append(" as bgroup ")
+		sb.append("select count(membership) from businessgroup as bgroup ")
 		  .append(" inner join bgroup.baseGroup as baseGroup")
 		  .append(" inner join baseGroup.members as membership")
 		  .append(" where bgroup.key=:businessGroupKey and membership.role='").append(GroupRoles.coach.name()).append("'")
@@ -227,7 +227,7 @@ public class BusinessGroupRelationDAO {
 	 */
 	public boolean hasRole(IdentityRef identity, BusinessGroupRef group, String role) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select count(membership) from ").append(BusinessGroupImpl.class.getName()).append(" as bgroup ")
+		sb.append("select count(membership) from businessgroup as bgroup ")
 		  .append(" inner join bgroup.baseGroup as baseGroup")
 		  .append(" inner join baseGroup.members as membership")
 		  .append(" where bgroup.key=:businessGroupKey and membership.identity.key=:identityKey and membership.role=:role");
@@ -242,7 +242,7 @@ public class BusinessGroupRelationDAO {
 	
 	public boolean hasAnyRole(IdentityRef identity, BusinessGroupRef group) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select count(membership) from ").append(BusinessGroupImpl.class.getName()).append(" as bgroup ")
+		sb.append("select count(membership) from businessgroup as bgroup ")
 		  .append(" inner join bgroup.baseGroup as baseGroup")
 		  .append(" inner join baseGroup.members as membership")
 		  .append(" where bgroup.key=:businessGroupKey and membership.identity.key=:identityKey");
@@ -256,7 +256,7 @@ public class BusinessGroupRelationDAO {
 	
 	public void touchMembership(IdentityRef identity, BusinessGroupRef group) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select membership from ").append(BusinessGroupImpl.class.getName()).append(" as bgroup ")
+		sb.append("select membership from businessgroup as bgroup ")
 		  .append(" inner join bgroup.baseGroup as baseGroup")
 		  .append(" inner join baseGroup.members as membership")
 		  .append(" where bgroup.key=:businessGroupKey and membership.identity.key=:identityKey");
@@ -272,7 +272,7 @@ public class BusinessGroupRelationDAO {
 	
 	public List<Identity> getMembers(BusinessGroupRef group, String... roles) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select membership.identity from ").append(BusinessGroupImpl.class.getName()).append(" as bgroup ")
+		sb.append("select membership.identity from businessgroup as bgroup ")
 		  .append(" inner join bgroup.baseGroup as baseGroup")
 		  .append(" inner join baseGroup.members as membership")
 		  .append(" where bgroup.key=:businessGroupKey and membership.role in (:roles)");
@@ -289,7 +289,7 @@ public class BusinessGroupRelationDAO {
 		if(groups == null || groups.isEmpty()) return Collections.emptyList();
 		
 		StringBuilder sb = new StringBuilder();
-		sb.append("select membership.identity.key from ").append(BusinessGroupImpl.class.getName()).append(" as bgroup ")
+		sb.append("select membership.identity.key from businessgroup as bgroup ")
 		  .append(" inner join bgroup.baseGroup as baseGroup")
 		  .append(" inner join baseGroup.members as membership")
 		  .append(" where bgroup.key in (:businessGroupKeys) and membership.role in (:roles)");
@@ -310,7 +310,7 @@ public class BusinessGroupRelationDAO {
 	
 	public List<Long> getMemberKeysOrderByDate(BusinessGroupRef group, String... roles) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select membership.identity.key from ").append(BusinessGroupImpl.class.getName()).append(" as bgroup ")
+		sb.append("select membership.identity.key from businessgroup as bgroup ")
 		  .append(" inner join bgroup.baseGroup as baseGroup")
 		  .append(" inner join baseGroup.members as membership")
 		  .append(" where bgroup.key=:businessGroupKey and membership.role in (:roles) order by membership.creationDate");
@@ -325,7 +325,7 @@ public class BusinessGroupRelationDAO {
 	
 	public List<Identity> getMembersOrderByDate(BusinessGroupRef group, String... roles) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select membership.identity from ").append(BusinessGroupImpl.class.getName()).append(" as bgroup ")
+		sb.append("select membership.identity from businessgroup as bgroup ")
 		  .append(" inner join bgroup.baseGroup as baseGroup")
 		  .append(" inner join baseGroup.members as membership")
 		  .append(" where bgroup.key=:businessGroupKey and membership.role in (:roles) order by membership.creationDate");
@@ -350,7 +350,7 @@ public class BusinessGroupRelationDAO {
 		if(businessGroups == null || businessGroups.isEmpty() || member == null) return Collections.emptyList();
 		
 		StringBuilder sb = new StringBuilder();
-		sb.append("select bgi from ").append(BusinessGroupImpl.class.getName()).append(" bgi")
+		sb.append("select bgi from businessgroup bgi")
 		  .append(" inner join fetch bgi.resource as ores ")
 		  .append(" inner join fetch bgi.baseGroup as baseGroup")
 		  .append(" inner join baseGroup.members as bmember")
@@ -383,7 +383,7 @@ public class BusinessGroupRelationDAO {
 	public boolean isIdentityInBusinessGroup(IdentityRef identity, Long groupKey, boolean ownedById, boolean attendeeById,
 			RepositoryEntryRef resource) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select count(bgi) from ").append(BusinessGroupImpl.class.getName()).append(" bgi")
+		sb.append("select count(bgi) from businessgroup bgi")
 		  .append(" inner join bgi.baseGroup as baseGroup")
 		  .append(" inner join baseGroup.members as bmember")
 		  .append(" where bmember.identity.key=:identityKey and bmember.role in (:roles)");
@@ -468,7 +468,7 @@ public class BusinessGroupRelationDAO {
 			.append(" left join fetch v.lifecycle as lifecycle")
 			.append(" inner join v.groups as relGroup")
 			.append(" where exists (")
-			.append("   select bgi from ").append(BusinessGroupImpl.class.getName()).append(" as bgi where bgi.baseGroup=relGroup.group and bgi.key in (:groupKeys)")
+			.append("   select bgi from businessgroup as bgi where bgi.baseGroup=relGroup.group and bgi.key in (:groupKeys)")
 			.append(" )");
 
 		TypedQuery<RepositoryEntry> query = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), RepositoryEntry.class);
@@ -492,7 +492,7 @@ public class BusinessGroupRelationDAO {
 			.append(" inner join v.olatResource as ores ")
 			.append(" inner join v.groups as relGroup")
 			.append(" where exists (")
-			.append("   select bgi from ").append(BusinessGroupImpl.class.getName()).append(" as bgi where bgi.baseGroup=relGroup.group and bgi.key in (:groupKeys)")
+			.append("   select bgi from businessgroup as bgi where bgi.baseGroup=relGroup.group and bgi.key in (:groupKeys)")
 			.append(" )");
 
 		TypedQuery<RepositoryEntryShort> query = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), RepositoryEntryShort.class);
@@ -557,7 +557,7 @@ public class BusinessGroupRelationDAO {
 		if(names.isEmpty()) return Collections.emptyList();
 			
 		StringBuilder sb = new StringBuilder();
-		sb.append("select bgi.key from ").append(BusinessGroupImpl.class.getName()).append(" as bgi ")
+		sb.append("select bgi.key from businessgroup as bgi ")
 		  .append(" inner join bgi.baseGroup as baseGroup")
 		  .append(" where bgi.name in (:names)")
 		  .append(" and exists (")
diff --git a/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java b/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java
index 930a93166a74621b775039b0115d081c1d96554e..c16bb088e04620bb7e99166e458f6bdab937dff7 100644
--- a/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java
+++ b/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java
@@ -78,7 +78,6 @@ import org.olat.group.BusinessGroupOrder;
 import org.olat.group.BusinessGroupRef;
 import org.olat.group.BusinessGroupService;
 import org.olat.group.BusinessGroupShort;
-import org.olat.group.BusinessGroupView;
 import org.olat.group.DeletableGroupData;
 import org.olat.group.GroupLoggingAction;
 import org.olat.group.area.BGArea;
@@ -91,11 +90,15 @@ import org.olat.group.model.BusinessGroupMembershipChange;
 import org.olat.group.model.BusinessGroupMembershipImpl;
 import org.olat.group.model.BusinessGroupMembershipViewImpl;
 import org.olat.group.model.BusinessGroupMembershipsChanges;
+import org.olat.group.model.BusinessGroupQueryParams;
 import org.olat.group.model.BusinessGroupRelationModified;
+import org.olat.group.model.BusinessGroupRow;
 import org.olat.group.model.EnrollState;
 import org.olat.group.model.IdentityGroupKey;
 import org.olat.group.model.LeaveOption;
 import org.olat.group.model.MembershipModification;
+import org.olat.group.model.OpenBusinessGroupRow;
+import org.olat.group.model.StatisticsBusinessGroupRow;
 import org.olat.group.model.SearchBusinessGroupParams;
 import org.olat.group.right.BGRightManager;
 import org.olat.group.right.BGRightsRole;
@@ -222,7 +225,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 	public BusinessGroup updateBusinessGroup(Identity ureqIdentity, BusinessGroup group, String name, String description,
 			String externalId, String managedFlags, Integer minParticipants, Integer maxParticipants) {
 		
-		BusinessGroup bg = businessGroupDAO.loadForUpdate(group.getKey());
+		BusinessGroup bg = businessGroupDAO.loadForUpdate(group);
 
 		Integer previousMaxParticipants = bg.getMaxParticipants();
 		bg.setName(name);
@@ -251,7 +254,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 	public BusinessGroup updateBusinessGroup(Identity ureqIdentity, BusinessGroup group, String name, String description,
 			Integer minParticipants, Integer maxParticipants, Boolean waitingList, Boolean autoCloseRanks) {
 		
-		BusinessGroup bg = businessGroupDAO.loadForUpdate(group.getKey());
+		BusinessGroup bg = businessGroupDAO.loadForUpdate(group);
 		
 		Integer previousMaxParticipants = bg.getMaxParticipants();
 		bg.setName(name);
@@ -298,7 +301,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 			boolean ownersPublic, boolean participantsPublic, boolean waitingListPublic,
 			boolean download) {
 		
-		BusinessGroup reloadedBusinessGroup = businessGroupDAO.loadForUpdate(group.getKey());
+		BusinessGroup reloadedBusinessGroup = businessGroupDAO.loadForUpdate(group);
 		BusinessGroup mergedGroup = null;
 		if(reloadedBusinessGroup != null) {
 			reloadedBusinessGroup.setOwnersVisibleIntern(ownersIntern);
@@ -318,7 +321,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 
 	@Override
 	public BusinessGroup updateAllowToLeaveBusinessGroup(BusinessGroup group, boolean allow) {
-		BusinessGroup reloadedBusinessGroup = businessGroupDAO.loadForUpdate(group.getKey());
+		BusinessGroup reloadedBusinessGroup = businessGroupDAO.loadForUpdate(group);
 		BusinessGroup mergedGroup = null;
 		if(reloadedBusinessGroup != null) {
 			reloadedBusinessGroup.setAllowToLeave(allow);
@@ -332,7 +335,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 
 	@Override
 	public BusinessGroup setLastUsageFor(final Identity identity, final BusinessGroup group) {
-		BusinessGroup reloadedBusinessGroup = businessGroupDAO.loadForUpdate(group.getKey());
+		BusinessGroup reloadedBusinessGroup = businessGroupDAO.loadForUpdate(group);
 		BusinessGroup mergedGroup = null;
 		if(reloadedBusinessGroup != null) {
 			reloadedBusinessGroup.setLastUsage(new Date());
@@ -473,7 +476,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 		groupsToMerge.remove(targetGroup);//to be sure
 		Roles ureqRoles = securityManager.getRoles(ureqIdentity);
 
-		targetGroup = businessGroupDAO.loadForUpdate(targetGroup.getKey());
+		targetGroup = businessGroupDAO.loadForUpdate(targetGroup);
 		Set<Identity> currentOwners
 			= new HashSet<Identity>(businessGroupRelationDAO.getMembers(targetGroup, GroupRoles.coach.name()));
 		Set<Identity> currentParticipants 
@@ -545,7 +548,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 	
 	private void updateMembers(Identity ureqIdentity, Roles ureqRoles, MembershipModification membersMod,
 			BusinessGroup group, MailPackage mailing) {
-		group = businessGroupDAO.loadForUpdate(group.getKey());
+		group = businessGroupDAO.loadForUpdate(group);
 		
 		List<Identity> currentOwners = businessGroupRelationDAO.getMembers(group, GroupRoles.coach.name());
 		List<Identity> currentParticipants = businessGroupRelationDAO.getMembers(group, GroupRoles.participant.name());
@@ -627,7 +630,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 		List<BusinessGroup> groups = loadBusinessGroups(changesMap.keySet());
 		for(BusinessGroup group:groups) {
 			BusinessGroupMembershipsChanges changesWrapper = changesMap.get(group.getKey());
-			group = businessGroupDAO.loadForUpdate(group.getKey());
+			group = businessGroupDAO.loadForUpdate(group);
 					
 			for(Identity id:changesWrapper.addToWaitingList) {
 				addToWaitingList(ureqIdentity, id, group, mailing, events);
@@ -694,17 +697,28 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 	}
 
 	@Override
-	public List<BusinessGroupView> findBusinessGroupViews(SearchBusinessGroupParams params, RepositoryEntryRef resource, int firstResult,
-			int maxResults, BusinessGroupOrder... ordering) {
-		if(params == null) {
-			params = new SearchBusinessGroupParams();
-		}
-		return businessGroupDAO.findBusinessGroupViews(params, resource, firstResult, maxResults);
+	public List<BusinessGroupRow> findBusinessGroupsWithMemberships(BusinessGroupQueryParams params, IdentityRef identity) {
+		return businessGroupDAO.searchBusinessGroupsWithMemberships(params, identity);
+	}
+
+	@Override
+	public List<StatisticsBusinessGroupRow> findBusinessGroupsFromRepositoryEntry(BusinessGroupQueryParams params, RepositoryEntryRef entry) {
+		return businessGroupDAO.searchBusinessGroupsForRepositoryEntry(entry);
+	}
+
+	@Override
+	public List<StatisticsBusinessGroupRow> findBusinessGroupsForSelection(BusinessGroupQueryParams params, IdentityRef identity) {
+		return businessGroupDAO.searchBusinessGroupsForSelection(params, identity);
+	}
+
+	@Override
+	public List<StatisticsBusinessGroupRow> findBusinessGroupsStatistics(BusinessGroupQueryParams params) {
+		return businessGroupDAO.searchBusinessGroupsStatistics(params);
 	}
 
 	@Override
-	public List<BusinessGroupView> findBusinessGroupViewsWithAuthorConnection(Identity author) {
-		return businessGroupDAO.findBusinessGroupWithAuthorConnection(author);
+	public List<OpenBusinessGroupRow> findPublishedBusinessGroups(BusinessGroupQueryParams params, IdentityRef identity) {
+		return businessGroupDAO.searchPublishedBusinessGroups(params, identity);
 	}
 
 	@Override
@@ -961,7 +975,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 		BusinessGroupAddResponse response = new BusinessGroupAddResponse();
 		List<BusinessGroupModifiedEvent.Deferred> events = new ArrayList<BusinessGroupModifiedEvent.Deferred>();
 
-		BusinessGroup currBusinessGroup = businessGroupDAO.loadForUpdate(group.getKey());	
+		BusinessGroup currBusinessGroup = businessGroupDAO.loadForUpdate(group);	
 		for (final Identity identity : addIdentities) {
 			if (securityManager.isIdentityPermittedOnResourceable(identity, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_GUESTONLY)) {
 				response.getIdentitiesWithoutPermission().add(identity);
@@ -1116,7 +1130,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 
 	@Override
 	public void removeParticipants(Identity ureqIdentity, List<Identity> identities, BusinessGroup group, MailPackage mailing) {
-		group = businessGroupDAO.loadForUpdate(group.getKey());
+		group = businessGroupDAO.loadForUpdate(group);
 		List<BusinessGroupModifiedEvent.Deferred> events = new ArrayList<BusinessGroupModifiedEvent.Deferred>();
 		for (Identity identity : identities) {
 		  removeParticipant(ureqIdentity, identity, group, mailing, events);
@@ -1157,10 +1171,10 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 		}
 
 		List<OLATResource> groupResources = new ArrayList<OLATResource>();
-		Map<Long,BusinessGroup> keyToGroupMap = new HashMap<Long,BusinessGroup>();
+		Map<Long,BusinessGroup> idToGroup = new HashMap<>();
 		for(BusinessGroup group:groups) {
 			groupResources.add(group.getResource());
-			keyToGroupMap.put(group.getKey(), group);
+			idToGroup.put(group.getKey(), group);
 		}
 		final Map<Long,Identity> keyToIdentityMap = new HashMap<Long,Identity>();
 		for(Identity identity:identities) {
@@ -1182,7 +1196,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 			}
 			
 			Long groupKey = currentMembership.getGroupKey();
-			BusinessGroup nextGroup = businessGroupDAO.loadForUpdate(groupKey);
+			BusinessGroup nextGroup = businessGroupDAO.loadForUpdate(idToGroup.get(groupKey));
 			nextGroupMembership = removeGroupMembers(ureqIdentity, currentMembership, nextGroup, keyToIdentityMap, itMembership, mailing, events);
 			//release the lock
 			dbInstance.commit();
@@ -1254,7 +1268,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 	@Override
 	public BusinessGroupAddResponse addToWaitingList(Identity ureqIdentity, List<Identity> addIdentities, BusinessGroup group, MailPackage mailing) {
 		BusinessGroupAddResponse response = new BusinessGroupAddResponse();
-		BusinessGroup currBusinessGroup = businessGroupDAO.loadForUpdate(group.getKey()); // reload business group
+		BusinessGroup currBusinessGroup = businessGroupDAO.loadForUpdate(group); // reload business group
 		List<BusinessGroupModifiedEvent.Deferred> events = new ArrayList<BusinessGroupModifiedEvent.Deferred>();
 
 		for (final Identity identity : addIdentities) {	
@@ -1298,7 +1312,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 	@Override
 	public void removeFromWaitingList(Identity ureqIdentity, List<Identity> identities, BusinessGroup businessGroup, MailPackage mailing) {
 		List<BusinessGroupModifiedEvent.Deferred> events = new ArrayList<BusinessGroupModifiedEvent.Deferred>();
-		businessGroup = businessGroupDAO.loadForUpdate(businessGroup.getKey());
+		businessGroup = businessGroupDAO.loadForUpdate(businessGroup);
 		for (Identity identity : identities) {
 		  removeFromWaitingList(ureqIdentity, identity, businessGroup, mailing, events);
 		}
@@ -1327,7 +1341,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 		
 		BusinessGroupAddResponse response = new BusinessGroupAddResponse();
 		List<BusinessGroupModifiedEvent.Deferred> events = new ArrayList<BusinessGroupModifiedEvent.Deferred>();
-		currBusinessGroup = businessGroupDAO.loadForUpdate(currBusinessGroup.getKey());
+		currBusinessGroup = businessGroupDAO.loadForUpdate(currBusinessGroup);
 		
 		for (Identity identity : identities) {
 			// check if identity is already in participant
@@ -1353,7 +1367,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 	@Override
 	public EnrollState enroll(Identity ureqIdentity, Roles ureqRoles, Identity identity, BusinessGroup group,
 			MailPackage mailing) {
-		final BusinessGroup reloadedGroup = businessGroupDAO.loadForUpdate(group.getKey());
+		final BusinessGroup reloadedGroup = businessGroupDAO.loadForUpdate(group);
 		
 		log.info("doEnroll start: group=" + OresHelper.createStringRepresenting(group), identity.getName());
 		EnrollState enrollStatus = new EnrollState();
diff --git a/src/main/java/org/olat/group/manager/ContactDAO.java b/src/main/java/org/olat/group/manager/ContactDAO.java
index 16c8d15e836caa7ff6a946dd989ff20507120be8..ddaea9e296ce55dccb63402d123ae2aa995394e8 100644
--- a/src/main/java/org/olat/group/manager/ContactDAO.java
+++ b/src/main/java/org/olat/group/manager/ContactDAO.java
@@ -29,7 +29,6 @@ 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.group.BusinessGroupImpl;
 import org.olat.group.model.ContactView;
 import org.olat.group.model.ContactViewExtended;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -62,7 +61,7 @@ public class ContactDAO {
 	
 	private List<Long> getMembersForCount(IdentityRef me) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select contact.identity.key from ").append(BusinessGroupImpl.class.getName()).append(" bgroup ")
+		sb.append("select contact.identity.key from businessgroup bgroup ")
 		  .append(" inner join bgroup.baseGroup baseGroup")
 		  .append(" inner join baseGroup.members contact")
 		  .append(" where exists (select me.key from bgroupmember as me where me.group=baseGroup and me.identity.key=:identKey)")
diff --git a/src/main/java/org/olat/group/model/BusinessGroupQueryParams.java b/src/main/java/org/olat/group/model/BusinessGroupQueryParams.java
new file mode 100644
index 0000000000000000000000000000000000000000..f0886770f826a022d02b50e84e7f3f9d8332e8ad
--- /dev/null
+++ b/src/main/java/org/olat/group/model/BusinessGroupQueryParams.java
@@ -0,0 +1,208 @@
+/**
+ * <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>
+ * 2011 by frentix GmbH, http://www.frentix.com
+ * <p>
+**/
+package org.olat.group.model;
+
+import org.olat.repository.RepositoryEntry;
+
+/**
+ * 
+ * Initial date: 08.10.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class BusinessGroupQueryParams {
+	
+	private String nameOrDesc;
+	private String name;
+	private String description;
+	private String ownerName;
+	private String courseTitle;
+	private String externalId;
+	private String idRef;
+	
+	private boolean owner;
+	private boolean attendee;
+	private boolean waiting;
+	private Boolean publicGroups;
+	private boolean marked;
+	private Boolean resources;
+	private boolean headless = false;
+	private boolean authorConnection;
+	
+	private Long businessGroupKey;
+	private RepositoryEntry repositoryEntry;
+	
+	public BusinessGroupQueryParams() {
+		//
+	}
+	
+	public BusinessGroupQueryParams(boolean owner, boolean attendee) {
+		this.owner = owner;
+		this.attendee = attendee;
+	}
+
+	public String getIdRef() {
+		return idRef;
+	}
+
+	public void setIdRef(String idRef) {
+		this.idRef = idRef;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getDescription() {
+		return description;
+	}
+
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	public String getOwnerName() {
+		return ownerName;
+	}
+
+	public void setOwnerName(String ownerName) {
+		this.ownerName = ownerName;
+	}
+
+	public String getCourseTitle() {
+		return courseTitle;
+	}
+
+	public void setCourseTitle(String courseTitle) {
+		this.courseTitle = courseTitle;
+	}
+
+	public String getNameOrDesc() {
+		return nameOrDesc;
+	}
+
+	public void setNameOrDesc(String nameOrDesc) {
+		this.nameOrDesc = nameOrDesc;
+	}
+
+	public String getExternalId() {
+		return externalId;
+	}
+
+	public void setExternalId(String externalId) {
+		this.externalId = externalId;
+	}
+
+	public boolean isOwner() {
+		return owner;
+	}
+
+	public void setOwner(boolean owner) {
+		this.owner = owner;
+	}
+
+	public boolean isAttendee() {
+		return attendee;
+	}
+
+	public void setAttendee(boolean attendee) {
+		this.attendee = attendee;
+	}
+
+	public boolean isWaiting() {
+		return waiting;
+	}
+
+	public void setWaiting(boolean waiting) {
+		this.waiting = waiting;
+	}
+
+	public Boolean getPublicGroups() {
+		return publicGroups;
+	}
+
+	public void setPublicGroups(Boolean publicGroups) {
+		this.publicGroups = publicGroups;
+	}
+
+	public boolean isMarked() {
+		return marked;
+	}
+
+	/**
+	 * Set true to see the bookmarked groups, false has no effect.
+	 * @param marked
+	 */
+	public void setMarked(boolean marked) {
+		this.marked = marked;
+	}
+
+	public boolean isAuthorConnection() {
+		return authorConnection;
+	}
+
+	public void setAuthorConnection(boolean authorConnection) {
+		this.authorConnection = authorConnection;
+	}
+
+	public Boolean getResources() {
+		return resources;
+	}
+
+	public void setResources(Boolean resources) {
+		this.resources = resources;
+	}
+
+	public Long getBusinessGroupKey() {
+		return businessGroupKey;
+	}
+
+	public void setBusinessGroupKey(Long businessGroupKey) {
+		this.businessGroupKey = businessGroupKey;
+	}
+
+	public RepositoryEntry getRepositoryEntry() {
+		return repositoryEntry;
+	}
+
+	public void setRepositoryEntry(RepositoryEntry repositoryEntry) {
+		this.repositoryEntry = repositoryEntry;
+	}
+
+	/**
+	 * Only available on views
+	 * @return
+	 */
+	public boolean isHeadless() {
+		return headless;
+	}
+
+	/**
+	 * Only available on views
+	 * @param headless
+	 */
+	public void setHeadless(boolean headless) {
+		this.headless = headless;
+	}
+}
diff --git a/src/main/java/org/olat/group/model/BusinessGroupRow.java b/src/main/java/org/olat/group/model/BusinessGroupRow.java
new file mode 100644
index 0000000000000000000000000000000000000000..8ac35c1aa94b7df8ee6fd31e90079644fb9f4d0c
--- /dev/null
+++ b/src/main/java/org/olat/group/model/BusinessGroupRow.java
@@ -0,0 +1,169 @@
+/**
+ * <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.group.model;
+
+import java.util.Date;
+import java.util.List;
+
+import org.olat.group.BusinessGroupManagedFlag;
+import org.olat.group.BusinessGroupRef;
+import org.olat.group.BusinessGroupShort;
+import org.olat.repository.RepositoryEntryShort;
+import org.olat.resource.accesscontrol.model.PriceMethodBundle;
+
+/**
+ * 
+ * Initial date: 05.10.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class BusinessGroupRow implements BusinessGroupRef, BusinessGroupShort {
+	
+	private final Long key;
+	private final String name;
+	private final String description;
+	private final String externalId;
+	private final Date lastUsage;
+	private final Long resourceKey;
+
+	private final Integer maxParticipants;
+	private final Boolean waitingListEnabled;
+	private final Boolean autoCloseRanksEnabled;
+	private final BusinessGroupManagedFlag[] managedFlags;
+	
+	private boolean marked;
+	
+	private BusinessGroupMembershipImpl member;
+	
+	private List<PriceMethodBundle> bundles;
+	protected List<RepositoryEntryShort> resources;
+
+	public BusinessGroupRow(BusinessGroupToSearch businessGroup) {
+		key = businessGroup.getKey();
+		name = businessGroup.getName();
+		lastUsage = businessGroup.getLastUsage();
+		description = businessGroup.getDescription();
+		externalId = businessGroup.getExternalId();
+		managedFlags = businessGroup.getManagedFlags();
+		resourceKey = businessGroup.getResource().getKey();
+		waitingListEnabled = businessGroup.getWaitingListEnabled();
+		autoCloseRanksEnabled = businessGroup.getAutoCloseRanksEnabled();
+		maxParticipants = businessGroup.getMaxParticipants();
+	}
+	
+	public BusinessGroupRow(BusinessGroupRow businessGroup) {
+		key = businessGroup.getKey();
+		name = businessGroup.getName();
+		lastUsage = businessGroup.getLastUsage();
+		description = businessGroup.getDescription();
+		externalId = businessGroup.getExternalId();
+		managedFlags = businessGroup.getManagedFlags();
+		resourceKey = businessGroup.getResourceKey();
+		waitingListEnabled = businessGroup.isWaitingListEnabled();
+		autoCloseRanksEnabled = businessGroup.isAutoCloseRanksEnabled();
+		maxParticipants = businessGroup.getMaxParticipants();
+	}
+	
+	public boolean isWaitingListEnabled() {
+		return  waitingListEnabled == null ? false : waitingListEnabled.booleanValue();
+	}
+	
+	public boolean isAutoCloseRanksEnabled() {
+		return autoCloseRanksEnabled == null ? false : autoCloseRanksEnabled.booleanValue();
+	}
+	
+	public Integer getMaxParticipants() {
+		return maxParticipants;
+	}
+
+	@Override
+	public Long getKey() {
+		return key;
+	}
+
+	public Long getResourceKey() {
+		return resourceKey;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	@Override
+	public String getResourceableTypeName() {
+		return "BusinessGroup";
+	}
+
+	@Override
+	public Long getResourceableId() {
+		return key;
+	}
+
+	public String getDescription() {
+		return description;
+	}
+
+	public Date getLastUsage() {
+		return lastUsage;
+	}
+
+	public String getExternalId() {
+		return externalId;
+	}
+
+	public BusinessGroupManagedFlag[] getManagedFlags() {
+		return managedFlags;
+	}
+
+	public List<PriceMethodBundle> getBundles() {
+		return bundles;
+	}
+
+	public void setBundles(List<PriceMethodBundle> bundles) {
+		this.bundles = bundles;
+	}
+
+	public List<RepositoryEntryShort> getResources() {
+		return resources;
+	}
+
+	public void setResources(List<RepositoryEntryShort> resources) {
+		this.resources = resources;
+	}
+
+	public boolean isMarked() {
+		return marked;
+	}
+
+	public void setMarked(boolean marked) {
+		this.marked = marked;
+	}
+
+	public BusinessGroupMembershipImpl getMember() {
+		return member;
+	}
+
+	public void setMember(BusinessGroupMembershipImpl member) {
+		this.member = member;
+	}
+	
+	
+	
+}
diff --git a/src/main/java/org/olat/group/model/BusinessGroupShortImpl.java b/src/main/java/org/olat/group/model/BusinessGroupShortImpl.java
index b1064064bf8a6cc3394d974971e5c7378edc27d7..8aa256adb1b4c638863af9a10a43e5a8f2695108 100644
--- a/src/main/java/org/olat/group/model/BusinessGroupShortImpl.java
+++ b/src/main/java/org/olat/group/model/BusinessGroupShortImpl.java
@@ -19,7 +19,16 @@
  */
 package org.olat.group.model;
 
-import org.olat.core.commons.persistence.PersistentObject;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+
+import org.hibernate.annotations.GenericGenerator;
+import org.olat.core.id.Persistable;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupManagedFlag;
@@ -33,13 +42,32 @@ import org.olat.group.BusinessGroupShort;
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class BusinessGroupShortImpl extends PersistentObject implements BusinessGroupShort {
+@Entity(name="businessgroupshort")
+@Table(name="o_gp_business")
+@NamedQueries({
+	@NamedQuery(name="loadBusinessGroupShortByIds",query="select bgi from businessgroupshort bgi  where bgi.key in (:ids)")
+})
+public class BusinessGroupShortImpl implements Persistable, BusinessGroupShort {
 
 	private static final long serialVersionUID = -5404538852842562897L;
 	
+	@Id
+	@GeneratedValue(generator = "system-uuid")
+	@GenericGenerator(name = "system-uuid", strategy = "hilo")
+	@Column(name="group_id", nullable=false, unique=true, insertable=true, updatable=false)
+	private Long key;
+
+	@Column(name="groupname", nullable=true, insertable=false, updatable=false)
 	private String name;
+	@Column(name="managed_flags", nullable=true, insertable=false, updatable=false)
 	private String managedFlagsString;
+	
+	@Override
+	public Long getKey() {
+		return key;
+	}
 
+	@Override
 	public String getName() {
 		return name;
 	}
@@ -85,7 +113,12 @@ public class BusinessGroupShortImpl extends PersistentObject implements Business
 		}
 		return false;
 	}
-	
+
+	@Override
+	public boolean equalsByPersistableKey(Persistable persistable) {
+		return equals(persistable);
+	}
+
 	@Override
 	public int hashCode() {
 		return getKey() == null ? 2901 : getKey().hashCode();
diff --git a/src/main/java/org/olat/group/model/BusinessGroupToSearch.java b/src/main/java/org/olat/group/model/BusinessGroupToSearch.java
new file mode 100644
index 0000000000000000000000000000000000000000..f90dc7563343eda665d88671911481ba26e8d64c
--- /dev/null
+++ b/src/main/java/org/olat/group/model/BusinessGroupToSearch.java
@@ -0,0 +1,175 @@
+/**
+ * <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.group.model;
+
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import org.hibernate.annotations.GenericGenerator;
+import org.olat.basesecurity.Group;
+import org.olat.basesecurity.model.GroupImpl;
+import org.olat.core.id.Persistable;
+import org.olat.core.util.StringHelper;
+import org.olat.group.BusinessGroup;
+import org.olat.group.BusinessGroupManagedFlag;
+import org.olat.resource.OLATResource;
+import org.olat.resource.OLATResourceImpl;
+
+/**
+ * 
+ * Initial date: 09.10.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Entity(name="businessgrouptosearch")
+@Table(name="o_gp_business")
+public class BusinessGroupToSearch implements Persistable {
+
+	private static final long serialVersionUID = 1483583378938116438L;
+
+	@Id
+	@GeneratedValue(generator = "system-uuid")
+	@GenericGenerator(name = "system-uuid", strategy = "hilo")
+	@Column(name="group_id", nullable=false, unique=true, insertable=true, updatable=false)
+	private Long key;
+	
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="creationdate", nullable=false, insertable=true, updatable=false)
+	private Date creationDate;
+
+	@Column(name="descr", nullable=true, insertable=true, updatable=true)
+	private String description;
+	@Column(name="groupname", nullable=true, insertable=true, updatable=true)
+	private String name;
+	
+	@Column(name="external_id", nullable=true, insertable=true, updatable=true)
+	private String externalId;
+	@Column(name="managed_flags", nullable=true, insertable=true, updatable=true)
+	private String managedFlagsString;
+	
+	@Column(name="maxparticipants", nullable=true, insertable=true, updatable=true)
+	private Integer maxParticipants;
+	@Column(name="waitinglist_enabled", nullable=true, insertable=true, updatable=true)
+	private Boolean waitingListEnabled;
+	@Column(name="autocloseranks_enabled", nullable=true, insertable=true, updatable=true)
+	private Boolean autoCloseRanksEnabled;
+
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="lastusage", nullable=true, insertable=true, updatable=true)
+	private Date lastUsage;
+
+	@Column(name="allowtoleave", nullable=true, insertable=true, updatable=true)
+	private boolean allowToLeave;
+	
+	@ManyToOne(targetEntity=OLATResourceImpl.class,fetch=FetchType.LAZY, optional=true)
+	@JoinColumn(name="fk_resource", nullable=true, insertable=true, updatable=true)
+	private OLATResource resource;
+	
+	@ManyToOne(targetEntity=GroupImpl.class,fetch=FetchType.LAZY,optional=false)
+	@JoinColumn(name="fk_group_id", nullable=false, insertable=false, updatable=false)
+	private Group baseGroup;
+	
+	@Override
+	public Long getKey() {
+		return key;
+	}
+	
+	public String getName() {
+		return name;
+	}
+
+	public String getDescription() {
+		return description;
+	}
+
+	public String getExternalId() {
+		return externalId;
+	}
+
+	public BusinessGroupManagedFlag[] getManagedFlags() {
+		if(StringHelper.containsNonWhitespace(managedFlagsString)) {
+			return BusinessGroupManagedFlag.toEnum(managedFlagsString);
+		}
+		return new BusinessGroupManagedFlag[0];
+	}
+
+	public boolean isAllowToLeave() {
+		return allowToLeave;
+	}
+
+	public OLATResource getResource() {
+		return resource;
+	}
+
+	public Group getBaseGroup() {
+		return baseGroup;
+	}
+
+	public Date getLastUsage() {
+		return lastUsage;
+	}
+
+	public Integer getMaxParticipants() {
+		return maxParticipants;
+	}
+
+	public Boolean getAutoCloseRanksEnabled() {
+		return autoCloseRanksEnabled;
+	}
+
+	public Boolean getWaitingListEnabled() {
+		return waitingListEnabled;
+	}
+	
+	/**
+	 * Compares the keys.
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	@Override
+	public boolean equals(Object obj) {
+		if(this == obj) {
+			return true;
+		} else if (obj instanceof BusinessGroup) {
+			BusinessGroup bg = (BusinessGroup)obj;
+			return getKey() != null && getKey().equals(bg.getKey());
+		}
+		return false;
+	}
+	
+	@Override
+	public boolean equalsByPersistableKey(Persistable persistable) {
+		return equals(persistable);
+	}
+	
+	@Override
+	public int hashCode() {
+		return getKey() == null ? 2901 : getKey().hashCode();
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/model/BusinessGroupViewImpl.hbm.xml b/src/main/java/org/olat/group/model/BusinessGroupViewImpl.hbm.xml
deleted file mode 100644
index 74bebc08d5dd323dc562771f720a336de9459434..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/group/model/BusinessGroupViewImpl.hbm.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE hibernate-mapping PUBLIC
-	"-//Hibernate/Hibernate Mapping DTD//EN"
-	"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
-
-<hibernate-mapping default-lazy="false">
-	<class name="org.olat.group.model.BusinessGroupViewImpl" table="o_gp_business_v" mutable="false">
-
-		<id name="key" type="long" column="group_id" unsaved-value="null">
-			<generator class="hilo"/>
-		</id>
-		<property  name="lastModified" column="lastmodified" type="timestamp" />
-		<property  name="creationDate" column="creationdate" type="timestamp" />
-		<!-- standards business group fields -->
-  		<property name="lastUsage" column="lastusage" type="timestamp" />
-		<property name="externalId" type="string" column="external_id" />	
-		<property name="name" type="string" column="groupname" unique="false" length="255" index="gp_name_idx"/>	
-		<property name="description" type="string" column="descr" length="16777210" not-null="false"/>
-		<property name="minParticipants" column="minparticipants" not-null="false"/>
-		<property name="maxParticipants" column="maxparticipants" not-null="false"/>
-		<property name="waitingListEnabled" type="boolean" column="waitinglist_enabled" unique="false" not-null="false"/>	
-		<property name="autoCloseRanksEnabled" type="boolean" column="autocloseranks_enabled" unique="false" not-null="false"/>
-		<property name="managedFlagsString" column="managed_flags" unique="false" not-null="false" type="string"/>
-		<!--  statistics informations -->
-  		<property name="numOfOwners" column="num_of_owners" type="long" />
-  		<property name="numOfParticipants" column="num_of_participants" type="long" />
-  		<property name="numOfPendings" column="num_of_pendings" type="long" />
-  		<property name="numOfRelations" column="num_of_relations" type="long" />
-  		<property name="numOfOffers" column="num_of_offers" type="long" />
-  		<property name="numOfValidOffers" column="num_of_valid_offers" type="long" />
-
-		<many-to-one name="resource" class="org.olat.resource.OLATResourceImpl"
-    		outer-join="true" cascade="none" lazy="false">  
-			<column name="fk_resource" not-null="false" unique="true" />    	
-    	</many-to-one> 
-
-		<many-to-one name="baseGroup"
-    		class="org.olat.basesecurity.model.GroupImpl"
-    		outer-join="true"
-    		cascade="none">
-			<column name="fk_group_id" not-null="false" unique="true" />
-    	</many-to-one>		  	
-	</class>
-
-</hibernate-mapping>
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/model/BusinessGroupViewImpl.java b/src/main/java/org/olat/group/model/BusinessGroupViewImpl.java
deleted file mode 100644
index c928aff89cd18876ab6c4280fa5708dcd98796e2..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/group/model/BusinessGroupViewImpl.java
+++ /dev/null
@@ -1,273 +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>
- * 2011 by frentix GmbH, http://www.frentix.com
- * <p>
-**/
-package org.olat.group.model;
-
-import java.util.Date;
-
-import org.olat.basesecurity.Group;
-import org.olat.core.commons.persistence.PersistentObject;
-import org.olat.core.util.resource.OresHelper;
-import org.olat.group.BusinessGroup;
-import org.olat.group.BusinessGroupManagedFlag;
-import org.olat.group.BusinessGroupView;
-import org.olat.resource.OLATResource;
-
-/**
- * 
- * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
- */
-public class BusinessGroupViewImpl extends PersistentObject implements BusinessGroupView {
-
-	private static final long serialVersionUID = -9042740930754224954L;
-	
-	private Long identityKey;
-	private String description;
-	private String name;
-	private String externalId;
-	private Integer minParticipants;
-	private Integer maxParticipants;
-	private OLATResource resource;
-	private Group baseGroup;
-	private Date lastUsage;
-	private Boolean waitingListEnabled;
-	private Boolean autoCloseRanksEnabled;
-	private Date lastModified;
-	private String managedFlagsString;
-
-	private long numOfOwners;
-	private long numOfParticipants;
-	private long numOfPendings;
-	private long numWaiting;
-	private long numOfRelations;
-	private long numOfOffers;
-	private long numOfValidOffers;
-
-	@Override
-	public long getNumOfRelations() {
-		return numOfRelations;
-	}
-
-	public void setNumOfRelations(long numOfRelations) {
-		this.numOfRelations = numOfRelations;
-	}
-
-	@Override
-	public long getNumOfOwners() {
-		return numOfOwners;
-	}
-
-	public void setNumOfOwners(long numOfOwners) {
-		this.numOfOwners = numOfOwners;
-	}
-
-	@Override
-	public long getNumOfParticipants() {
-		return numOfParticipants;
-	}
-
-	public void setNumOfParticipants(long numOfParticipants) {
-		this.numOfParticipants = numOfParticipants;
-	}
-
-	@Override
-	public long getNumOfPendings() {
-		return numOfPendings;
-	}
-
-	public void setNumOfPendings(long numOfPendings) {
-		this.numOfPendings = numOfPendings;
-	}
-
-	@Override
-	public long getNumWaiting() {
-		return numWaiting;
-	}
-
-	public void setNumWaiting(long numWaiting) {
-		this.numWaiting = numWaiting;
-	}
-
-	@Override
-	public long getNumOfOffers() {
-		return numOfOffers;
-	}
-	
-	public void setNumOfOffers(long numOfOffers) {
-		this.numOfOffers = numOfOffers;
-	}
-
-	@Override
-	public long getNumOfValidOffers() {
-		return numOfValidOffers;
-	}
-
-	public void setNumOfValidOffers(long numOfValidOffers) {
-		this.numOfValidOffers = numOfValidOffers;
-	}
-	
-	public Long getIdentityKey() {
-		return identityKey;
-	}
-
-	public void setIdentityKey(Long identityKey) {
-		this.identityKey = identityKey;
-	}
-
-	@Override
-	public String getResourceableTypeName() {
-		return OresHelper.calculateTypeName(BusinessGroup.class);
-	}
-
-	@Override
-	public Long getResourceableId() {
-		return getKey();
-	}
-
-	@Override
-	public Date getLastModified() {
-		return lastModified;
-	}
-
-	@Override
-	public void setLastModified(Date date) {
-		this.lastModified = date;
-	}
-
-	public String getExternalId() {
-		return externalId;
-	}
-
-	public void setExternalId(String externalId) {
-		this.externalId = externalId;
-	}
-
-	@Override
-	public String getName() {
-		return name;
-	}
-
-	public void setName(String name) {
-		this.name = name;
-	}
-
-	@Override
-	public String getDescription() {
-		return description;
-	}
-
-	public void setDescription(String description) {
-		this.description = description;
-	}
-	
-	@Override
-	public Date getLastUsage() {
-		return lastUsage;
-	}
-
-	public void setLastUsage(Date lastUsage) {
-		this.lastUsage = lastUsage;
-	}
-
-	public String getManagedFlagsString() {
-		return managedFlagsString;
-	}
-
-	public void setManagedFlagsString(String managedFlagsString) {
-		this.managedFlagsString = managedFlagsString;
-	}
-
-	@Override
-	public BusinessGroupManagedFlag[] getManagedFlags() {
-		return BusinessGroupManagedFlag.toEnum(managedFlagsString);
-	}
-
-	@Override
-	public OLATResource getResource() {
-		return resource;
-	}
-	
-
-	public void setResource(OLATResource resource) {
-		this.resource = resource;
-	}
-
-	public Group getBaseGroup() {
-		return baseGroup;
-	}
-
-	public void setBaseGroup(Group group) {
-		this.baseGroup = group;
-	}
-
-	@Override
-	public Integer getMaxParticipants() {
-		return maxParticipants;
-	}
-
-	public void setMaxParticipants(Integer maxParticipants) {
-		this.maxParticipants = maxParticipants;
-	}
-
-	@Override
-	public Integer getMinParticipants() {
-		return minParticipants;
-	}
-
-	public void setMinParticipants(Integer minParticipants) {
-		this.minParticipants = minParticipants;
-	}
-
-	@Override
-	public Boolean getAutoCloseRanksEnabled() {
-		return autoCloseRanksEnabled;
-	}
-
-	public void setAutoCloseRanksEnabled(Boolean autoCloseRanksEnabled) {
-		this.autoCloseRanksEnabled = autoCloseRanksEnabled;
-	}
-
-	@Override
-	public Boolean getWaitingListEnabled() {
-		return waitingListEnabled;
-	}
-
-	public void setWaitingListEnabled(Boolean waitingListEnabled) {
-		this.waitingListEnabled = waitingListEnabled;
-	}
-
-	@Override
-	public int hashCode() {
-		return (getKey() == null ? 2634 : getKey().hashCode())
-			+ (identityKey == null ? -24 :identityKey.hashCode());
-	}
-
-	@Override
-	public boolean equals(Object obj) {
-		if(this == obj) {
-			return true;
-		}
-		if(obj instanceof BusinessGroupViewImpl) {
-			BusinessGroupViewImpl centric = (BusinessGroupViewImpl)obj;
-			return getKey() != null && getKey().equals(centric.getKey())
-					&& identityKey != null && identityKey.equals(centric.getKey());
-		}
-		return false;
-	}
-}
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/model/GroupToBusinessGroup.java b/src/main/java/org/olat/group/model/GroupToBusinessGroup.java
new file mode 100644
index 0000000000000000000000000000000000000000..0bb708f1ec8af9297ce067a277b6545baa09ba3a
--- /dev/null
+++ b/src/main/java/org/olat/group/model/GroupToBusinessGroup.java
@@ -0,0 +1,55 @@
+/**
+ * <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.group.model;
+
+import java.util.Set;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+
+import org.hibernate.annotations.GenericGenerator;
+import org.olat.group.BusinessGroup;
+import org.olat.group.BusinessGroupImpl;
+
+/**
+ * Build the relation repository entry to business group.
+ * 
+ * Initial date: 29.10.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Entity(name="grouptobusinessgroup")
+@Table(name="o_bs_group")
+public class GroupToBusinessGroup {
+	
+	@Id
+	@GeneratedValue(generator = "system-uuid")
+	@GenericGenerator(name = "system-uuid", strategy = "hilo")
+	@Column(name="id", nullable=false, unique=true, insertable=true, updatable=false)
+	private Long key;
+
+	@OneToMany(targetEntity=BusinessGroupImpl.class, mappedBy="baseGroup")
+	private Set<BusinessGroup> businessGroups;
+
+}
diff --git a/src/main/java/org/olat/group/model/OpenBusinessGroupRow.java b/src/main/java/org/olat/group/model/OpenBusinessGroupRow.java
new file mode 100644
index 0000000000000000000000000000000000000000..5d73152673654dcf14dc063f5f138050aeaf0b9b
--- /dev/null
+++ b/src/main/java/org/olat/group/model/OpenBusinessGroupRow.java
@@ -0,0 +1,47 @@
+/**
+ * <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.group.model;
+
+/**
+ * 
+ * Initial date: 29.10.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class OpenBusinessGroupRow extends BusinessGroupRow {
+	
+	private Long numOfParticipants;
+	private Long numOfReservations;
+	
+	public OpenBusinessGroupRow(BusinessGroupToSearch businessGroup, Long numOfParticipants, Long numOfReservations) {
+		super(businessGroup);
+		this.numOfParticipants = numOfParticipants;
+		this.numOfReservations = numOfReservations;
+	}
+
+	public Long getNumOfParticipants() {
+		return numOfParticipants;
+	}
+
+	public Long getNumOfReservations() {
+		return numOfReservations;
+	}
+
+}
diff --git a/src/main/java/org/olat/group/model/RepositoryEntryToBusinessGroup.java b/src/main/java/org/olat/group/model/RepositoryEntryToBusinessGroup.java
new file mode 100644
index 0000000000000000000000000000000000000000..fb1bb0802c3ac4f1262d1278aea647770dfe4ad1
--- /dev/null
+++ b/src/main/java/org/olat/group/model/RepositoryEntryToBusinessGroup.java
@@ -0,0 +1,59 @@
+/**
+ * <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.group.model;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+import org.hibernate.annotations.GenericGenerator;
+import org.olat.repository.RepositoryEntry;
+
+/**
+ * Map the relation repository entry to business groups.
+ * 
+ * Initial date: 29.10.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Entity(name="repoentrytobusinessgroup")
+@Table(name="o_re_to_group")
+public class RepositoryEntryToBusinessGroup {
+	
+	@Id
+	@GeneratedValue(generator = "system-uuid")
+	@GenericGenerator(name = "system-uuid", strategy = "hilo")
+	@Column(name="id", nullable=false, unique=true, insertable=true, updatable=false)
+	private Long key;
+	
+	@ManyToOne(targetEntity=RepositoryEntry.class,fetch=FetchType.LAZY,optional=false)
+	@JoinColumn(name="fk_entry_id", nullable=false, insertable=true, updatable=false)
+	private RepositoryEntry entry;
+	
+	@ManyToOne(targetEntity=GroupToBusinessGroup.class,fetch=FetchType.LAZY)
+	@JoinColumn(name="fk_group_id", nullable=false, insertable=false, updatable=false)
+	private GroupToBusinessGroup businessGroup;
+
+}
diff --git a/src/main/java/org/olat/group/model/SearchBusinessGroupParams.java b/src/main/java/org/olat/group/model/SearchBusinessGroupParams.java
index 5421835659fbd5f5877e1b820592732d6dd28c4f..87d57ac63a0256c073e4e6e61d0c55d4af86d0a0 100644
--- a/src/main/java/org/olat/group/model/SearchBusinessGroupParams.java
+++ b/src/main/java/org/olat/group/model/SearchBusinessGroupParams.java
@@ -42,7 +42,6 @@ public class SearchBusinessGroupParams {
 	private String name;
 	private String exactName;
 	private String description;
-	private String ownerName;
 	private String courseTitle;
 	private String externalId;
 	private Boolean managed;
@@ -52,13 +51,6 @@ public class SearchBusinessGroupParams {
 	private boolean owner;
 	private boolean attendee;
 	private boolean waiting;
-	private Boolean publicGroups;
-	private Boolean marked;
-	private Boolean resources;
-	private boolean headless = false;
-	private int numOfMembers = -1;
-	private boolean numOfMembersBigger = true;
-	
 	
 	public SearchBusinessGroupParams() {
 		//
@@ -127,14 +119,6 @@ public class SearchBusinessGroupParams {
 		this.description = description;
 	}
 
-	public String getOwnerName() {
-		return ownerName;
-	}
-
-	public void setOwnerName(String ownerName) {
-		this.ownerName = ownerName;
-	}
-
 	public String getCourseTitle() {
 		return courseTitle;
 	}
@@ -199,75 +183,6 @@ public class SearchBusinessGroupParams {
 		this.waiting = waiting;
 	}
 
-	public Boolean getPublicGroups() {
-		return publicGroups;
-	}
-
-	public void setPublicGroups(Boolean publicGroups) {
-		this.publicGroups = publicGroups;
-	}
-
-	public Boolean getMarked() {
-		return marked;
-	}
-
-	public void setMarked(Boolean marked) {
-		this.marked = marked;
-	}
-
-	public Boolean getResources() {
-		return resources;
-	}
-
-	public void setResources(Boolean resources) {
-		this.resources = resources;
-	}
 
-	/**
-	 * Only available on views
-	 * @return
-	 */
-	public boolean isHeadless() {
-		return headless;
-	}
 
-	/**
-	 * Only available on views
-	 * @param headless
-	 */
-	public void setHeadless(boolean headless) {
-		this.headless = headless;
-	}
-
-	/**
-	 * Only available on views
-	 * @return
-	 */
-	public int getNumOfMembers() {
-		return numOfMembers;
-	}
-
-	/**
-	 * Only available on views
-	 * @param headless
-	 */
-	public void setNumOfMembers(int numOfMembers) {
-		this.numOfMembers = numOfMembers;
-	}
-	
-	/**
-	 * Only available on views
-	 * @return
-	 */
-	public boolean isNumOfMembersBigger() {
-		return numOfMembersBigger;
-	}
-
-	/**
-	 * Only available on views
-	 * @param headless
-	 */
-	public void setNumOfMembersBigger(boolean numOfMembersBigger) {
-		this.numOfMembersBigger = numOfMembersBigger;
-	}
 }
diff --git a/src/main/java/org/olat/group/model/StatisticsBusinessGroupRow.java b/src/main/java/org/olat/group/model/StatisticsBusinessGroupRow.java
new file mode 100644
index 0000000000000000000000000000000000000000..58f9a4dcc7e32d4414b25aa7e60410d5a31fa705
--- /dev/null
+++ b/src/main/java/org/olat/group/model/StatisticsBusinessGroupRow.java
@@ -0,0 +1,60 @@
+/**
+ * <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.group.model;
+
+/**
+ * 
+ * Initial date: 29.10.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class StatisticsBusinessGroupRow extends BusinessGroupRow {
+	
+	private int numOfCoaches;
+	private int numOfParticipants;
+	private int numWaiting;
+	private int numPending;
+	
+	public StatisticsBusinessGroupRow(BusinessGroupToSearch businessGroup,
+			Number coaches, Number participants, Number waiting, Number pending) {
+		super(businessGroup);
+		numOfCoaches = coaches == null ? 0 : coaches.intValue();
+		numOfParticipants = participants == null ? 0 : participants.intValue();
+		numWaiting = waiting == null ? 0 : waiting.intValue();
+		numPending = pending == null ? 0 : pending.intValue();
+	}
+
+	public long getNumOfCoaches() {
+		return numOfCoaches;
+	}
+	
+	public long getNumOfParticipants() {
+		return numOfParticipants;
+	}
+	
+	public long getNumWaiting() {
+		return numWaiting;
+	}
+
+	public long getNumPending() {
+		return numPending;
+	}
+
+}
diff --git a/src/main/java/org/olat/group/ui/main/BusinessGroupTableModelWithType.java b/src/main/java/org/olat/group/ui/main/AbstractBusinessGroupFlexiTableModel.java
similarity index 68%
rename from src/main/java/org/olat/group/ui/main/BusinessGroupTableModelWithType.java
rename to src/main/java/org/olat/group/ui/main/AbstractBusinessGroupFlexiTableModel.java
index fb04b8aef75be1962f18d657d69d9c3b70d03119..89f1928ec4f11fefb3c3a4a9bbaedacde8176897 100644
--- a/src/main/java/org/olat/group/ui/main/BusinessGroupTableModelWithType.java
+++ b/src/main/java/org/olat/group/ui/main/AbstractBusinessGroupFlexiTableModel.java
@@ -1,73 +1,63 @@
 /**
-* OLAT - Online Learning and Training<br>
-* http://www.olat.org
-* <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
-* <p>
-* http://www.apache.org/licenses/LICENSE-2.0
-* <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>
-* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
-* University of Zurich, Switzerland.
-* <hr>
-* <a href="http://www.openolat.org">
-* OpenOLAT - Online Learning and Training</a><br>
-* This file has been modified by the OpenOLAT community. Changes are licensed
-* under the Apache 2.0 license as the original file.
-*/
-
+ * <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.group.ui.main;
 
 import java.util.ArrayList;
 import java.util.List;
 
 import org.olat.core.gui.UserRequest;
-import org.olat.core.gui.components.table.DefaultTableDataModel;
-import org.olat.core.gui.translator.Translator;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
 import org.olat.core.util.Formatter;
 import org.olat.core.util.filter.FilterFactory;
 import org.olat.group.BusinessGroupManagedFlag;
 import org.olat.group.BusinessGroupMembership;
 
 /**
- * @author gnaegi
+ * 
+ * Initial date: 10.06.2014<br>
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
  */
-public class BusinessGroupTableModelWithType extends DefaultTableDataModel<BGTableItem> {
-	private final int columnCount;
-	private final Translator trans;
+public abstract class AbstractBusinessGroupFlexiTableModel extends DefaultFlexiTableDataModel<BGTableItem> {
 
 	/**
 	 * @param owned list of business groups
 	 */
-	public BusinessGroupTableModelWithType(Translator trans, int columnCount) {
-		super(new ArrayList<BGTableItem>());
-		this.trans = trans;
-		this.columnCount = columnCount;
-	}
-
-	/**
-	 * @see org.olat.core.gui.components.table.TableDataModel#getColumnCount()
-	 */
-	public int getColumnCount() {
-		return columnCount;
+	public AbstractBusinessGroupFlexiTableModel(FlexiTableColumnModel columnModel) {
+		super(new ArrayList<BGTableItem>(), columnModel);
 	}
 
 	/**
 	 * @see org.olat.core.gui.components.table.TableDataModel#getValueAt(int, int)
 	 */
+	@Override
 	public Object getValueAt(int row, int col) {
-		BGTableItem wrapped = objects.get(row);
+		BGTableItem wrapped = getObject(row);
+		return getValueAt(wrapped, col);
+	}	
+		
+	public Object getValueAt(BGTableItem wrapped, int col) {
 		switch (Cols.values()[col]) {
 			case name:
-				return wrapped.getBusinessGroup();
+				return wrapped;
 			case description:
 				String description = wrapped.getBusinessGroupDescription();
 				description = FilterFactory.getHtmlTagsFilter().filter(description);
@@ -95,21 +85,14 @@ public class BusinessGroupTableModelWithType extends DefaultTableDataModel<BGTab
 			}
 			case resources:
 				return wrapped;
-			//fxdiff VCRP-1,2: access control of resources
 			case accessControl:
 				return new Boolean(wrapped.isAccessControl());
 			case accessControlLaunch:
-				if(wrapped.isAccessControl()) {
-					if(wrapped.getMembership() != null) {
-						return trans.translate("select");
-					}
-					return trans.translate("table.access");
-				}
-				return null;
+				return wrapped.getAccessLink();
 			case accessTypes:
 				return wrapped.getAccessTypes();
 			case mark:
-				return new Boolean(wrapped.isMarked());
+				return wrapped.getMarkLink();
 			case lastUsage:
 				return wrapped.getBusinessGroupLastUsage();
 			case role:
@@ -123,7 +106,7 @@ public class BusinessGroupTableModelWithType extends DefaultTableDataModel<BGTab
 				return membership == null ? null : membership.getLastModified();
 			}
 			case key:
-				return wrapped.getBusinessGroupKey().toString();
+				return wrapped.getBusinessGroupKey();
 			case freePlaces: {
 				Integer maxParticipants = wrapped.getMaxParticipants();
 				if(maxParticipants != null && maxParticipants.intValue() >= 0) {
@@ -151,15 +134,21 @@ public class BusinessGroupTableModelWithType extends DefaultTableDataModel<BGTab
 				return wrapped;
 			case externalId:
 				return wrapped.getBusinessGroupExternalId();
+			case unlink: {	
+				boolean managed = BusinessGroupManagedFlag.isManaged(wrapped.getManagedFlags(), BusinessGroupManagedFlag.resources);
+				return managed ? Boolean.FALSE : Boolean.TRUE;
+			}
 			default:
 				return "ERROR";
 		}
 	}
-	
-	@Override
-	public Object createCopyWithEmptyList() {
-		return new BusinessGroupTableModelWithType(trans, columnCount);
-	}
+	/*
+	public void sort(SortKey orderBy) {
+		if(orderBy != null) {
+			List<BGTableItem> views = new BusinessGroupFlexiTableModelSort(orderBy, null, null).sort();
+			super.setObjects(views);
+		}
+	}*/
 	
 	public boolean filterEditableGroupKeys(UserRequest ureq, List<Long> groupKeys) {
 		if(ureq.getUserSession().getRoles().isOLATAdmin() || ureq.getUserSession().getRoles().isGroupManager()) {
@@ -191,13 +180,18 @@ public class BusinessGroupTableModelWithType extends DefaultTableDataModel<BGTab
 	public void removeBusinessGroup(Long bgKey) {
 		if(bgKey == null) return;
 		
-		for(int i=objects.size(); i-->0; ) {
-			BGTableItem wrapped = objects.get(i);
+		boolean removed = false;
+		List<BGTableItem> items = getObjects();
+		for(int i=items.size(); i-->0; ) {
+			BGTableItem wrapped = items.get(i);
 			if(bgKey.equals(wrapped.getBusinessGroupKey())) {
-				objects.remove(i);
-				return;
+				items.remove(i);
+				removed = true;
 			}
 		}
+		if(removed) {
+			setObjects(items);
+		}
 	}
 	
 	public enum Cols {
@@ -222,7 +216,8 @@ public class BusinessGroupTableModelWithType extends DefaultTableDataModel<BGTab
 		waitingListCount("table.header.waitingListCount"),
 		wrapper(""),
 		card("table.header.businesscard"),
-		externalId("table.header.externalid");
+		externalId("table.header.externalid"),
+		unlink("table.header.unlink");
 		
 		private final String i18n;
 		
diff --git a/src/main/java/org/olat/group/ui/main/AbstractBusinessGroupListController.java b/src/main/java/org/olat/group/ui/main/AbstractBusinessGroupListController.java
index 67e1dee9b9ff1227b167dce6424f4f5bf72ccf8c..3a1019b07730d85b9edfb1df82e83fdc481c4d8e 100644
--- a/src/main/java/org/olat/group/ui/main/AbstractBusinessGroupListController.java
+++ b/src/main/java/org/olat/group/ui/main/AbstractBusinessGroupListController.java
@@ -21,13 +21,9 @@ package org.olat.group.ui.main;
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
-import java.util.Map;
 import java.util.Set;
 
 import org.olat.NewControllerFactory;
@@ -35,7 +31,6 @@ import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.GroupRoles;
 import org.olat.collaboration.CollaborationTools;
 import org.olat.collaboration.CollaborationToolsFactory;
-import org.olat.core.commons.services.mark.Mark;
 import org.olat.core.commons.services.mark.MarkManager;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
@@ -84,21 +79,21 @@ import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupManagedFlag;
 import org.olat.group.BusinessGroupMembership;
 import org.olat.group.BusinessGroupModule;
+import org.olat.group.BusinessGroupRef;
 import org.olat.group.BusinessGroupService;
 import org.olat.group.BusinessGroupShort;
-import org.olat.group.BusinessGroupView;
 import org.olat.group.GroupLoggingAction;
 import org.olat.group.area.BGAreaManager;
 import org.olat.group.manager.BusinessGroupMailing;
 import org.olat.group.manager.BusinessGroupMailing.MailType;
-import org.olat.group.model.BGRepositoryEntryRelation;
+import org.olat.group.model.BusinessGroupQueryParams;
+import org.olat.group.model.BusinessGroupRow;
 import org.olat.group.model.BusinessGroupSelectionEvent;
 import org.olat.group.model.LeaveOption;
 import org.olat.group.model.MembershipModification;
-import org.olat.group.model.SearchBusinessGroupParams;
 import org.olat.group.right.BGRightManager;
 import org.olat.group.ui.NewBGController;
-import org.olat.group.ui.main.BusinessGroupTableModelWithType.Cols;
+import org.olat.group.ui.main.BusinessGroupFlexiTableModel.Cols;
 import org.olat.group.ui.wizard.BGConfigBusinessGroup;
 import org.olat.group.ui.wizard.BGConfigToolsStep;
 import org.olat.group.ui.wizard.BGCopyBusinessGroup;
@@ -113,8 +108,6 @@ import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryEntryRef;
 import org.olat.repository.RepositoryEntryShort;
 import org.olat.resource.accesscontrol.ACService;
-import org.olat.resource.accesscontrol.model.OLATResourceAccess;
-import org.olat.resource.accesscontrol.model.PriceMethodBundle;
 import org.olat.util.logging.activity.LoggingResourceable;
 import org.springframework.beans.factory.annotation.Autowired;
 
@@ -139,8 +132,8 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 	protected static final BusinessGroupMembershipComparator MEMBERSHIP_COMPARATOR = new BusinessGroupMembershipComparator();
 
 	protected FlexiTableElement tableEl;
-	protected BusinessGroupFlexiTableModel groupTableModel;
-	protected SearchBusinessGroupParams lastSearchParams;
+	protected AbstractBusinessGroupFlexiTableModel groupTableModel;
+	protected BusinessGroupQueryParams lastSearchParams;
 	
 	private DialogBoxController leaveDialogBox;
 	
@@ -197,13 +190,13 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 		this.prefsKey = prefsKey;
 
 		initForm(ureq);
-	}
+	} 
 	
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		FlexiTableColumnModel columnModel = initColumnModel();
 		
-		groupTableModel = new BusinessGroupFlexiTableModel(getTranslator(), columnModel);
+		groupTableModel = initTableModel(columnModel);
 		tableEl = uifactory.addTableElement(getWindowControl(), "table", groupTableModel, 20, false, getTranslator(), formLayout);
 
 		FlexiTableSortOptions options = new FlexiTableSortOptions();
@@ -226,6 +219,10 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 	
 	protected abstract FlexiTableColumnModel initColumnModel();
 
+	protected final AbstractBusinessGroupFlexiTableModel initTableModel(FlexiTableColumnModel columnModel) {
+		return new BusinessGroupListFlexiTableModel(columnModel);
+	}
+
 	public Object getUserObject() {
 		return userObject;
 	}
@@ -306,11 +303,11 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 		//
 	}
 	
-	protected List<BGTableItem> getSelectedItems() {
+	protected List<BusinessGroupRow> getSelectedItems() {
 		Set<Integer> selections = tableEl.getMultiSelectedIndex();
-		List<BGTableItem> rows = new ArrayList<>(selections.size());
+		List<BusinessGroupRow> rows = new ArrayList<>(selections.size());
 		for(Integer i:selections) {
-			BGTableItem row = groupTableModel.getObject(i.intValue());
+			BusinessGroupRow row = groupTableModel.getObject(i.intValue());
 			if(row != null) {
 				rows.add(row);
 			}
@@ -340,7 +337,7 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 			FormLink link = (FormLink)source;
 			String cmd = link.getCmd();
 			if("mark".equals(cmd)) {
-				BGTableItem row = (BGTableItem)link.getUserObject();
+				BusinessGroupRow row = (BusinessGroupRow)link.getUserObject();
 				boolean marked = toogleMark(row);
 				link.setIconLeftCSS(marked ? "o_icon o_icon_bookmark o_icon-lg" : "o_icon o_icon_bookmark_add o_icon-lg");
 				link.getComponent().setDirty(true);
@@ -350,9 +347,9 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 			} else if("resource".equals(cmd)) {
 				RepositoryEntryShort re = (RepositoryEntryShort)link.getUserObject();
 				NewControllerFactory.getInstance().launch("[RepositoryEntry:" + re.getKey() + "]", ureq, getWindowControl());
-			} else if(link.getUserObject() instanceof BGTableItem) {
-				BGTableItem item = (BGTableItem)link.getUserObject();
-				Long businessGroupKey = item.getBusinessGroupKey();
+			} else if(link.getUserObject() instanceof BusinessGroupRef) {
+				BusinessGroupRef item = (BusinessGroupRef)link.getUserObject();
+				Long businessGroupKey = item.getKey();
 				BusinessGroup businessGroup = businessGroupService.loadBusinessGroup(businessGroupKey);
 				if(businessGroup == null) {
 					groupTableModel.removeBusinessGroup(businessGroupKey);
@@ -369,8 +366,8 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 			if(event instanceof SelectionEvent) {
 				SelectionEvent se = (SelectionEvent)event;
 				if(se.getIndex() >= 0 && se.getIndex() < groupTableModel.getRowCount()) {
-					BGTableItem item = groupTableModel.getObject(se.getIndex());
-					Long businessGroupKey = item.getBusinessGroupKey();
+					BusinessGroupRef item = groupTableModel.getObject(se.getIndex());
+					Long businessGroupKey = item.getKey();
 					BusinessGroup businessGroup = businessGroupService.loadBusinessGroup(businessGroupKey);
 					//prevent rs after a group is deleted by someone else
 					if(businessGroup == null) {
@@ -403,14 +400,14 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 	 * Add/remove as favorite
 	 * @param item
 	 */
-	private boolean toogleMark(BGTableItem item) {
-		OLATResourceable bgResource = OresHelper.createOLATResourceableInstance("BusinessGroup", item.getBusinessGroupKey());
+	private boolean toogleMark(BusinessGroupRow item) {
+		OLATResourceable bgResource = OresHelper.createOLATResourceableInstance("BusinessGroup", item.getKey());
 		//		item.getBusinessGroup().getResource();
 		if(markManager.isMarked(bgResource, getIdentity(), null)) {
 			markManager.removeMark(bgResource, getIdentity(), null);
 			item.setMarked(false);
 		} else {
-			String businessPath = "[BusinessGroup:" + item.getBusinessGroupKey() + "]";
+			String businessPath = "[BusinessGroup:" + item.getKey() + "]";
 			markManager.setMark(bgResource, getIdentity(), null, businessPath);
 			item.setMarked(true);
 		}
@@ -637,7 +634,7 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 	 * @param ureq
 	 * @param items
 	 */
-	private void doCopy(UserRequest ureq, List<BGTableItem> items) {
+	private void doCopy(UserRequest ureq, List<? extends BusinessGroupRef> items) {
 		removeAsListenerAndDispose(businessGroupWizard);
 		if(items == null || items.isEmpty()) {
 			showWarning("error.select.one");
@@ -699,7 +696,7 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 	 * @param ureq
 	 * @param items
 	 */
-	private void doConfiguration(UserRequest ureq, List<BGTableItem> selectedItems) {
+	private void doConfiguration(UserRequest ureq, List<? extends BusinessGroupRef> selectedItems) {
 		removeAsListenerAndDispose(businessGroupWizard);
 		if(selectedItems == null || selectedItems.isEmpty()) {
 			showWarning("error.select.one");
@@ -783,7 +780,7 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 	 * @param ureq
 	 * @param items
 	 */
-	private void doEmails(UserRequest ureq, List<BGTableItem> selectedItems) {
+	private void doEmails(UserRequest ureq, List<? extends BusinessGroupRef> selectedItems) {
 		removeAsListenerAndDispose(businessGroupWizard);
 		if(selectedItems == null || selectedItems.isEmpty()) {
 			showWarning("error.select.one");
@@ -811,7 +808,7 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 	 * @param ureq
 	 * @param items
 	 */
-	private void doUserManagement(UserRequest ureq, List<BGTableItem> selectedItems) {
+	private void doUserManagement(UserRequest ureq, List<? extends BusinessGroupRef> selectedItems) {
 		removeAsListenerAndDispose(cmc);
 		removeAsListenerAndDispose(userManagementController);
 		if(selectedItems == null || selectedItems.isEmpty()) {
@@ -890,30 +887,30 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 	}
 	
 	protected void doSearch(FlexiTableSearchEvent event) {
-		SearchBusinessGroupParams params = getDefaultSearchParams();
+		BusinessGroupQueryParams params = getDefaultSearchParams();
 		params.setNameOrDesc(event.getSearch());
-		updateTableModel(params, false);
+		loadModel(params);
 	}
 
 	private void search(SearchEvent event) {
 		if(event == null) {
-			updateTableModel(null, false);
+			loadModel(null);
 		} else {
-			SearchBusinessGroupParams params = getSearchParams(event);
-			updateTableModel(params, false);
+			BusinessGroupQueryParams params = getSearchParams(event);
+			loadModel(params);
 		}
 	}
 	
-	protected abstract SearchBusinessGroupParams getSearchParams(SearchEvent event);
+	protected abstract BusinessGroupQueryParams getSearchParams(SearchEvent event);
 	
-	protected abstract SearchBusinessGroupParams getDefaultSearchParams();
+	protected abstract BusinessGroupQueryParams getDefaultSearchParams();
 	
 	protected boolean doDefaultSearch() {
-		SearchBusinessGroupParams params = getDefaultSearchParams();
-		return updateTableModel(params, false).isEmpty();
+		BusinessGroupQueryParams params = getDefaultSearchParams();
+		return loadModel(params) > 0;
 	}
 	
-	private void doSelect(UserRequest ureq, List<BGTableItem> items) {
+	private void doSelect(UserRequest ureq, List<? extends BusinessGroupRef> items) {
 		List<BusinessGroup> selection = toBusinessGroups(ureq, items, false);
 		fireEvent(ureq, new BusinessGroupSelectionEvent(selection));
 	}
@@ -928,7 +925,7 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 	 * @param ureq
 	 * @param items
 	 */
-	private void doMerge(UserRequest ureq, List<BGTableItem> selectedItems) {
+	private void doMerge(UserRequest ureq, List<? extends BusinessGroupRef> selectedItems) {
 		removeAsListenerAndDispose(businessGroupWizard);
 		if(selectedItems == null || selectedItems.size() < 2) {
 			showWarning("error.select.one");
@@ -977,7 +974,7 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 	 * @param ureq
 	 * @param selectedItems
 	 */
-	private void confirmDelete(UserRequest ureq, List<BGTableItem> selectedItems) {
+	private void confirmDelete(UserRequest ureq, List<? extends BusinessGroupRef> selectedItems) {
 		List<BusinessGroup> groups = toBusinessGroups(ureq, selectedItems, true);
 		if(groups.isEmpty()) {
 			showWarning("msg.alleastone.editable.group");
@@ -1009,10 +1006,10 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 		}
 	}
 	
-	protected List<BusinessGroup> toBusinessGroups(UserRequest ureq, List<BGTableItem> items, boolean editableOnly) {
+	protected List<BusinessGroup> toBusinessGroups(UserRequest ureq, List<? extends BusinessGroupRef> items, boolean editableOnly) {
 		List<Long> groupKeys = new ArrayList<Long>();
-		for(BGTableItem item:items) {
-			groupKeys.add(item.getBusinessGroupKey());
+		for(BusinessGroupRef item:items) {
+			groupKeys.add(item.getKey());
 		}
 		if(editableOnly) {
 			groupTableModel.filterEditableGroupKeys(ureq, groupKeys);
@@ -1049,172 +1046,34 @@ public abstract class AbstractBusinessGroupListController extends FormBasicContr
 	}
 	
 	protected void reloadModel() {
-		updateTableModel(lastSearchParams, false);
+		loadModel(lastSearchParams);
 	}
 	
 	protected RepositoryEntryRef getResource() {
 		return null;
 	}
+
+	protected abstract List<BGTableItem> searchTableItems(BusinessGroupQueryParams params);
 	
-	protected List<BusinessGroupView> searchBusinessGroupViews(SearchBusinessGroupParams params) {
-		List<BusinessGroupView> groups;
+	protected final int loadModel(BusinessGroupQueryParams params) {
 		if(params == null) {
-			groups = new ArrayList<BusinessGroupView>();
+			groupTableModel.setEntries(Collections.<BGTableItem>emptyList());
+			tableEl.reset();
+			return 0;
 		} else {
-			groups = businessGroupService.findBusinessGroupViews(params, getResource(), 0, -1);
-			
+			List<BGTableItem> items = searchTableItems(params);
 			if(filter != null) {
-				for(Iterator<BusinessGroupView> groupIt=groups.iterator(); groupIt.hasNext(); ) {
+				for(Iterator<BGTableItem> groupIt=items.iterator(); groupIt.hasNext(); ) {
 					if(!filter.accept(groupIt.next())) {
 						groupIt.remove();
 					}
 				}
 			}
-		}
-		return groups;
-	}
-	
-	protected List<BusinessGroupView> updateTableModel(SearchBusinessGroupParams params, boolean alreadyMarked) {
-		List<BusinessGroupView> groups = searchBusinessGroupViews(params);
-		lastSearchParams = params;
-		if(groups.isEmpty()) {
-			groupTableModel.setEntries(Collections.<BGTableItem>emptyList());
-			tableEl.reset();
-			return groups;
-		}
-
-		List<Long> groupKeysWithMembers;
-		if(groups.size() > 50) {
-			groupKeysWithMembers = null;
-		} else {
-			groupKeysWithMembers = new ArrayList<Long>(groups.size());
-			for(BusinessGroupView view:groups) {
-				groupKeysWithMembers.add(view.getKey());
-			}
-		}
-
-		//retrieve all user's membership if there are more than 50 groups
-		List<BusinessGroupMembership> groupsAsOwner = businessGroupService.getBusinessGroupMembership(groupKeysWithMembers, getIdentity());
-		Map<Long, BusinessGroupMembership> memberships = new HashMap<Long, BusinessGroupMembership>();
-		for(BusinessGroupMembership membership: groupsAsOwner) {
-			memberships.put(membership.getGroupKey(), membership);
-		}
-		
-		//find resources / courses
-		List<Long> groupKeysWithRelations = new ArrayList<Long>();
-		for(BusinessGroupView view:groups) {
-			if(view.getNumOfRelations() > 0) {
-				groupKeysWithRelations.add(view.getKey());
-			}
-		}
-		List<BGRepositoryEntryRelation> resources = businessGroupService.findRelationToRepositoryEntries(groupKeysWithRelations, 0, -1);
-
-		//find offers
-		List<Long> groupWithOfferKeys = new ArrayList<Long>(groups.size());
-		for(BusinessGroupView view:groups) {
-			if(view.getNumOfOffers() > 0) {
-				groupWithOfferKeys.add(view.getResource().getKey());
-			}
-		}
-		List<OLATResourceAccess> resourcesWithAC;
-		if(groupWithOfferKeys.isEmpty()) {
-			resourcesWithAC = Collections.emptyList();
-		} else {
-			resourcesWithAC	= acService.getAccessMethodForResources(groupWithOfferKeys, "BusinessGroup", true, new Date());
-		}
-		
-		Set<Long> markedResources = new HashSet<Long>(groups.size() * 2 + 1);
-		for(BusinessGroupView group:groups) {
-			markedResources.add(group.getResource().getResourceableId());
-		}
-		if(!alreadyMarked) {
-			markManager.filterMarks(getIdentity(), "BusinessGroup", markedResources);
-		}
-		
-		List<BGTableItem> items = new ArrayList<BGTableItem>();
-		Map<Long, BGTableItem> groupKeyToItems = new HashMap<>();
-		for(BusinessGroupView group:groups) {
-			Long oresKey = group.getResource().getKey();
-			List<PriceMethodBundle> accessMethods = null;
-			for(OLATResourceAccess access:resourcesWithAC) {
-				if(oresKey.equals(access.getResource().getKey())){
-					accessMethods = access.getMethods();
-					break;
-				}
-			}
 			
-			BusinessGroupMembership membership =  memberships.get(group.getKey());
-			Boolean allowLeave =  membership != null;
-			Boolean allowDelete = admin ? Boolean.TRUE : (membership == null ? null : new Boolean(membership.isOwner()));
-			
-			boolean marked = markedResources.contains(group.getResource().getResourceableId());
-			FormLink markLink = uifactory.addFormLink("mark_" + group.getKey(), "mark", "", null, null, Link.NONTRANSLATED);
-			markLink.setIconLeftCSS(marked ? Mark.MARK_CSS_LARGE : Mark.MARK_ADD_CSS_LARGE);
-
-			BGTableItem tableItem = new BGTableItem(group, markLink, marked, membership, allowLeave, allowDelete, accessMethods);
-			//tableItem.setUnfilteredRelations(resources);
-			items.add(tableItem);
-			markLink.setUserObject(tableItem);
-			
-			if(group.getNumOfValidOffers() > 0l) {
-				addAccessLink(tableItem);
-			}
-			groupKeyToItems.put(group.getKey(), tableItem);
-		}
-		
-		for(BGRepositoryEntryRelation relation:resources) {
-			BGTableItem tableItem = groupKeyToItems.get(relation.getGroupKey());
-			if(tableItem != null) {
-				tableItem.addRelation(relation);
-			}
-		}
-
-		groupTableModel.setObjects(items);
-		tableEl.reset();
-		return groups;
-	}
-	
-	protected void addAccessLink(BGTableItem item) {
-		String action;
-		BusinessGroupMembership membership = item.getMembership();
-		if(membership != null && membership.isOwner()) {
-			return;
-		} else if(membership != null && (membership.isParticipant() || membership.isWaiting())) {
-			action = TABLE_ACTION_LEAVE;
-		} else if(item.isFull() && !item.isWaitingListEnabled()) {
-			action = null;
-		} else {
-			action = TABLE_ACTION_ACCESS;
-		}
-		
-		String i18nKey;
-		if (membership != null && membership.isParticipant()) {
-			i18nKey = "table.header.leave";
-		} else if (membership != null && membership.isWaiting()) {
-			i18nKey = "table.header.leave.waiting";
-		} if(item.isFull()) {
-			if(item.isWaitingListEnabled()) {
-				i18nKey = "table.access.waitingList";
-			} else {
-				i18nKey = "table.header.group.full";
-			}
-		} else if(item.isWaitingListEnabled()) {
-			if(item.isFull()) {
-				i18nKey = "table.access.waitingList";
-			}	else {
-				i18nKey = "table.access";
-			}
-		} else {
-			i18nKey = "table.access";
-		}
-		
-		FormLink accessLink = uifactory.addFormLink("open_" + item.getBusinessGroupKey(), action, i18nKey,
-				null, null, Link.LINK);
-		if(action == null) {
-			accessLink.setEnabled(false);
+			groupTableModel.setEntries(items);
+			tableEl.reset();
+			return items.size();
 		}
-		accessLink.setUserObject(item);
-		item.setAccessLink(accessLink);
 	}
 	
 	protected static class RoleColumnDescriptor extends CustomRenderColumnDescriptor {
diff --git a/src/main/java/org/olat/group/ui/main/AbstractSelectBusinessGroupListController.java b/src/main/java/org/olat/group/ui/main/AbstractSelectBusinessGroupListController.java
new file mode 100644
index 0000000000000000000000000000000000000000..f7c6077a0aa9a78a0d71825cf1e4d630ba6cd87f
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/main/AbstractSelectBusinessGroupListController.java
@@ -0,0 +1,116 @@
+/**
+ * <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.group.ui.main;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.olat.core.commons.services.mark.Mark;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.EscapeMode;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
+import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.group.model.BusinessGroupQueryParams;
+import org.olat.group.model.StatisticsBusinessGroupRow;
+import org.olat.group.ui.main.BusinessGroupFlexiTableModel.Cols;
+
+/**
+ * Used for the business groups selection popup.
+ * 
+ * Initial date: 29.10.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public abstract class AbstractSelectBusinessGroupListController extends AbstractBusinessGroupListController {
+	
+	public AbstractSelectBusinessGroupListController(UserRequest ureq, WindowControl wControl, String page, String prefsKey) {
+		super(ureq, wControl, page, prefsKey);
+	}
+	
+	@Override
+	protected void initButtons(FormItemContainer formLayout, UserRequest ureq) {
+		//
+	}
+
+	@Override
+	protected FlexiTableColumnModel initColumnModel() {
+		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
+		//mark
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.mark.i18n(), Cols.mark.ordinal(),
+				true, Cols.mark.name()));
+		//group name
+		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.name.i18n(), Cols.name.ordinal(), TABLE_ACTION_LAUNCH,
+				true, Cols.name.name(), new StaticFlexiCellRenderer(TABLE_ACTION_LAUNCH, new BusinessGroupNameCellRenderer())));
+		//id and reference
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.key.i18n(), Cols.key.ordinal(), true, Cols.key.name()));
+		if(groupModule.isManagedBusinessGroups()) {
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.externalId.i18n(), Cols.externalId.ordinal(),
+					true, Cols.externalId.name()));
+		}
+		//description
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.description.i18n(), Cols.description.ordinal(),
+				false, null, FlexiColumnModel.ALIGNMENT_LEFT, new TextFlexiCellRenderer(EscapeMode.antisamy)));
+		//courses
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.resources.i18n(), Cols.resources.ordinal(),
+				true, Cols.resources.name(), FlexiColumnModel.ALIGNMENT_LEFT, new BGResourcesCellRenderer(flc)));
+
+		//stats
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.tutorsCount.i18n(), Cols.tutorsCount.ordinal(),
+				true, Cols.tutorsCount.name()));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.participantsCount.i18n(), Cols.participantsCount.ordinal(),
+				true, Cols.participantsCount.name()));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.freePlaces.i18n(), Cols.freePlaces.ordinal(),
+				true, Cols.freePlaces.name(), FlexiColumnModel.ALIGNMENT_LEFT, new TextFlexiCellRenderer(EscapeMode.none)));
+		//free places = max participant - num of participant - num pending
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.waitingListCount.i18n(), Cols.waitingListCount.ordinal(),
+				true, Cols.waitingListCount.name()));
+		
+		//actions
+		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("select", translate("select"), TABLE_ACTION_SELECT));
+		return columnsModel;
+	}
+
+	@Override
+	protected List<BGTableItem> searchTableItems(BusinessGroupQueryParams params) {
+		List<StatisticsBusinessGroupRow> rows = businessGroupService.findBusinessGroupsForSelection(params, getIdentity());
+		List<BGTableItem> items = new ArrayList<>(rows.size());
+		for(StatisticsBusinessGroupRow row:rows) {
+			FormLink markLink = uifactory.addFormLink("mark_" + row.getKey(), "mark", "", null, null, Link.NONTRANSLATED);
+			markLink.setIconLeftCSS(row.isMarked() ? Mark.MARK_CSS_LARGE : Mark.MARK_ADD_CSS_LARGE);
+			
+			BGTableItem item = new BGTableItem(row, markLink, Boolean.FALSE, Boolean.FALSE);
+			item.setNumOfOwners(row.getNumOfCoaches());
+			item.setNumOfParticipants(row.getNumOfParticipants());
+			item.setNumWaiting(row.getNumWaiting());
+			item.setNumOfPendings(row.getNumPending());
+			items.add(item);
+		}
+		return items;
+	}
+}
diff --git a/src/main/java/org/olat/group/ui/main/AbstractStandardBusinessGroupListController.java b/src/main/java/org/olat/group/ui/main/AbstractStandardBusinessGroupListController.java
new file mode 100644
index 0000000000000000000000000000000000000000..2c54ebea86fa712ea4ebe17d40191d61d41ecab2
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/main/AbstractStandardBusinessGroupListController.java
@@ -0,0 +1,93 @@
+/**
+ * <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.group.ui.main;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.EscapeMode;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.BooleanCellRenderer;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DateFlexiCellRenderer;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.group.ui.main.BusinessGroupFlexiTableModel.Cols;
+
+/**
+ * 
+ * Initial date: 29.10.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public abstract class AbstractStandardBusinessGroupListController extends AbstractBusinessGroupListController {
+	
+	public AbstractStandardBusinessGroupListController(UserRequest ureq, WindowControl wControl, String page, String prefsKey) {
+		super(ureq, wControl, page, prefsKey);
+	}
+	
+	public AbstractStandardBusinessGroupListController(UserRequest ureq, WindowControl wControl, String page,
+			boolean showAdminTools, boolean startExtendedSearch, String prefsKey, Object userObject) {
+		super(ureq, wControl, page, showAdminTools, startExtendedSearch, prefsKey, userObject);
+	}
+
+	@Override
+	protected FlexiTableColumnModel initColumnModel() {
+		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
+		//mark
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.mark.i18n(), Cols.mark.ordinal(),
+				true, Cols.mark.name()));
+		//group name
+		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.name.i18n(), Cols.name.ordinal(), TABLE_ACTION_LAUNCH,
+				true, Cols.name.name(), new StaticFlexiCellRenderer(TABLE_ACTION_LAUNCH, new BusinessGroupNameCellRenderer())));
+		//id and reference
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.key.i18n(), Cols.key.ordinal(), true, Cols.key.name()));
+		if(groupModule.isManagedBusinessGroups()) {
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.externalId.i18n(), Cols.externalId.ordinal(),
+					true, Cols.externalId.name()));
+		}
+		//description
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.description.i18n(), Cols.description.ordinal(),
+				false, null, FlexiColumnModel.ALIGNMENT_LEFT, new TextFlexiCellRenderer(EscapeMode.antisamy)));
+		//courses
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.resources.i18n(), Cols.resources.ordinal(),
+				true, Cols.resources.name(), FlexiColumnModel.ALIGNMENT_LEFT, new BGResourcesCellRenderer(flc)));
+		//access
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.accessTypes.i18n(), Cols.accessTypes.ordinal(),
+				true, Cols.accessTypes.name(), FlexiColumnModel.ALIGNMENT_LEFT, new BGAccessControlledCellRenderer()));
+		//launch dates
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.firstTime.i18n(), Cols.firstTime.ordinal(),
+				true, Cols.firstTime.name(), FlexiColumnModel.ALIGNMENT_LEFT, new DateFlexiCellRenderer(getLocale())));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.lastTime.i18n(), Cols.lastTime.ordinal(),
+				true, Cols.lastTime.name(), FlexiColumnModel.ALIGNMENT_LEFT, new DateFlexiCellRenderer(getLocale())));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.lastUsage.i18n(), Cols.lastUsage.ordinal(),
+				true, Cols.lastUsage.name()));
+		//roles
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.role.i18n(), Cols.role.ordinal(),
+				true, Cols.role.name(), FlexiColumnModel.ALIGNMENT_LEFT, new BGRoleCellRenderer(getLocale())));
+		
+		//actions
+		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.allowLeave.i18n(), Cols.allowLeave.ordinal(), TABLE_ACTION_LEAVE,
+				new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("table.header.leave"), TABLE_ACTION_LEAVE), null)));
+		return columnsModel;
+	}
+}
diff --git a/src/main/java/org/olat/group/ui/main/BGResourcesCellRenderer.java b/src/main/java/org/olat/group/ui/main/BGResourcesCellRenderer.java
index 0853324c90c5e749e06fada47cf798bbb876d9bb..64b767b8b79685b9953c2d9a76638c2cb8af96e7 100644
--- a/src/main/java/org/olat/group/ui/main/BGResourcesCellRenderer.java
+++ b/src/main/java/org/olat/group/ui/main/BGResourcesCellRenderer.java
@@ -79,7 +79,7 @@ public class BGResourcesCellRenderer implements FlexiCellRenderer {
 							allResourcesLink = uifactory.addFormLink("repo_entry_" + counter.incrementAndGet(), "allresources", "...",
 								null, formLayout, Link.NONTRANSLATED);
 						}
-						allResourcesLink.setUserObject(item.getBusinessGroup());
+						allResourcesLink.setUserObject(item);
 						allResourcesLink.getComponent().getHTMLRendererSingleton()
 							.render(renderer, sb, allResourcesLink.getComponent(), ubu, translator, null, null);
 						break;
diff --git a/src/main/java/org/olat/group/ui/main/BGTableItem.java b/src/main/java/org/olat/group/ui/main/BGTableItem.java
index 5e86039413c3fbf16ac8e882084e88f7612175fc..be36b64ecbc9b3270af892abd5937fcc33f18821 100644
--- a/src/main/java/org/olat/group/ui/main/BGTableItem.java
+++ b/src/main/java/org/olat/group/ui/main/BGTableItem.java
@@ -19,17 +19,12 @@
  */
 package org.olat.group.ui.main;
 
-import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
 import org.olat.core.gui.components.form.flexible.elements.FormLink;
-import org.olat.group.BusinessGroup;
-import org.olat.group.BusinessGroupManagedFlag;
 import org.olat.group.BusinessGroupMembership;
-import org.olat.group.BusinessGroupShort;
-import org.olat.group.BusinessGroupView;
-import org.olat.group.model.BGRepositoryEntryRelation;
+import org.olat.group.model.BusinessGroupRow;
 import org.olat.repository.RepositoryEntryShort;
 import org.olat.resource.accesscontrol.model.PriceMethodBundle;
 
@@ -42,104 +37,80 @@ import org.olat.resource.accesscontrol.model.PriceMethodBundle;
  * Initial Date:  7 mars 2011 <br>
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class BGTableItem {
-	private final BusinessGroupMembership member;
-	private boolean marked;
-	private final FormLink markLink;
+public class BGTableItem extends BusinessGroupRow {
+	private BusinessGroupMembership member;
+	private FormLink markLink;
 	private FormLink allResourcesLink;
 	private FormLink accessLink;
 	
 	private final Boolean allowLeave;
 	private final Boolean allowDelete;
-	private final String businessGroupDescription;
-	private final Date businessGroupLastUsage;
 	
-	private final BGShort businessGroup;
-	private List<RepositoryEntryShort> relations;
-	private List<PriceMethodBundle> access;
+	private long numOfParticipants;
+	private long numOfPendings;
+	private long numOfOwners;
+	private long numWaiting;
 	
-	public BGTableItem(BusinessGroup businessGroup, boolean marked, BusinessGroupMembership member, Boolean allowLeave, Boolean allowDelete, List<PriceMethodBundle> access) {
-		this.businessGroup = new BGShort(businessGroup);
-		this.businessGroupDescription = businessGroup.getDescription();
-		this.businessGroupLastUsage = businessGroup.getLastUsage();
-		this.marked = marked;
-		this.markLink = null;
-		this.member = member;
-		this.allowLeave = allowLeave;
-		this.allowDelete = allowDelete;
-		this.access = access;
-	}
-	
-	public BGTableItem(BusinessGroupView businessGroup, boolean marked, BusinessGroupMembership member, Boolean allowLeave, Boolean allowDelete, List<PriceMethodBundle> access) {
-		this.businessGroup = new BGShort(businessGroup);
-		this.businessGroupDescription = businessGroup.getDescription();
-		this.businessGroupLastUsage = businessGroup.getLastUsage();
-		this.marked = marked;
-		this.markLink = null;
-		this.member = member;
-		this.allowLeave = allowLeave;
-		this.allowDelete = allowDelete;
-		this.access = access;
-	}
-	
-	public BGTableItem(BusinessGroupView businessGroup, FormLink markLink, boolean marked, BusinessGroupMembership member, Boolean allowLeave, Boolean allowDelete, List<PriceMethodBundle> access) {
-		this.businessGroup = new BGShort(businessGroup);
-		this.businessGroupDescription = businessGroup.getDescription();
-		this.businessGroupLastUsage = businessGroup.getLastUsage();
-		this.marked = marked;
+	public BGTableItem(BusinessGroupRow businessGroup, FormLink markLink, Boolean allowLeave, Boolean allowDelete) {
+		super(businessGroup);
 		this.markLink = markLink;
-		this.member = member;
+		if(markLink != null) {
+			markLink.setUserObject(this);
+		}
+		this.member = businessGroup.getMember();
+		setResources(businessGroup.getResources());
+		setBundles(businessGroup.getBundles());
 		this.allowLeave = allowLeave;
 		this.allowDelete = allowDelete;
-		this.access = access;
 	}
 
 	public Long getBusinessGroupKey() {
-		return businessGroup.getKey();
+		return getKey();
 	}
 	
 	public String getBusinessGroupExternalId() {
-		return businessGroup.getExternalId();
+		return getExternalId();
 	}
 	
 	public String getBusinessGroupName() {
-		return businessGroup.getName();
+		return getName();
 	}
+
 	
 	public long getNumOfParticipants() {
-		return businessGroup.getNumOfParticipants();
+		return numOfParticipants;
 	}
 	
 	public long getNumOfPendings() {
-		return businessGroup.getNumOfPendings();
+		return numOfPendings;
 	}
 	
 	public long getNumOfOwners() {
-		return businessGroup.getNumOfOwners();
+		return numOfOwners;
 	}
 	
 	public long getNumWaiting() {
-		return businessGroup.getNumWaiting();
+		return numWaiting;
 	}
-	
-	public Integer getMaxParticipants() {
-		return businessGroup.getMaxParticipants();
+
+	public void setNumWaiting(long numWaiting) {
+		this.numWaiting = numWaiting;
 	}
-	
-	public boolean isWaitingListEnabled() {
-		return businessGroup.isWaitingListEnabled();
+
+	public void setNumOfParticipants(long numOfParticipants) {
+		this.numOfParticipants = numOfParticipants;
 	}
-	
-	public boolean isAutoCloseRanksEnabled() {
-		return businessGroup.isAutoCloseRanksEnabled();
+
+	public void setNumOfPendings(long numOfPendings) {
+		this.numOfPendings = numOfPendings;
 	}
-	
-	public BusinessGroupManagedFlag[] getManagedFlags() {
-		return businessGroup.getManagedFlags();
+
+	public void setNumOfOwners(long numOfOwners) {
+		this.numOfOwners = numOfOwners;
 	}
-	
+
 	public boolean isFull() {
-		Integer maxParticipants = businessGroup.getMaxParticipants();
+		Integer maxParticipants = getMaxParticipants();
 		if(maxParticipants == null || maxParticipants.intValue() < 0) {
 			return false;
 		}
@@ -153,11 +124,11 @@ public class BGTableItem {
 	}
 
 	public String getBusinessGroupDescription() {
-		return businessGroupDescription;
+		return getDescription();
 	}
 
 	public Date getBusinessGroupLastUsage() {
-		return businessGroupLastUsage;
+		return getLastUsage();
 	}
 
 	public FormLink getMarkLink() {
@@ -171,6 +142,10 @@ public class BGTableItem {
 	public void setAllResourcesLink(FormLink allResourcesLink) {
 		this.allResourcesLink = allResourcesLink;
 	}
+	
+	public List<RepositoryEntryShort> getRelations() {
+		return super.getResources();
+	}
 
 	public FormLink getAccessLink() {
 		return accessLink;
@@ -180,24 +155,16 @@ public class BGTableItem {
 		this.accessLink = accessLink;
 	}
 
-	public boolean isMarked() {
-		return marked;
-	}
-	
-	public void setMarked(boolean mark) {
-		this.marked = mark;
-	}
-
 	public BusinessGroupMembership getMembership() {
 		return member;
 	}
 	
 	public boolean isAccessControl() {
-		return access != null;
+		return getBundles() != null && !getBundles().isEmpty();
 	}
 
 	public List<PriceMethodBundle> getAccessTypes() {
-		return access;
+		return getBundles();
 	}
 
 	public Boolean getAllowLeave() {
@@ -208,27 +175,9 @@ public class BGTableItem {
 		return allowDelete;
 	}
 
-	public BusinessGroupShort getBusinessGroup() {
-		return businessGroup;
-	}
-	
-	public List<RepositoryEntryShort> getRelations() {
-		return relations;
-	}
-	
-	public void addRelation(BGRepositoryEntryRelation resource) {
-		if(resource == null) return;
-		if(relations == null) {
-			relations = new ArrayList<RepositoryEntryShort>(3);
-		}
-		if(relations.size() < 3) {
-			relations.add(new REShort(resource));
-		}
-	}
-
 	@Override
 	public int hashCode() {
-		return businessGroup.getKey().hashCode();
+		return getKey().hashCode();
 	}
 	
 	@Override
@@ -238,166 +187,8 @@ public class BGTableItem {
 		}
 		if(obj instanceof BGTableItem) {
 			BGTableItem item = (BGTableItem)obj;
-			return businessGroup != null && businessGroup.equals(item.businessGroup);
+			return getKey() != null && getKey().equals(item.getKey());
 		}
 		return false;
 	}
-	
-	private static class BGShort implements BusinessGroupShort {
-		private final Long key;
-		private final String name;
-		private final String externalId;
-		private final Integer maxParticipants;
-		private long numWaiting;
-		private long numOfOwners;
-		private long numOfParticipants;
-		private long numOfPendings;
-		private final boolean waitingListEnabled;
-		private final boolean autoCloseRanksEnabled;
-		private final BusinessGroupManagedFlag[] managedflags;
-		
-		public BGShort(BusinessGroup group) {
-			key = group.getKey();
-			name = group.getName();
-			maxParticipants = group.getMaxParticipants();
-			waitingListEnabled = group.getWaitingListEnabled() == null ? false : group.getWaitingListEnabled().booleanValue();
-			autoCloseRanksEnabled = group.getAutoCloseRanksEnabled() == null ? false : group.getAutoCloseRanksEnabled().booleanValue();
-			managedflags = group.getManagedFlags();
-			externalId = group.getExternalId();
-		}
-		
-		public BGShort(BusinessGroupView group) {
-			key = group.getKey();
-			name = group.getName();
-			maxParticipants = group.getMaxParticipants();
-			numWaiting = group.getNumWaiting();
-			numOfOwners = group.getNumOfOwners();
-			numOfParticipants = group.getNumOfParticipants();
-			numOfPendings = group.getNumOfPendings();
-			waitingListEnabled = group.getWaitingListEnabled() == null ? false : group.getWaitingListEnabled().booleanValue();
-			autoCloseRanksEnabled = group.getAutoCloseRanksEnabled() == null ? false : group.getAutoCloseRanksEnabled().booleanValue();
-			managedflags = group.getManagedFlags();
-			externalId = group.getExternalId();
-		}
-
-		@Override
-		public String getResourceableTypeName() {
-			return "BusinessGroup";
-		}
-
-		@Override
-		public Long getResourceableId() {
-			return key;
-		}
-
-		@Override
-		public Long getKey() {
-			return key;
-		}
-
-		public String getExternalId() {
-			return externalId;
-		}
-
-		@Override
-		public String getName() {
-			return name;
-		}
-
-		public Integer getMaxParticipants() {
-			return maxParticipants;
-		}
-
-		public long getNumOfParticipants() {
-			return numOfParticipants;
-		}
-		
-		public long getNumOfPendings() {
-			return numOfPendings;
-		}
-		
-		public long getNumOfOwners() {
-			return numOfOwners;
-		}
-		
-		public long getNumWaiting() {
-			return numWaiting;
-		}
-		
-		public boolean isWaitingListEnabled() {
-			return waitingListEnabled;
-		}
-
-		public boolean isAutoCloseRanksEnabled() {
-			return autoCloseRanksEnabled;
-		}
-
-		@Override
-		public BusinessGroupManagedFlag[] getManagedFlags() {
-			return managedflags;
-		}
-
-		@Override
-		public int hashCode() {
-			return key.hashCode();
-		}
-
-		@Override
-		public boolean equals(Object obj) {
-			if(this == obj) {
-				return true;
-			}
-			if(obj instanceof BGShort) {
-				BGShort sh = (BGShort)obj;
-				return key != null && key.equals(sh.key);
-			}
-			return false;
-		}
-	}
-	
-	private static class REShort implements RepositoryEntryShort {
-		private final Long key;
-		private final String displayname;
-		public REShort(BGRepositoryEntryRelation rel) {
-			this.key = rel.getRepositoryEntryKey();
-			this.displayname = rel.getRepositoryEntryDisplayName();
-		}
-
-		@Override
-		public Long getKey() {
-			return key;
-		}
-
-		@Override
-		public String getDisplayname() {
-			return displayname;
-		}
-
-		@Override
-		public String getResourceType() {
-			return "CourseModule";
-		}
-
-		@Override
-		public int getStatusCode() {
-			return 0;
-		}
-
-		@Override
-		public int hashCode() {
-			return key.hashCode();
-		}
-
-		@Override
-		public boolean equals(Object obj) {
-			if(this == obj) {
-				return true;
-			}
-			if(obj instanceof REShort) {
-				REShort re = (REShort)obj;
-				return key != null && key.equals(re.key);
-			}
-			return false;
-		}
-	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/ui/main/BusinessGroupFlexiTableModel.java b/src/main/java/org/olat/group/ui/main/BusinessGroupFlexiTableModel.java
index 9d2a778c4124274a0d8faa437f45e1a3119d9df3..f87a15c9249f6b3971d909099a8f5b58ef21b13e 100644
--- a/src/main/java/org/olat/group/ui/main/BusinessGroupFlexiTableModel.java
+++ b/src/main/java/org/olat/group/ui/main/BusinessGroupFlexiTableModel.java
@@ -19,35 +19,19 @@
  */
 package org.olat.group.ui.main;
 
-import static org.olat.group.ui.main.AbstractBusinessGroupListController.TABLE_ACTION_DELETE;
-import static org.olat.group.ui.main.AbstractBusinessGroupListController.TABLE_ACTION_LAUNCH;
-import static org.olat.group.ui.main.AbstractBusinessGroupListController.TABLE_ACTION_LEAVE;
-import static org.olat.group.ui.main.AbstractBusinessGroupListController.TABLE_ACTION_SELECT;
-
 import java.util.ArrayList;
 import java.util.List;
 
 import org.olat.core.commons.persistence.SortKey;
 import org.olat.core.gui.UserRequest;
-import org.olat.core.gui.components.EscapeMode;
-import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.BooleanCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.DateFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.util.Formatter;
 import org.olat.core.util.filter.FilterFactory;
 import org.olat.group.BusinessGroupManagedFlag;
 import org.olat.group.BusinessGroupMembership;
-import org.olat.group.BusinessGroupModule;
 
 /**
  * 
@@ -67,87 +51,6 @@ public class BusinessGroupFlexiTableModel extends DefaultFlexiTableDataModel<BGT
 		super(new ArrayList<BGTableItem>(), columnModel);
 		this.trans = trans;
 	}
-	
-	public static FlexiTableColumnModel getStandardColumnModel(boolean delete, FormLayoutContainer flc, BusinessGroupModule groupModule, Translator translator) {
-		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
-		//mark
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.mark.i18n(), Cols.mark.ordinal(),
-				true, Cols.mark.name()));
-		//group name
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.name.i18n(), Cols.name.ordinal(), TABLE_ACTION_LAUNCH,
-				true, Cols.name.name(), new StaticFlexiCellRenderer(TABLE_ACTION_LAUNCH, new BusinessGroupNameCellRenderer())));
-		//id and reference
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.key.i18n(), Cols.key.ordinal(), true, Cols.key.name()));
-		if(groupModule.isManagedBusinessGroups()) {
-			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.externalId.i18n(), Cols.externalId.ordinal(),
-					true, Cols.externalId.name()));
-		}
-		//description
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.description.i18n(), Cols.description.ordinal(),
-				false, null, FlexiColumnModel.ALIGNMENT_LEFT, new TextFlexiCellRenderer(EscapeMode.antisamy)));
-		//courses
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.resources.i18n(), Cols.resources.ordinal(),
-				true, Cols.resources.name(), FlexiColumnModel.ALIGNMENT_LEFT, new BGResourcesCellRenderer(flc)));
-		//access
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.accessTypes.i18n(), Cols.accessTypes.ordinal(),
-				true, Cols.accessTypes.name(), FlexiColumnModel.ALIGNMENT_LEFT, new BGAccessControlledCellRenderer()));
-		//launch dates
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.firstTime.i18n(), Cols.firstTime.ordinal(),
-				true, Cols.firstTime.name(), FlexiColumnModel.ALIGNMENT_LEFT, new DateFlexiCellRenderer(translator.getLocale())));
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.lastTime.i18n(), Cols.lastTime.ordinal(),
-				true, Cols.lastTime.name(), FlexiColumnModel.ALIGNMENT_LEFT, new DateFlexiCellRenderer(translator.getLocale())));
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.lastUsage.i18n(), Cols.lastUsage.ordinal(),
-				true, Cols.lastUsage.name()));
-		//roles
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.role.i18n(), Cols.role.ordinal(),
-				true, Cols.role.name(), FlexiColumnModel.ALIGNMENT_LEFT, new BGRoleCellRenderer(translator.getLocale())));
-		
-		//actions
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.allowLeave.i18n(), Cols.allowLeave.ordinal(), TABLE_ACTION_LEAVE,
-				new BooleanCellRenderer(new StaticFlexiCellRenderer(translator.translate("table.header.leave"), TABLE_ACTION_LEAVE), null)));
-		if(delete) {
-			columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.allowDelete.i18n(), Cols.allowDelete.ordinal(), TABLE_ACTION_DELETE,
-				new BooleanCellRenderer(new StaticFlexiCellRenderer(translator.translate("table.header.delete"), TABLE_ACTION_DELETE), null)));
-		}
-		
-		return columnsModel;
-	}
-	
-	public static FlexiTableColumnModel getSelectColumnModel(FormLayoutContainer flc, BusinessGroupModule groupModule, Translator translator) {
-		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
-		//mark
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.mark.i18n(), Cols.mark.ordinal(),
-				true, Cols.mark.name()));
-		//group name
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.name.i18n(), Cols.name.ordinal(), TABLE_ACTION_LAUNCH,
-				true, Cols.name.name(), new StaticFlexiCellRenderer(TABLE_ACTION_LAUNCH, new BusinessGroupNameCellRenderer())));
-		//id and reference
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.key.i18n(), Cols.key.ordinal(), true, Cols.key.name()));
-		if(groupModule.isManagedBusinessGroups()) {
-			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.externalId.i18n(), Cols.externalId.ordinal(),
-					true, Cols.externalId.name()));
-		}
-		//description
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.description.i18n(), Cols.description.ordinal(),
-				false, null, FlexiColumnModel.ALIGNMENT_LEFT, new TextFlexiCellRenderer(EscapeMode.antisamy)));
-		//courses
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.resources.i18n(), Cols.resources.ordinal(),
-				true, Cols.resources.name(), FlexiColumnModel.ALIGNMENT_LEFT, new BGResourcesCellRenderer(flc)));
-
-		//stats
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.tutorsCount.i18n(), Cols.tutorsCount.ordinal(),
-				true, Cols.tutorsCount.name()));
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.participantsCount.i18n(), Cols.participantsCount.ordinal(),
-				true, Cols.participantsCount.name()));
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.freePlaces.i18n(), Cols.freePlaces.ordinal(),
-				true, Cols.freePlaces.name(), FlexiColumnModel.ALIGNMENT_LEFT, new TextFlexiCellRenderer(EscapeMode.none)));
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.waitingListCount.i18n(), Cols.waitingListCount.ordinal(),
-				true, Cols.waitingListCount.name()));
-		
-		//actions
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("select", translator.translate("select"), TABLE_ACTION_SELECT));
-		return columnsModel;
-	}
 
 	/**
 	 * @see org.olat.core.gui.components.table.TableDataModel#getValueAt(int, int)
@@ -162,7 +65,7 @@ public class BusinessGroupFlexiTableModel extends DefaultFlexiTableDataModel<BGT
 	public Object getValueAt(BGTableItem wrapped, int col) {
 		switch (Cols.values()[col]) {
 			case name:
-				return wrapped.getBusinessGroup();
+				return wrapped;
 			case description:
 				String description = wrapped.getBusinessGroupDescription();
 				description = FilterFactory.getHtmlTagsFilter().filter(description);
@@ -193,12 +96,6 @@ public class BusinessGroupFlexiTableModel extends DefaultFlexiTableDataModel<BGT
 			case accessControl:
 				return new Boolean(wrapped.isAccessControl());
 			case accessControlLaunch:
-				/*if(wrapped.isAccessControl()) {
-					if(wrapped.getMembership() != null) {
-						return trans.translate("select");
-					}
-					return trans.translate("table.access");
-				}*/
 				return wrapped.getAccessLink();
 			case accessTypes:
 				return wrapped.getAccessTypes();
diff --git a/src/main/java/org/olat/group/ui/main/BusinessGroupListController.java b/src/main/java/org/olat/group/ui/main/BusinessGroupListController.java
index 64097229cf8fadc7859fea25834c3b7f517a68ea..168ba45bd4ed528e36d2676f6367f88234ef72b5 100644
--- a/src/main/java/org/olat/group/ui/main/BusinessGroupListController.java
+++ b/src/main/java/org/olat/group/ui/main/BusinessGroupListController.java
@@ -19,17 +19,29 @@
  */
 package org.olat.group.ui.main;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import org.olat.core.commons.services.mark.Mark;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.BooleanCellRenderer;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
+import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.WindowControl;
-import org.olat.group.model.SearchBusinessGroupParams;
+import org.olat.group.BusinessGroupMembership;
+import org.olat.group.model.BusinessGroupQueryParams;
+import org.olat.group.model.BusinessGroupRow;
+import org.olat.group.ui.main.BusinessGroupFlexiTableModel.Cols;
 
 /**
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class BusinessGroupListController extends AbstractBusinessGroupListController {
+public class BusinessGroupListController extends AbstractStandardBusinessGroupListController {
 	
 	public BusinessGroupListController(UserRequest ureq, WindowControl wControl, String prefsKey) {
 		super(ureq, wControl, "group_list", prefsKey);
@@ -38,35 +50,53 @@ public class BusinessGroupListController extends AbstractBusinessGroupListContro
 	@Override
 	protected void initButtons(FormItemContainer formLayout, UserRequest ureq) {
 		initButtons(formLayout, ureq, true, false, true);
-		
 		searchCtrl.enablePublic(false);
 	}
 	
 	@Override
 	protected FlexiTableColumnModel initColumnModel() {
-		return BusinessGroupFlexiTableModel.getStandardColumnModel(true, flc, groupModule, getTranslator());
+		FlexiTableColumnModel columnsModel = super.initColumnModel();
+		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.allowDelete.i18n(), Cols.allowDelete.ordinal(), TABLE_ACTION_DELETE,
+			new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("table.header.delete"), TABLE_ACTION_DELETE), null)));
+		return columnsModel;
 	}
 
 	@Override
-	protected SearchBusinessGroupParams getSearchParams(SearchEvent event) {
-		SearchBusinessGroupParams params = event.convertToSearchBusinessGroupParams(getIdentity());
+	protected BusinessGroupQueryParams getSearchParams(SearchEvent event) {
+		BusinessGroupQueryParams params = event.convertToBusinessGroupQueriesParams();
 		//security
 		if(!params.isAttendee() && !params.isOwner() && !params.isWaiting()) {
 			params.setOwner(true);
 			params.setAttendee(true);
 			params.setWaiting(true);
 		}
-		params.setIdentity(getIdentity());
 		return params;
 	}
 
 	@Override
-	protected SearchBusinessGroupParams getDefaultSearchParams() {
-		SearchBusinessGroupParams params = new SearchBusinessGroupParams();
+	protected BusinessGroupQueryParams getDefaultSearchParams() {
+		BusinessGroupQueryParams params = new BusinessGroupQueryParams();
 		params.setAttendee(true);
 		params.setOwner(true);
 		params.setWaiting(true);
-		params.setIdentity(getIdentity());
 		return params;
 	}
+	
+	@Override
+	protected List<BGTableItem> searchTableItems(BusinessGroupQueryParams params) {
+		List<BusinessGroupRow> rows = businessGroupService.findBusinessGroupsWithMemberships(params, getIdentity());
+		List<BGTableItem> items = new ArrayList<>(rows.size());
+		for(BusinessGroupRow row:rows) {
+			BusinessGroupMembership membership = row.getMember();
+			Boolean allowLeave =  membership != null;
+			Boolean allowDelete = isAdmin() ? Boolean.TRUE : (membership == null ? null : new Boolean(membership.isOwner()));
+			
+			FormLink markLink = uifactory.addFormLink("mark_" + row.getKey(), "mark", "", null, null, Link.NONTRANSLATED);
+			markLink.setIconLeftCSS(row.isMarked() ? Mark.MARK_CSS_LARGE : Mark.MARK_ADD_CSS_LARGE);
+
+			BGTableItem item = new BGTableItem(row, markLink, allowLeave, allowDelete);
+			items.add(item);
+		}
+		return items;
+	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/ui/main/BusinessGroupListFlexiTableModel.java b/src/main/java/org/olat/group/ui/main/BusinessGroupListFlexiTableModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..aed5ea82cf61c150a47b8177dc27bbde0f370611
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/main/BusinessGroupListFlexiTableModel.java
@@ -0,0 +1,42 @@
+/**
+ * <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.group.ui.main;
+
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
+
+/**
+ * 
+ * Initial date: 29.10.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class BusinessGroupListFlexiTableModel extends AbstractBusinessGroupFlexiTableModel {
+	
+	public BusinessGroupListFlexiTableModel(FlexiTableColumnModel columnModel) {
+		super(columnModel);
+	}
+
+	@Override
+	public DefaultFlexiTableDataModel<BGTableItem> createCopyWithEmptyList() {
+		return new BusinessGroupListFlexiTableModel(getTableColumnModel());
+	}
+
+}
diff --git a/src/main/java/org/olat/group/ui/main/BusinessGroupViewFilter.java b/src/main/java/org/olat/group/ui/main/BusinessGroupViewFilter.java
index 1213ec37a917ecc770cc28823e803b25ff449444..5dc32dd5a232ea244129c04b6dc3ef31756d4eed 100644
--- a/src/main/java/org/olat/group/ui/main/BusinessGroupViewFilter.java
+++ b/src/main/java/org/olat/group/ui/main/BusinessGroupViewFilter.java
@@ -19,7 +19,7 @@
  */
 package org.olat.group.ui.main;
 
-import org.olat.group.BusinessGroupView;
+import org.olat.group.model.BusinessGroupRow;
 
 /**
  * 
@@ -29,6 +29,6 @@ import org.olat.group.BusinessGroupView;
  */
 public interface BusinessGroupViewFilter {
 	
-	public boolean accept(BusinessGroupView view);
+	public boolean accept(BusinessGroupRow row);
 
 }
diff --git a/src/main/java/org/olat/group/ui/main/CourseRoleCellRenderer.java b/src/main/java/org/olat/group/ui/main/CourseRoleCellRenderer.java
index d94a565272b869fee9d61d15c1e081b5c281a613..b5ac5f0b0a756c9470c2badf941f413c04337b3f 100644
--- a/src/main/java/org/olat/group/ui/main/CourseRoleCellRenderer.java
+++ b/src/main/java/org/olat/group/ui/main/CourseRoleCellRenderer.java
@@ -44,7 +44,7 @@ public class CourseRoleCellRenderer implements CustomCellRenderer, FlexiCellRend
 	
 	@Override
 	public void render(Renderer renderer, StringOutput target, Object cellValue, int row,
-			FlexiTableComponent source, URLBuilder ubu, Translator translator) {
+			FlexiTableComponent source, URLBuilder ubu, Translator trans) {
 		if (cellValue instanceof CourseMembership) {
 			render(target, (CourseMembership) cellValue);
 		}
diff --git a/src/main/java/org/olat/group/ui/main/EditMembershipController.java b/src/main/java/org/olat/group/ui/main/EditMembershipController.java
index 29c5b34b4aba6b3c35d289a3c31698f7526a544d..52b2859e0c637bda7812fa66ff75491c8ee2df94 100644
--- a/src/main/java/org/olat/group/ui/main/EditMembershipController.java
+++ b/src/main/java/org/olat/group/ui/main/EditMembershipController.java
@@ -27,7 +27,6 @@ import java.util.List;
 import java.util.UUID;
 
 import org.olat.basesecurity.GroupRoles;
-import org.olat.core.commons.persistence.PersistenceHelper;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.EscapeMode;
 import org.olat.core.gui.components.form.flexible.FormItem;
@@ -58,12 +57,12 @@ import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupManagedFlag;
 import org.olat.group.BusinessGroupMembership;
 import org.olat.group.BusinessGroupService;
-import org.olat.group.BusinessGroupView;
 import org.olat.group.model.BusinessGroupMembershipChange;
-import org.olat.group.model.SearchBusinessGroupParams;
+import org.olat.group.model.BusinessGroupQueryParams;
+import org.olat.group.model.BusinessGroupRow;
+import org.olat.group.model.StatisticsBusinessGroupRow;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryEntryManagedFlag;
-import org.olat.repository.RepositoryEntryRef;
 import org.olat.repository.RepositoryManager;
 import org.olat.repository.model.RepositoryEntryMembership;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -161,15 +160,15 @@ public class EditMembershipController extends FormBasicController {
 	}
 	
 	private void loadModel(Identity memberToLoad) {
-		RepositoryEntryRef resource = null;
-		SearchBusinessGroupParams params = new SearchBusinessGroupParams();
+		BusinessGroupQueryParams params = new BusinessGroupQueryParams();
 		if(repoEntry == null) {
-			params.setGroupKeys(Collections.singletonList(businessGroup.getKey()));
+			params.setBusinessGroupKey(businessGroup.getKey());
 		} else {
-			resource = repoEntry;
+			params.setRepositoryEntry(repoEntry);
 		}
-		List<BusinessGroupView> groups = businessGroupService.findBusinessGroupViews(params, resource, 0, -1);
-	
+
+		List<StatisticsBusinessGroupRow> groups = businessGroupService.findBusinessGroupsStatistics(params);
+
 		boolean defaultMembership = false;
 		if(memberToLoad == null) {
 			if(repoEntry != null && groups.isEmpty()) {
@@ -185,17 +184,20 @@ public class EditMembershipController extends FormBasicController {
 			}
 		}
 
-		List<Long> businessGroupKeys = PersistenceHelper.toKeys(groups);
+		List<Long> businessGroupKeys = new ArrayList<>(groups.size());
+		groups.forEach(group -> businessGroupKeys.add(group.getKey()));
+		
 		groupMemberships = memberToLoad == null ?
 				Collections.<BusinessGroupMembership>emptyList() : businessGroupService.getBusinessGroupMembership(businessGroupKeys, memberToLoad);
+		
 		List<MemberOption> options = new ArrayList<MemberOption>();
-		for(BusinessGroupView group:groups) {
+		for(StatisticsBusinessGroupRow group:groups) {
 			boolean managed = BusinessGroupManagedFlag.isManaged(group.getManagedFlags(), BusinessGroupManagedFlag.membersmanagement);
 			MemberOption option = new MemberOption(group);
 			BGPermission bgPermission = PermissionHelper.getPermission(group.getKey(), memberToLoad, groupMemberships);
 			option.setTutor(createSelection(bgPermission.isTutor(), !managed, GroupRoles.coach.name()));
 			option.setParticipant(createSelection(bgPermission.isParticipant() || defaultMembership, !managed, GroupRoles.participant.name()));
-			boolean waitingListEnable = !managed && group.getWaitingListEnabled() != null && group.getWaitingListEnabled().booleanValue();
+			boolean waitingListEnable = !managed && group.isWaitingListEnabled();
 			option.setWaiting(createSelection(bgPermission.isWaitingList(), waitingListEnable, GroupRoles.waiting.name()));
 			options.add(option);
 		}
@@ -350,16 +352,16 @@ public class EditMembershipController extends FormBasicController {
 	}
 
 	private static class MemberOption {
-		private final BusinessGroupView group;
+		private final StatisticsBusinessGroupRow group;
 		private MultipleSelectionElement tutor;
 		private MultipleSelectionElement participant;
 		private MultipleSelectionElement waiting;
 		
-		public MemberOption(BusinessGroupView group) {
+		public MemberOption(StatisticsBusinessGroupRow group) {
 			this.group = group;
 		}
 		
-		public BusinessGroupView getGroup() {
+		public BusinessGroupRow getGroup() {
 			return group;
 		}
 		
@@ -372,7 +374,7 @@ public class EditMembershipController extends FormBasicController {
 		}
 
 		public long getTutorCount() {
-			return group.getNumOfOwners();
+			return group.getNumOfCoaches();
 		}
 		
 		public long getParticipantCount() {
@@ -380,7 +382,7 @@ public class EditMembershipController extends FormBasicController {
 		}
 		
 		public long getNumOfPendings() {
-			return group.getNumOfPendings();
+			return group.getNumPending();
 		}
 		
 		public Integer getMaxParticipants() {
diff --git a/src/main/java/org/olat/group/ui/main/FavoritBusinessGroupListController.java b/src/main/java/org/olat/group/ui/main/FavoritBusinessGroupListController.java
index cc61890433281d2d4c156c5a72e419559873ded0..42150fbb4bf9d18db4092c609ae0ec26deade656 100644
--- a/src/main/java/org/olat/group/ui/main/FavoritBusinessGroupListController.java
+++ b/src/main/java/org/olat/group/ui/main/FavoritBusinessGroupListController.java
@@ -19,17 +19,24 @@
  */
 package org.olat.group.ui.main;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import org.olat.core.commons.services.mark.Mark;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
+import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.WindowControl;
-import org.olat.group.model.SearchBusinessGroupParams;
+import org.olat.group.BusinessGroupMembership;
+import org.olat.group.model.BusinessGroupQueryParams;
+import org.olat.group.model.BusinessGroupRow;
 
 /**
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class FavoritBusinessGroupListController extends AbstractBusinessGroupListController {
+public class FavoritBusinessGroupListController extends AbstractStandardBusinessGroupListController {
 
 	public FavoritBusinessGroupListController(UserRequest ureq, WindowControl wControl, String prefsKey) {
 		super(ureq, wControl, "group_list", prefsKey);
@@ -39,34 +46,45 @@ public class FavoritBusinessGroupListController extends AbstractBusinessGroupLis
 	protected void initButtons(FormItemContainer formLayout, UserRequest ureq) {
 		initButtons(formLayout, ureq, true, false, false);
 	}
-
-	@Override
-	protected FlexiTableColumnModel initColumnModel() {
-		return BusinessGroupFlexiTableModel.getStandardColumnModel(false, flc, groupModule, getTranslator());
-	}
 	
 	@Override
-	protected SearchBusinessGroupParams getSearchParams(SearchEvent event) {
-		SearchBusinessGroupParams params = event.convertToSearchBusinessGroupParams(getIdentity());
+	protected BusinessGroupQueryParams getSearchParams(SearchEvent event) {
+		BusinessGroupQueryParams params = event.convertToBusinessGroupQueriesParams();
 		//security
 		if(!params.isAttendee() && !params.isOwner() && !params.isWaiting()) {
 			params.setOwner(true);
 			params.setAttendee(true);
 			params.setWaiting(true);
 		}
-		params.setMarked(Boolean.TRUE);
-		params.setIdentity(getIdentity());
+		params.setMarked(true);
 		return params;
 	}
 	
 	@Override
-	protected SearchBusinessGroupParams getDefaultSearchParams() {
-		SearchBusinessGroupParams params = new SearchBusinessGroupParams();
-		params.setMarked(Boolean.TRUE);
+	protected BusinessGroupQueryParams getDefaultSearchParams() {
+		BusinessGroupQueryParams params = new BusinessGroupQueryParams();
+		params.setMarked(true);
 		params.setAttendee(true);
 		params.setOwner(true);
 		params.setWaiting(true);
-		params.setIdentity(getIdentity());
 		return params;
 	}
+
+	@Override
+	protected List<BGTableItem> searchTableItems(BusinessGroupQueryParams params) {
+		List<BusinessGroupRow> rows = businessGroupService.findBusinessGroupsWithMemberships(params, getIdentity());
+		List<BGTableItem> items = new ArrayList<>(rows.size());
+		for(BusinessGroupRow row:rows) {
+			BusinessGroupMembership membership = row.getMember();
+			Boolean allowLeave =  membership != null;
+			Boolean allowDelete = isAdmin() ? Boolean.TRUE : (membership == null ? null : new Boolean(membership.isOwner()));
+			
+			FormLink markLink = uifactory.addFormLink("mark_" + row.getKey(), "mark", "", null, null, Link.NONTRANSLATED);
+			markLink.setIconLeftCSS(row.isMarked() ? Mark.MARK_CSS_LARGE : Mark.MARK_ADD_CSS_LARGE);
+			
+			BGTableItem item = new BGTableItem(row, markLink, allowLeave, allowDelete);
+			items.add(item);
+		}
+		return items;
+	}
 }
diff --git a/src/main/java/org/olat/group/ui/main/OpenBusinessGroupListController.java b/src/main/java/org/olat/group/ui/main/OpenBusinessGroupListController.java
index 0bc11b54d49f58b4d37cc498b8d7f33ab442491a..d2969f56361db5500c0c2c22f7497ce0c632c112 100644
--- a/src/main/java/org/olat/group/ui/main/OpenBusinessGroupListController.java
+++ b/src/main/java/org/olat/group/ui/main/OpenBusinessGroupListController.java
@@ -19,10 +19,14 @@
  */
 package org.olat.group.ui.main;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.olat.NewControllerFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.EscapeMode;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
@@ -30,9 +34,12 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
+import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.group.BusinessGroup;
-import org.olat.group.model.SearchBusinessGroupParams;
+import org.olat.group.BusinessGroupMembership;
+import org.olat.group.model.BusinessGroupQueryParams;
+import org.olat.group.model.OpenBusinessGroupRow;
 import org.olat.group.ui.main.BusinessGroupFlexiTableModel.Cols;
 
 /**
@@ -87,18 +94,75 @@ public class OpenBusinessGroupListController extends AbstractBusinessGroupListCo
 			NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl());
 		}
 	}
-	
+
 	@Override
-	protected SearchBusinessGroupParams getSearchParams(SearchEvent event) {
-		SearchBusinessGroupParams params = event.convertToSearchBusinessGroupParams(getIdentity());
+	protected BusinessGroupQueryParams getSearchParams(SearchEvent event) {
+		BusinessGroupQueryParams params = event.convertToBusinessGroupQueriesParams();
 		params.setPublicGroups(Boolean.TRUE);
 		return params;
 	}
 
 	@Override
-	protected SearchBusinessGroupParams getDefaultSearchParams() {
-		SearchBusinessGroupParams params = new SearchBusinessGroupParams();
+	protected BusinessGroupQueryParams getDefaultSearchParams() {
+		BusinessGroupQueryParams params = new BusinessGroupQueryParams();
 		params.setPublicGroups(Boolean.TRUE);
 		return params;
 	}
+
+	@Override
+	protected List<BGTableItem> searchTableItems(BusinessGroupQueryParams params) {
+		List<OpenBusinessGroupRow> rows = businessGroupService.findPublishedBusinessGroups(params, getIdentity());
+		List<BGTableItem> items = new ArrayList<>(rows.size());
+		for(OpenBusinessGroupRow row:rows) {
+			BusinessGroupMembership membership = row.getMember();
+			Boolean allowLeave =  membership != null;
+			BGTableItem item = new BGTableItem(row, null, allowLeave, Boolean.FALSE);
+			addAccessLink(item);
+			items.add(item);
+		}
+		return items;
+	}
+	
+	protected void addAccessLink(BGTableItem item) {
+		String action;
+		BusinessGroupMembership membership = item.getMembership();
+		if(membership != null && membership.isOwner()) {
+			return;
+		} else if(membership != null && (membership.isParticipant() || membership.isWaiting())) {
+			action = TABLE_ACTION_LEAVE;
+		} else if(item.isFull() && !item.isWaitingListEnabled()) {
+			action = null;
+		} else {
+			action = TABLE_ACTION_ACCESS;
+		}
+		
+		String i18nKey;
+		if (membership != null && membership.isParticipant()) {
+			i18nKey = "table.header.leave";
+		} else if (membership != null && membership.isWaiting()) {
+			i18nKey = "table.header.leave.waiting";
+		} else if(item.isFull()) {
+			if(item.isWaitingListEnabled()) {
+				i18nKey = "table.access.waitingList";
+			} else {
+				i18nKey = "table.header.group.full";
+			}
+		} else if(item.isWaitingListEnabled()) {
+			if(item.isFull()) {
+				i18nKey = "table.access.waitingList";
+			}	else {
+				i18nKey = "table.access";
+			}
+		} else {
+			i18nKey = "table.access";
+		}
+		
+		FormLink accessLink = uifactory.addFormLink("open_" + item.getBusinessGroupKey(), action, i18nKey,
+				null, null, Link.LINK);
+		if(action == null) {
+			accessLink.setEnabled(false);
+		}
+		accessLink.setUserObject(item);
+		item.setAccessLink(accessLink);
+	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/ui/main/SearchBusinessGroupListController.java b/src/main/java/org/olat/group/ui/main/SearchBusinessGroupListController.java
index b82ad7cfdb42219796b51a4a841805c9f1be68f0..773e07c207b9561d8e7f75b0979c8816aaeace4a 100644
--- a/src/main/java/org/olat/group/ui/main/SearchBusinessGroupListController.java
+++ b/src/main/java/org/olat/group/ui/main/SearchBusinessGroupListController.java
@@ -19,18 +19,30 @@
  */
 package org.olat.group.ui.main;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import org.olat.core.commons.services.mark.Mark;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.BooleanCellRenderer;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
+import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.group.BusinessGroup;
-import org.olat.group.model.SearchBusinessGroupParams;
+import org.olat.group.BusinessGroupMembership;
+import org.olat.group.model.BusinessGroupQueryParams;
+import org.olat.group.model.BusinessGroupRow;
+import org.olat.group.ui.main.BusinessGroupFlexiTableModel.Cols;
 
 /**
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class SearchBusinessGroupListController extends AbstractBusinessGroupListController {
+public class SearchBusinessGroupListController extends AbstractStandardBusinessGroupListController {
 	
 	public SearchBusinessGroupListController(UserRequest ureq, WindowControl wControl, String prefsKey) {
 		super(ureq, wControl, "group_list", true, true, prefsKey, null);
@@ -45,15 +57,18 @@ public class SearchBusinessGroupListController extends AbstractBusinessGroupList
 			searchCtrl.enableId(true);
 		}
 	}
-	
+
 	@Override
 	protected FlexiTableColumnModel initColumnModel() {
-		return BusinessGroupFlexiTableModel.getStandardColumnModel(true, flc, groupModule, getTranslator());
+		FlexiTableColumnModel columnsModel = super.initColumnModel();
+		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.allowDelete.i18n(), Cols.allowDelete.ordinal(), TABLE_ACTION_DELETE,
+			new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("table.header.delete"), TABLE_ACTION_DELETE), null)));
+		return columnsModel;
 	}
 
 	@Override
-	protected SearchBusinessGroupParams getSearchParams(SearchEvent event) {
-		SearchBusinessGroupParams params = event.convertToSearchBusinessGroupParams(getIdentity());
+	protected BusinessGroupQueryParams getSearchParams(SearchEvent event) {
+		BusinessGroupQueryParams params = event.convertToBusinessGroupQueriesParams();
 		//security
 		if(!isAdmin() && !params.isAttendee() && !params.isOwner() && !params.isWaiting()
 				&& (params.getPublicGroups() == null || !params.getPublicGroups().booleanValue())) {
@@ -65,15 +80,14 @@ public class SearchBusinessGroupListController extends AbstractBusinessGroupList
 	}
 
 	@Override
-	protected SearchBusinessGroupParams getDefaultSearchParams() {
-		SearchBusinessGroupParams params = new SearchBusinessGroupParams();
+	protected BusinessGroupQueryParams getDefaultSearchParams() {
+		BusinessGroupQueryParams params = new BusinessGroupQueryParams();
 		//security
 		if(!isAdmin()) {
 			params.setOwner(true);
 			params.setAttendee(true);
 			params.setWaiting(true);
 		}
-		params.setIdentity(getIdentity());
 		return params;
 	}
 	
@@ -84,4 +98,22 @@ public class SearchBusinessGroupListController extends AbstractBusinessGroupList
 		}
 		super.doLaunch(ureq, group);
 	}
+
+	@Override
+	protected List<BGTableItem> searchTableItems(BusinessGroupQueryParams params) {
+		List<BusinessGroupRow> rows = businessGroupService.findBusinessGroupsWithMemberships(params, getIdentity());
+		List<BGTableItem> items = new ArrayList<>(rows.size());
+		for(BusinessGroupRow row:rows) {
+			BusinessGroupMembership membership = row.getMember();
+			Boolean allowLeave =  membership != null;
+			Boolean allowDelete = isAdmin() ? Boolean.TRUE : (membership == null ? null : new Boolean(membership.isOwner()));
+			
+			FormLink markLink = uifactory.addFormLink("mark_" + row.getKey(), "mark", "", null, null, Link.NONTRANSLATED);
+			markLink.setIconLeftCSS(row.isMarked() ? Mark.MARK_CSS_LARGE : Mark.MARK_ADD_CSS_LARGE);
+
+			BGTableItem item = new BGTableItem(row, markLink, allowLeave, allowDelete);
+			items.add(item);
+		}
+		return items;
+	}
 }
diff --git a/src/main/java/org/olat/group/ui/main/SearchEvent.java b/src/main/java/org/olat/group/ui/main/SearchEvent.java
index 91987f1758fc9faac379fcabc7e1892369a0cf4a..b892376c16b6dca0dbacdd9d41290843ed6994e7 100644
--- a/src/main/java/org/olat/group/ui/main/SearchEvent.java
+++ b/src/main/java/org/olat/group/ui/main/SearchEvent.java
@@ -20,10 +20,9 @@
 package org.olat.group.ui.main;
 
 import org.olat.core.gui.control.Event;
-import org.olat.core.id.Identity;
 import org.olat.core.id.context.StateEntry;
 import org.olat.core.util.StringHelper;
-import org.olat.group.model.SearchBusinessGroupParams;
+import org.olat.group.model.BusinessGroupQueryParams;
 
 /**
  * 
@@ -136,9 +135,9 @@ public class SearchEvent extends Event implements StateEntry {
 	public void setHeadless(boolean headless) {
 		this.headless = headless;
 	}
-
-	public SearchBusinessGroupParams convertToSearchBusinessGroupParams(Identity identity) {
-		SearchBusinessGroupParams params = new SearchBusinessGroupParams();
+	
+	public BusinessGroupQueryParams convertToBusinessGroupQueriesParams() {
+		BusinessGroupQueryParams params = new BusinessGroupQueryParams();
 		params.setIdRef(StringHelper.containsNonWhitespace(idRef) ? idRef : null);
 		params.setName(StringHelper.containsNonWhitespace(name) ? name : null);
 		params.setDescription(StringHelper.containsNonWhitespace(description) ? description : null);
@@ -149,7 +148,6 @@ public class SearchEvent extends Event implements StateEntry {
 		params.setWaiting(isWaiting());
 		params.setPublicGroups(getPublicGroups());
 		params.setResources(getResources());
-		params.setIdentity(identity);
 		params.setHeadless(isHeadless());
 		return params;
 	}
diff --git a/src/main/java/org/olat/group/ui/main/SelectBusinessGroupCourseAuthorController.java b/src/main/java/org/olat/group/ui/main/SelectBusinessGroupCourseAuthorController.java
index 4210eddf4d434b450c0b47a64ef5bc6bd7e129ea..d1100c68251b4f47bdf9179dcfbbb81690f7b983 100644
--- a/src/main/java/org/olat/group/ui/main/SelectBusinessGroupCourseAuthorController.java
+++ b/src/main/java/org/olat/group/ui/main/SelectBusinessGroupCourseAuthorController.java
@@ -19,20 +19,16 @@
  */
 package org.olat.group.ui.main;
 
-import java.util.List;
-
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
 import org.olat.core.gui.control.WindowControl;
-import org.olat.group.BusinessGroupView;
-import org.olat.group.model.SearchBusinessGroupParams;
+import org.olat.group.model.BusinessGroupQueryParams;
 
 /**
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class SelectBusinessGroupCourseAuthorController extends AbstractBusinessGroupListController {
+public class SelectBusinessGroupCourseAuthorController extends AbstractSelectBusinessGroupListController {
 	
 	public SelectBusinessGroupCourseAuthorController(UserRequest ureq, WindowControl wControl) {
 		super(ureq, wControl, "group_list", "authors");
@@ -50,24 +46,16 @@ public class SelectBusinessGroupCourseAuthorController extends AbstractBusinessG
 	}
 
 	@Override
-	protected FlexiTableColumnModel initColumnModel() {
-		return BusinessGroupFlexiTableModel.getSelectColumnModel(flc, groupModule, getTranslator());
-	}
-
-	@Override
-	protected SearchBusinessGroupParams getSearchParams(SearchEvent event) {
-		SearchBusinessGroupParams params = new SearchBusinessGroupParams();
+	protected BusinessGroupQueryParams getSearchParams(SearchEvent event) {
+		BusinessGroupQueryParams params = new BusinessGroupQueryParams();
+		params.setAuthorConnection(true);
 		return params;
 	}
 
 	@Override
-	protected SearchBusinessGroupParams getDefaultSearchParams() {
-		SearchBusinessGroupParams params = new SearchBusinessGroupParams();
+	protected BusinessGroupQueryParams getDefaultSearchParams() {
+		BusinessGroupQueryParams params = new BusinessGroupQueryParams();
+		params.setAuthorConnection(true);
 		return params;
 	}
-
-	@Override
-	protected List<BusinessGroupView> searchBusinessGroupViews(SearchBusinessGroupParams params) {
-		return businessGroupService.findBusinessGroupViewsWithAuthorConnection(getIdentity());
-	}
 }
diff --git a/src/main/java/org/olat/group/ui/main/SelectFavoritBusinessGroupController.java b/src/main/java/org/olat/group/ui/main/SelectFavoritBusinessGroupController.java
index 2bc1e0de90f24e103fa31703b87822ca043f0d22..36c69080c96a45d11a23ea6d738d29f0dd163ada 100644
--- a/src/main/java/org/olat/group/ui/main/SelectFavoritBusinessGroupController.java
+++ b/src/main/java/org/olat/group/ui/main/SelectFavoritBusinessGroupController.java
@@ -21,15 +21,14 @@ package org.olat.group.ui.main;
 
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
 import org.olat.core.gui.control.WindowControl;
-import org.olat.group.model.SearchBusinessGroupParams;
+import org.olat.group.model.BusinessGroupQueryParams;
 
 /**
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class SelectFavoritBusinessGroupController extends AbstractBusinessGroupListController {
+public class SelectFavoritBusinessGroupController extends AbstractSelectBusinessGroupListController {
 
 	public SelectFavoritBusinessGroupController(UserRequest ureq, WindowControl wControl) {
 		super(ureq, wControl, "group_list", "sel-favorit");
@@ -46,32 +45,24 @@ public class SelectFavoritBusinessGroupController extends AbstractBusinessGroupL
 		initButtons(formLayout, ureq, false, true, false);
 		tableEl.setSearchEnabled(false);
 	}
-	
-	@Override
-	protected FlexiTableColumnModel initColumnModel() {
-		return BusinessGroupFlexiTableModel.getSelectColumnModel(flc, groupModule, getTranslator());
-	}
-
 
 	@Override
-	protected SearchBusinessGroupParams getSearchParams(SearchEvent event) {
-		SearchBusinessGroupParams params = new SearchBusinessGroupParams();
+	protected BusinessGroupQueryParams getSearchParams(SearchEvent event) {
+		BusinessGroupQueryParams params = new BusinessGroupQueryParams();
 		params.setMarked(Boolean.TRUE);
 		params.setAttendee(true);
 		params.setOwner(true);
 		params.setWaiting(true);
-		params.setIdentity(getIdentity());
 		return params;
 	}
 
 	@Override
-	protected SearchBusinessGroupParams getDefaultSearchParams() {
-		SearchBusinessGroupParams params = new SearchBusinessGroupParams();
+	protected BusinessGroupQueryParams getDefaultSearchParams() {
+		BusinessGroupQueryParams params = new BusinessGroupQueryParams();
 		params.setMarked(Boolean.TRUE);
 		params.setAttendee(true);
 		params.setOwner(true);
 		params.setWaiting(true);
-		params.setIdentity(getIdentity());
 		return params;
 	}
 }
diff --git a/src/main/java/org/olat/group/ui/main/SelectOwnedBusinessGroupController.java b/src/main/java/org/olat/group/ui/main/SelectOwnedBusinessGroupController.java
index 7ce702ed822fe6368fef0658d99eba60a8b72ce5..0f1546c4e42e2170b4bc38b030fa32887e06b4a3 100644
--- a/src/main/java/org/olat/group/ui/main/SelectOwnedBusinessGroupController.java
+++ b/src/main/java/org/olat/group/ui/main/SelectOwnedBusinessGroupController.java
@@ -21,15 +21,14 @@ package org.olat.group.ui.main;
 
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
 import org.olat.core.gui.control.WindowControl;
-import org.olat.group.model.SearchBusinessGroupParams;
+import org.olat.group.model.BusinessGroupQueryParams;
 
 /**
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class SelectOwnedBusinessGroupController extends AbstractBusinessGroupListController {
+public class SelectOwnedBusinessGroupController extends AbstractSelectBusinessGroupListController {
 	
 	public SelectOwnedBusinessGroupController(UserRequest ureq, WindowControl wControl) {
 		super(ureq, wControl, "group_list", "sel-owned");
@@ -47,26 +46,15 @@ public class SelectOwnedBusinessGroupController extends AbstractBusinessGroupLis
 	}
 
 	@Override
-	protected FlexiTableColumnModel initColumnModel() {
-		return BusinessGroupFlexiTableModel.getSelectColumnModel(flc, groupModule, getTranslator());
-	}
-
-	@Override
-	protected SearchBusinessGroupParams getSearchParams(SearchEvent event) {
-		SearchBusinessGroupParams params = new SearchBusinessGroupParams();
-		params.setIdentity(getIdentity());
-		params.setOwner(true);
-		params.setAttendee(false);
+	protected BusinessGroupQueryParams getSearchParams(SearchEvent event) {
+		BusinessGroupQueryParams params = new BusinessGroupQueryParams(true, false);
 		params.setWaiting(false);
 		return params;
 	}
 
 	@Override
-	protected SearchBusinessGroupParams getDefaultSearchParams() {
-		SearchBusinessGroupParams params = new SearchBusinessGroupParams();
-		params.setIdentity(getIdentity());
-		params.setOwner(true);
-		params.setAttendee(false);
+	protected BusinessGroupQueryParams getDefaultSearchParams() {
+		BusinessGroupQueryParams params = new BusinessGroupQueryParams(true, false);
 		params.setWaiting(false);
 		return params;
 	}
diff --git a/src/main/java/org/olat/group/ui/main/SelectSearchBusinessGroupController.java b/src/main/java/org/olat/group/ui/main/SelectSearchBusinessGroupController.java
index 6d882b634172bc785e566ebfc88d439f13eaf6d0..d1d89b73d558e4bb9f5963d9c68d845945f20046 100644
--- a/src/main/java/org/olat/group/ui/main/SelectSearchBusinessGroupController.java
+++ b/src/main/java/org/olat/group/ui/main/SelectSearchBusinessGroupController.java
@@ -21,15 +21,14 @@ package org.olat.group.ui.main;
 
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
 import org.olat.core.gui.control.WindowControl;
-import org.olat.group.model.SearchBusinessGroupParams;
+import org.olat.group.model.BusinessGroupQueryParams;
 
 /**
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class SelectSearchBusinessGroupController extends AbstractBusinessGroupListController {
+public class SelectSearchBusinessGroupController extends AbstractSelectBusinessGroupListController {
 	
 	private final boolean restricted;
 	
@@ -49,13 +48,8 @@ public class SelectSearchBusinessGroupController extends AbstractBusinessGroupLi
 	}
 
 	@Override
-	protected FlexiTableColumnModel initColumnModel() {
-		return BusinessGroupFlexiTableModel.getSelectColumnModel(flc, groupModule, getTranslator());
-	}
-
-	@Override
-	protected SearchBusinessGroupParams getSearchParams(SearchEvent event) {
-		SearchBusinessGroupParams params = event.convertToSearchBusinessGroupParams(getIdentity());
+	protected BusinessGroupQueryParams getSearchParams(SearchEvent event) {
+		BusinessGroupQueryParams params = event.convertToBusinessGroupQueriesParams();
 		//security
 		if(restricted && !params.isAttendee() && !params.isOwner() && !params.isWaiting()
 				&& (params.getPublicGroups() == null || !params.getPublicGroups().booleanValue())) {
@@ -67,15 +61,14 @@ public class SelectSearchBusinessGroupController extends AbstractBusinessGroupLi
 	}
 
 	@Override
-	protected SearchBusinessGroupParams getDefaultSearchParams() {
-		SearchBusinessGroupParams params = new SearchBusinessGroupParams();
+	protected BusinessGroupQueryParams getDefaultSearchParams() {
+		BusinessGroupQueryParams params = new BusinessGroupQueryParams();
 		//security
 		if(restricted) {
 			params.setOwner(true);
 			params.setAttendee(true);
 			params.setWaiting(true);
 		}
-		params.setIdentity(getIdentity());
 		return params;
 	}
 
diff --git a/src/main/java/org/olat/group/ui/main/UnmanagedGroupFilter.java b/src/main/java/org/olat/group/ui/main/UnmanagedGroupFilter.java
index ea6511e9a5b72acd94a04e0bc84ff96fd05f8b62..5fb77cdc920b7074691a2226961d50efb003610b 100644
--- a/src/main/java/org/olat/group/ui/main/UnmanagedGroupFilter.java
+++ b/src/main/java/org/olat/group/ui/main/UnmanagedGroupFilter.java
@@ -20,7 +20,7 @@
 package org.olat.group.ui.main;
 
 import org.olat.group.BusinessGroupManagedFlag;
-import org.olat.group.BusinessGroupView;
+import org.olat.group.model.BusinessGroupRow;
 
 /**
  * Accept only NOT managed groups.
@@ -38,7 +38,7 @@ public class UnmanagedGroupFilter implements BusinessGroupViewFilter {
 	}
 
 	@Override
-	public boolean accept(BusinessGroupView view) {
-		return !BusinessGroupManagedFlag.isManaged(view.getManagedFlags(), flag);
+	public boolean accept(BusinessGroupRow row) {
+		return !BusinessGroupManagedFlag.isManaged(row.getManagedFlags(), flag);
 	}
 }
diff --git a/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java b/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java
index 6201cf1c12276be057e1cecd0d6bdca823c764f4..a40f57119be1d183c3c7c5f745f1f6144c8de111 100644
--- a/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java
+++ b/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java
@@ -774,10 +774,10 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 		addToHistory(ureq, bwControl);
 		
 		CollaborationTools collabTools = CollaborationToolsFactory.getInstance().getOrCreateCollaborationTools(businessGroup);
-		Controller collabToolCtr = collabTools.createPortfolioController(ureq, bwControl, businessGroup);
-		listenTo(collabToolCtr);
-		mainPanel.setContent(collabToolCtr.getInitialComponent());
-		return (Activateable2)collabToolCtr;
+		Controller collaborationToolCtr = collabTools.createPortfolioController(ureq, bwControl, businessGroup);
+		listenTo(collaborationToolCtr);
+		mainPanel.setContent(collaborationToolCtr.getInitialComponent());
+		return (Activateable2)collaborationToolCtr;
 	}
 	
 	private void doOpenMeetings(UserRequest ureq) {
diff --git a/src/main/java/org/olat/modules/qpool/manager/PoolDAO.java b/src/main/java/org/olat/modules/qpool/manager/PoolDAO.java
index 25168da2e0865f0e9ad2aec3783d1684ba496446..aa79d53935e63d07e89adce7e2991744a55d5ef4 100644
--- a/src/main/java/org/olat/modules/qpool/manager/PoolDAO.java
+++ b/src/main/java/org/olat/modules/qpool/manager/PoolDAO.java
@@ -159,7 +159,7 @@ public class PoolDAO {
 		Number countShared = null;
 		if(countPool == null || countPool.intValue() <= 0) {
 			StringBuilder sc = new StringBuilder();
-			sc.append("select count(bgi.key) from ").append(org.olat.group.BusinessGroupImpl.class.getName()).append(" as bgi ")
+			sc.append("select count(bgi.key) from businessgroup as bgi ")
 			  .append(" inner join bgi.baseGroup as baseGroup")
 			  .append(" inner join baseGroup.members as membership")
 			  .append(" where membership.identity.key=:identityKey")
diff --git a/src/main/java/org/olat/modules/qpool/manager/QuestionItemDAO.java b/src/main/java/org/olat/modules/qpool/manager/QuestionItemDAO.java
index 4e9caa2d91312d74176015efa2033404d4a5951f..c36a4e9c6fe09ec1fdeee3054fc5377640359696 100644
--- a/src/main/java/org/olat/modules/qpool/manager/QuestionItemDAO.java
+++ b/src/main/java/org/olat/modules/qpool/manager/QuestionItemDAO.java
@@ -344,7 +344,7 @@ public class QuestionItemDAO {
 	
 	public List<BusinessGroup> getResourcesWithSharedItems(Identity identity) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select distinct(bgi) from ").append(org.olat.group.BusinessGroupImpl.class.getName()).append(" as bgi ")
+		sb.append("select distinct(bgi) from businessgroup as bgi ")
 		  .append(" inner join fetch bgi.resource bgResource")
 		  .append(" inner join fetch bgi.baseGroup as baseGroup")
 		  .append(" inner join fetch baseGroup.members as membership")
diff --git a/src/main/java/org/olat/resource/accesscontrol/manager/ACMethodDAO.java b/src/main/java/org/olat/resource/accesscontrol/manager/ACMethodDAO.java
index fa0c990fd28701720ed22aabbff44fb504de3b4f..61b9f7c53d9f78f2568247a439b414a0fbeb13b4 100644
--- a/src/main/java/org/olat/resource/accesscontrol/manager/ACMethodDAO.java
+++ b/src/main/java/org/olat/resource/accesscontrol/manager/ACMethodDAO.java
@@ -46,7 +46,6 @@ import org.olat.core.util.event.FrameworkStartedEvent;
 import org.olat.core.util.event.FrameworkStartupEventChannel;
 import org.olat.core.util.event.GenericEventListener;
 import org.olat.group.BusinessGroup;
-import org.olat.group.BusinessGroupImpl;
 import org.olat.group.BusinessGroupService;
 import org.olat.resource.OLATResource;
 import org.olat.resource.OLATResourceImpl;
@@ -246,7 +245,7 @@ public class ACMethodDAO implements GenericEventListener {
 
 		StringBuilder sb = new StringBuilder();
 		sb.append("select access.method, group.key, offer.price from ").append(OfferAccessImpl.class.getName()).append(" access, ")
-			.append(BusinessGroupImpl.class.getName()).append(" group ")
+			.append(" businessgroup group ")
 			.append(" inner join access.offer offer")
 			.append(" where access.valid=").append(valid)
 			.append(" and offer.valid=").append(valid)
diff --git a/src/main/java/org/olat/upgrade/OLATUpgrade_9_4_0.java b/src/main/java/org/olat/upgrade/OLATUpgrade_9_4_0.java
index 969d192bfdde7f2b151f509980ac0bf4848a5dab..553c43b4804452e625498202b9c7fed70461a28b 100644
--- a/src/main/java/org/olat/upgrade/OLATUpgrade_9_4_0.java
+++ b/src/main/java/org/olat/upgrade/OLATUpgrade_9_4_0.java
@@ -221,7 +221,7 @@ public class OLATUpgrade_9_4_0 extends OLATUpgrade {
 	
 	private List<BusinessGroupImpl> findGroups(int firstResult, int maxResults) {
 		StringBuilder sb = new StringBuilder();	
-		sb.append("select grp from ").append(BusinessGroupImpl.class.getName()).append(" grp order by key");
+		sb.append("select grp from businessgroup grp order by key");
 		return dbInstance.getCurrentEntityManager().createQuery(sb.toString(), BusinessGroupImpl.class)
 				.setFirstResult(firstResult)
 				.setMaxResults(maxResults)
diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml
index 6e89e7b9721933ce4a77d8d497952aa25b8c9e61..6ceed4375b656aebe0c0c09bfbcf3dcb04768623 100644
--- a/src/main/resources/META-INF/persistence.xml
+++ b/src/main/resources/META-INF/persistence.xml
@@ -19,8 +19,6 @@
 		<mapping-file>org/olat/commons/info/model/InfoMessageImpl.hbm.xml</mapping-file>
 		<mapping-file>org/olat/group/area/BGAreaImpl.hbm.xml</mapping-file>
 		<mapping-file>org/olat/group/area/BGtoAreaRelationImpl.hbm.xml</mapping-file>
-		<mapping-file>org/olat/group/BusinessGroupImpl.hbm.xml</mapping-file>
-		<mapping-file>org/olat/group/model/BusinessGroupViewImpl.hbm.xml</mapping-file>
 		<mapping-file>org/olat/resource/OLATResourceImpl.hbm.xml</mapping-file>
 		<mapping-file>org/olat/resource/accesscontrol/model/Offer.hbm.xml</mapping-file>
 		<mapping-file>org/olat/resource/accesscontrol/model/AccessMethod.hbm.xml</mapping-file>
@@ -116,8 +114,13 @@
 		<class>org.olat.course.certificate.model.CertificateTemplateImpl</class>
 		<class>org.olat.group.model.ContactView</class>
 		<class>org.olat.group.model.ContactViewExtended</class>
+		<class>org.olat.group.model.BusinessGroupShortImpl</class>
 		<class>org.olat.group.model.BusinessGroupMembershipViewImpl</class>
 		<class>org.olat.group.model.BGRepositoryEntryRelation</class>
+		<class>org.olat.group.model.RepositoryEntryToBusinessGroup</class>
+		<class>org.olat.group.model.GroupToBusinessGroup</class>
+		<class>org.olat.group.model.BusinessGroupToSearch</class>
+		<class>org.olat.group.BusinessGroupImpl</class>
 		<class>org.olat.repository.RepositoryEntry</class>
 		<class>org.olat.repository.model.RepositoryEntryToGroupRelation</class>
 		<class>org.olat.repository.model.RepositoryEntryLifecycle</class>
diff --git a/src/main/resources/database/mysql/refreshViews.sql b/src/main/resources/database/mysql/refreshViews.sql
index 636bc6e409e504d0ccf1a87d65398410a41a5d48..93137953a4c6b89ff7f3b7d273b55bd0b115160e 100644
--- a/src/main/resources/database/mysql/refreshViews.sql
+++ b/src/main/resources/database/mysql/refreshViews.sql
@@ -116,47 +116,6 @@ create or replace view o_bs_gp_membership_v as (
    inner join o_gp_business as gp on (gp.fk_group_id=membership.fk_group_id)
 );
 
-create or replace view o_gp_business_v  as (
-   select
-      gp.group_id as group_id,
-      gp.groupname as groupname,
-      gp.lastmodified as lastmodified,
-      gp.creationdate as creationdate,
-      gp.lastusage as lastusage,
-      gp.descr as descr,
-      gp.minparticipants as minparticipants,
-      gp.maxparticipants as maxparticipants,
-      gp.waitinglist_enabled as waitinglist_enabled,
-      gp.autocloseranks_enabled as autocloseranks_enabled,
-      gp.external_id as external_id,
-      gp.managed_flags as managed_flags,
-      (select count(part.id) from o_bs_group_member as part where part.fk_group_id = gp.fk_group_id and part.g_role='participant') as num_of_participants,
-      (select count(pending.reservation_id) from o_ac_reservation as pending where pending.fk_resource = gp.fk_resource) as num_of_pendings,
-      (select count(own.id) from o_bs_group_member as own where own.fk_group_id = gp.fk_group_id and own.g_role='coach') as num_of_owners,
-      (case when gp.waitinglist_enabled = true
-         then 
-           (select count(waiting.id) from o_bs_group_member as waiting where waiting.fk_group_id = gp.fk_group_id and waiting.g_role='waiting')
-         else
-           0
-      end) as num_waiting,
-      (select count(offer.offer_id) from o_ac_offer as offer 
-         where offer.fk_resource_id = gp.fk_resource
-         and offer.is_valid=true
-         and (offer.validfrom is null or offer.validfrom <= current_timestamp())
-         and (offer.validto is null or offer.validto >= current_timestamp())
-      ) as num_of_valid_offers,
-      (select count(offer.offer_id) from o_ac_offer as offer 
-         where offer.fk_resource_id = gp.fk_resource
-         and offer.is_valid=true
-      ) as num_of_offers,
-      (select count(relation.fk_entry_id) from o_re_to_group as relation 
-         where relation.fk_group_id = gp.fk_group_id
-      ) as num_of_relations,
-      gp.fk_resource as fk_resource,
-      gp.fk_group_id as fk_group_id
-   from o_gp_business as gp
-);
-
 create or replace view o_re_membership_v as (
    select
       bmember.id as membership_id,
diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql
index 50a16f6366a11b21a40651b8e436fb9a02f77412..22332ce509b03ff76b552c8b8bf2a0a2932d5554 100644
--- a/src/main/resources/database/mysql/setupDatabase.sql
+++ b/src/main/resources/database/mysql/setupDatabase.sql
@@ -1560,47 +1560,6 @@ create view o_bs_gp_membership_v as (
    inner join o_gp_business as gp on (gp.fk_group_id=membership.fk_group_id)
 );
 
-create view o_gp_business_v  as (
-   select
-      gp.group_id as group_id,
-      gp.groupname as groupname,
-      gp.lastmodified as lastmodified,
-      gp.creationdate as creationdate,
-      gp.lastusage as lastusage,
-      gp.descr as descr,
-      gp.minparticipants as minparticipants,
-      gp.maxparticipants as maxparticipants,
-      gp.waitinglist_enabled as waitinglist_enabled,
-      gp.autocloseranks_enabled as autocloseranks_enabled,
-      gp.external_id as external_id,
-      gp.managed_flags as managed_flags,
-      (select count(part.id) from o_bs_group_member as part where part.fk_group_id = gp.fk_group_id and part.g_role='participant') as num_of_participants,
-      (select count(pending.reservation_id) from o_ac_reservation as pending where pending.fk_resource = gp.fk_resource) as num_of_pendings,
-      (select count(own.id) from o_bs_group_member as own where own.fk_group_id = gp.fk_group_id and own.g_role='coach') as num_of_owners,
-      (case when gp.waitinglist_enabled = true
-         then 
-           (select count(waiting.id) from o_bs_group_member as waiting where waiting.fk_group_id = gp.fk_group_id and waiting.g_role='waiting')
-         else
-           0
-      end) as num_waiting,
-      (select count(offer.offer_id) from o_ac_offer as offer 
-         where offer.fk_resource_id = gp.fk_resource
-         and offer.is_valid=true
-         and (offer.validfrom is null or offer.validfrom <= current_timestamp())
-         and (offer.validto is null or offer.validto >= current_timestamp())
-      ) as num_of_valid_offers,
-      (select count(offer.offer_id) from o_ac_offer as offer 
-         where offer.fk_resource_id = gp.fk_resource
-         and offer.is_valid=true
-      ) as num_of_offers,
-      (select count(relation.fk_entry_id) from o_re_to_group as relation 
-         where relation.fk_group_id = gp.fk_group_id
-      ) as num_of_relations,
-      gp.fk_resource as fk_resource,
-      gp.fk_group_id as fk_group_id
-   from o_gp_business as gp
-);
-
 create or replace view o_re_membership_v as (
    select
       bmember.id as membership_id,
diff --git a/src/main/resources/database/oracle/setupDatabase.sql b/src/main/resources/database/oracle/setupDatabase.sql
index ea2e0f54b71f1b590a7181370ff8ce2aababc249..1f6e91e45a5f75ebfac944efa73c6c00d47ad856 100644
--- a/src/main/resources/database/oracle/setupDatabase.sql
+++ b/src/main/resources/database/oracle/setupDatabase.sql
@@ -1614,47 +1614,6 @@ create view o_bs_gp_membership_v as (
    inner join o_gp_business gp on (gp.fk_group_id=membership.fk_group_id)
 );
 
-create or replace view o_gp_business_v  as (
-   select
-      gp.group_id as group_id,
-      gp.groupname as groupname,
-      gp.lastmodified as lastmodified,
-      gp.creationdate as creationdate,
-      gp.lastusage as lastusage,
-      gp.descr as descr,
-      gp.minparticipants as minparticipants,
-      gp.maxparticipants as maxparticipants,
-      gp.waitinglist_enabled as waitinglist_enabled,
-      gp.autocloseranks_enabled as autocloseranks_enabled,
-      gp.external_id as external_id,
-      gp.managed_flags as managed_flags,
-      (select count(part.id) from o_bs_group_member part where part.fk_group_id = gp.fk_group_id and part.g_role='participant') as num_of_participants,
-      (select count(pending.reservation_id) from o_ac_reservation pending where pending.fk_resource = gp.fk_resource) as num_of_pendings,
-      (select count(own.id) from o_bs_group_member own where own.fk_group_id = gp.fk_group_id and own.g_role='coach') as num_of_owners,
-      (case when gp.waitinglist_enabled > 0
-         then 
-           (select count(waiting.id) from o_bs_group_member waiting where waiting.fk_group_id = gp.fk_group_id and waiting.g_role='waiting')
-         else
-           0
-      end) as num_waiting,
-      (select count(offer.offer_id) from o_ac_offer offer 
-         where offer.fk_resource_id = gp.fk_resource
-         and offer.is_valid > 0
-         and (offer.validfrom is null or offer.validfrom <= current_date)
-         and (offer.validto is null or offer.validto >= current_date)
-      ) as num_of_valid_offers,
-      (select count(offer.offer_id) from o_ac_offer offer 
-         where offer.fk_resource_id = gp.fk_resource
-         and offer.is_valid > 0
-      ) as num_of_offers,
-      (select count(relation.fk_entry_id) from o_re_to_group relation 
-         where relation.fk_group_id = gp.fk_group_id
-      ) as num_of_relations,
-      gp.fk_resource as fk_resource,
-      gp.fk_group_id as fk_group_id
-   from o_gp_business gp
-);
-
 create or replace view o_re_membership_v as (
    select
       bmember.id as membership_id,
diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql
index 1ebd076078f6694a8f14e798084fb5d5ba303463..047f864e3785e8a785d5dbce839b5d125afb72fc 100644
--- a/src/main/resources/database/postgresql/setupDatabase.sql
+++ b/src/main/resources/database/postgresql/setupDatabase.sql
@@ -1562,47 +1562,6 @@ create view o_bs_gp_membership_v as (
    inner join o_gp_business as gp on (gp.fk_group_id=membership.fk_group_id)
 );
 
-create or replace view o_gp_business_v  as (
-   select
-      gp.group_id as group_id,
-      gp.groupname as groupname,
-      gp.lastmodified as lastmodified,
-      gp.creationdate as creationdate,
-      gp.lastusage as lastusage,
-      gp.descr as descr,
-      gp.minparticipants as minparticipants,
-      gp.maxparticipants as maxparticipants,
-      gp.waitinglist_enabled as waitinglist_enabled,
-      gp.autocloseranks_enabled as autocloseranks_enabled,
-      gp.external_id as external_id,
-      gp.managed_flags as managed_flags,
-      (select count(part.id) from o_bs_group_member as part where part.fk_group_id = gp.fk_group_id and part.g_role='participant') as num_of_participants,
-      (select count(pending.reservation_id) from o_ac_reservation as pending where pending.fk_resource = gp.fk_resource) as num_of_pendings,
-      (select count(own.id) from o_bs_group_member as own where own.fk_group_id = gp.fk_group_id and own.g_role='coach') as num_of_owners,
-      (case when gp.waitinglist_enabled = true
-         then 
-           (select count(waiting.id) from o_bs_group_member as waiting where waiting.fk_group_id = gp.fk_group_id and waiting.g_role='waiting')
-         else
-           0
-      end) as num_waiting,
-      (select count(offer.offer_id) from o_ac_offer as offer 
-         where offer.fk_resource_id = gp.fk_resource
-         and offer.is_valid=true
-         and (offer.validfrom is null or offer.validfrom <= current_timestamp)
-         and (offer.validto is null or offer.validto >= current_timestamp)
-      ) as num_of_valid_offers,
-      (select count(offer.offer_id) from o_ac_offer as offer 
-         where offer.fk_resource_id = gp.fk_resource
-         and offer.is_valid=true
-      ) as num_of_offers,
-      (select count(relation.fk_entry_id) from o_re_to_group as relation 
-         where relation.fk_group_id = gp.fk_group_id
-      ) as num_of_relations,
-      gp.fk_resource as fk_resource,
-      gp.fk_group_id as fk_group_id
-   from o_gp_business as gp
-);
-
 create or replace view o_re_membership_v as (
    select
       bmember.id as membership_id,
diff --git a/src/test/java/org/olat/group/test/BusinessGroupDAOTest.java b/src/test/java/org/olat/group/test/BusinessGroupDAOTest.java
index 82d2f06df793670c7e6dca363d4f9b5ac45cfe62..122944f2f50291f7d4dffbf61c809dc0dcb53e93 100644
--- a/src/test/java/org/olat/group/test/BusinessGroupDAOTest.java
+++ b/src/test/java/org/olat/group/test/BusinessGroupDAOTest.java
@@ -40,16 +40,20 @@ import org.olat.core.commons.services.mark.MarkManager;
 import org.olat.core.id.Identity;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupMembership;
-import org.olat.group.BusinessGroupOrder;
+import org.olat.group.BusinessGroupRef;
 import org.olat.group.BusinessGroupShort;
-import org.olat.group.BusinessGroupView;
 import org.olat.group.manager.BusinessGroupDAO;
 import org.olat.group.manager.BusinessGroupRelationDAO;
 import org.olat.group.model.BusinessGroupMembershipViewImpl;
+import org.olat.group.model.BusinessGroupQueryParams;
+import org.olat.group.model.BusinessGroupRow;
+import org.olat.group.model.OpenBusinessGroupRow;
+import org.olat.group.model.StatisticsBusinessGroupRow;
 import org.olat.group.model.SearchBusinessGroupParams;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.manager.RepositoryEntryRelationDAO;
 import org.olat.resource.OLATResource;
+import org.olat.resource.OLATResourceManager;
 import org.olat.resource.accesscontrol.ACService;
 import org.olat.resource.accesscontrol.model.Offer;
 import org.olat.test.JunitTestHelper;
@@ -62,18 +66,20 @@ import org.springframework.beans.factory.annotation.Autowired;
  */
 public class BusinessGroupDAOTest extends OlatTestCase {
 	
-	@Autowired
-	private BusinessGroupDAO businessGroupDao;
-	@Autowired
-	private BusinessGroupRelationDAO businessGroupRelationDao;
-	@Autowired
-	private RepositoryEntryRelationDAO repositoryEntryRelationDao;
 	@Autowired
 	private DB dbInstance;
 	@Autowired
 	private ACService acService;
 	@Autowired
 	private MarkManager markManager;
+	@Autowired
+	private BusinessGroupDAO businessGroupDao;
+	@Autowired
+	private OLATResourceManager resourceManager;
+	@Autowired
+	private BusinessGroupRelationDAO businessGroupRelationDao;
+	@Autowired
+	private RepositoryEntryRelationDAO repositoryEntryRelationDao;
 	
 	@Test
 	public void should_service_present() {
@@ -271,7 +277,6 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		Assert.assertTrue(allGroups.contains(group1));
 		Assert.assertTrue(allGroups.contains(group2));
 	}
-
 	
 	@Test
 	public void mergeBusinessGroup() {
@@ -367,33 +372,6 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		Assert.assertTrue(groupOfId3.isEmpty());
 	}
 	
-	@Test
-	public void findBusinessGroupWithAuthorConnection() {
-		Identity author = JunitTestHelper.createAndPersistIdentityAsUser("bdao-5-" + UUID.randomUUID().toString());
-		RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry();
-		repositoryEntryRelationDao.addRole(author, re, GroupRoles.owner.name());
-		
-		BusinessGroup group1 = businessGroupDao.createAndPersist(null, "gdlo", "gdlo-desc", 0, 5, true, false, false, false, false);
-		BusinessGroup group2 = businessGroupDao.createAndPersist(author, "gdmo", "gdmo-desc", 0, 5, true, false, false, false, false);
-		BusinessGroup group3 = businessGroupDao.createAndPersist(author, "gdmo", "gdmo-desc", 0, 5, true, false, false, false, false);
-		businessGroupRelationDao.addRelationToResource(group1, re);
-		businessGroupRelationDao.addRelationToResource(group3, re);
-		dbInstance.commitAndCloseSession();
-		
-		//check 
-		List<BusinessGroupView> groups = businessGroupDao.findBusinessGroupWithAuthorConnection(author);
-		Assert.assertNotNull(groups);
-		Assert.assertEquals(2, groups.size());
-		
-		Set<Long> retrievedGroupkey = new HashSet<Long>();
-		for(BusinessGroupView view:groups) {
-			retrievedGroupkey.add(view.getKey());
-		}
-		Assert.assertTrue(retrievedGroupkey.contains(group1.getKey()));
-		Assert.assertTrue(retrievedGroupkey.contains(group3.getKey()));
-		Assert.assertFalse(retrievedGroupkey.contains(group2.getKey()));
-	}
-	
 	@Test
 	public void testVisibilityOfSecurityGroups() {
 		//create 3 groups
@@ -418,6 +396,7 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 	
 	@Test
 	public void findBusinessGroups() {
+		Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("bg-search");
 		BusinessGroup group1 = businessGroupDao.createAndPersist(null, "gduo", "gduo-desc", 0, 5, true, false, true, false, false);
 		BusinessGroup group2 = businessGroupDao.createAndPersist(null, "gdvo", "gdvo-desc", 0, 5, true, false, true, false, false);
 		dbInstance.commitAndCloseSession();
@@ -429,21 +408,19 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		Assert.assertTrue(groups.contains(group1));
 		Assert.assertTrue(groups.contains(group2));
 
-		List<BusinessGroupView> groupViews = businessGroupDao.findBusinessGroupViews(params, null, 0, -1);
+		BusinessGroupQueryParams searchParams = new BusinessGroupQueryParams();
+		List<BusinessGroupRow> groupViews = businessGroupDao.searchBusinessGroupsWithMemberships(searchParams, identity);
 		Assert.assertNotNull(groupViews);
 		Assert.assertTrue(groupViews.size() >= 2);
 		Assert.assertTrue(contains(groupViews, group1));
 		Assert.assertTrue(contains(groupViews, group2));
 
-		dbInstance.commit();
-
-		List<BusinessGroup> groupLimit = businessGroupDao.findBusinessGroups(params, null, 0, 1);
-		Assert.assertNotNull(groupLimit);
-		Assert.assertEquals(1, groupLimit.size());
+		List<StatisticsBusinessGroupRow> groupToSelect = businessGroupDao.searchBusinessGroupsForSelection(searchParams, identity);
+		Assert.assertNotNull(groupToSelect);
+		Assert.assertTrue(groupToSelect.size() >= 2);
 		
-		List<BusinessGroupView> groupViewLimit = businessGroupDao.findBusinessGroupViews(params, null, 0, 1);
-		Assert.assertNotNull(groupViewLimit);
-		Assert.assertEquals(1, groupViewLimit.size());
+		List<OpenBusinessGroupRow> openGroups = businessGroupDao.searchPublishedBusinessGroups(searchParams, identity);
+		Assert.assertNotNull(openGroups);
 	}
 	
 	@Test
@@ -462,19 +439,12 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		Assert.assertTrue(groups.contains(group1));
 		Assert.assertFalse(groups.contains(group2));
 		Assert.assertFalse(groups.contains(group3));
-		
-		//check find with views
-		List<BusinessGroupView> groupViews = businessGroupDao.findBusinessGroupViews(params, null, 0, -1);
-		Assert.assertNotNull(groupViews);
-		Assert.assertEquals(1, groupViews.size());
-		Assert.assertTrue(contains(groupViews, group1));
-		Assert.assertFalse(contains(groupViews, group2));
-		Assert.assertFalse(contains(groupViews, group3));
 	}
 	
 	@Test
 	public void findBusinessGroupsByName() {
 		String marker = UUID.randomUUID().toString();
+		Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("bg-search-2");
 		BusinessGroup group1 = businessGroupDao.createAndPersist(null, marker.toUpperCase(), "fingbg-1-desc", 0, 5, true, false, true, false, false);
 		BusinessGroup group2 = businessGroupDao.createAndPersist(null, marker + "xxx", "fingbg-2-desc", 0, 5, true, false, true, false, false);
 		BusinessGroup group3 = businessGroupDao.createAndPersist(null, "yyy" + marker.toUpperCase(), "fingbg-3-desc", 0, 5, true, false, true, false, false);
@@ -490,7 +460,9 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		Assert.assertFalse(groups.contains(group3));
 		
 		//check the same with the views
-		List<BusinessGroupView> groupViews = businessGroupDao.findBusinessGroupViews(params, null, 0, -1);
+		BusinessGroupQueryParams searchParams = new BusinessGroupQueryParams();
+		searchParams.setName(marker);
+		List<BusinessGroupRow> groupViews = businessGroupDao.searchBusinessGroupsWithMemberships(searchParams, identity);
 		Assert.assertNotNull(groupViews);
 		Assert.assertEquals(2, groupViews.size() );
 		Assert.assertTrue(contains(groupViews, group1));
@@ -501,6 +473,7 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 	@Test
 	public void findBusinessGroupsByNameFuzzy() {
 		String marker = UUID.randomUUID().toString();
+		Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("bg-search-3");
 		BusinessGroup group1 = businessGroupDao.createAndPersist(null, marker.toUpperCase(), "fingbg-1-desc", 0, 5, true, false, true, false, false);
 		BusinessGroup group2 = businessGroupDao.createAndPersist(null, marker + "xxx", "fingbg-2-desc", 0, 5, true, false, true, false, false);
 		BusinessGroup group3 = businessGroupDao.createAndPersist(null, "yyy" + marker.toUpperCase(), "fingbg-3-desc", 0, 5, true, false, true, false, false);
@@ -516,7 +489,9 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		Assert.assertTrue(groups.contains(group3));
 		
 		//check the same with the views
-		List<BusinessGroupView> groupViews = businessGroupDao.findBusinessGroupViews(params, null, 0, -1);
+		BusinessGroupQueryParams searchParams = new BusinessGroupQueryParams();
+		searchParams.setName("*" + marker + "*");
+		List<BusinessGroupRow> groupViews = businessGroupDao.searchBusinessGroupsWithMemberships(searchParams, identity);
 		Assert.assertNotNull(groupViews);
 		Assert.assertEquals(3, groupViews.size() );
 		Assert.assertTrue(contains(groupViews, group1));
@@ -527,6 +502,7 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 	@Test
 	public void findBusinessGroupsByDescription() {
 		String marker = UUID.randomUUID().toString();
+		Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("bg-search-4");
 		BusinessGroup group1 = businessGroupDao.createAndPersist(null, "fingbg-1", marker.toUpperCase() + "-desc", 0, 5, true, false, true, false, false);
 		BusinessGroup group2 = businessGroupDao.createAndPersist(null, "fingbg-2", "desc-" + marker, 0, 5, true, false, true, false, false);
 		BusinessGroup group3 = businessGroupDao.createAndPersist(null, "fingbg-3", "desc-" + marker + "-desc", 0, 5, true, false, true, false, false);
@@ -543,7 +519,10 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		Assert.assertFalse(groups.contains(group3));
 		
 		//check find business group
-		List<BusinessGroupView> groupViews = businessGroupDao.findBusinessGroupViews(params, null, 0, -1);
+
+		BusinessGroupQueryParams searchParams = new BusinessGroupQueryParams();
+		searchParams.setDescription(marker);
+		List<BusinessGroupRow> groupViews = businessGroupDao.searchBusinessGroupsWithMemberships(searchParams, identity);
 		Assert.assertNotNull(groupViews);
 		Assert.assertEquals(1, groupViews.size() );
 		Assert.assertTrue(contains(groupViews, group1));
@@ -554,6 +533,7 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 	@Test
 	public void findBusinessGroupsByDescriptionFuzzy() {
 		String marker = UUID.randomUUID().toString();
+		Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("bg-search-5");
 		BusinessGroup group1 = businessGroupDao.createAndPersist(null, "fingbg-1", marker + "-desc", 0, 5, true, false, true, false, false);
 		BusinessGroup group2 = businessGroupDao.createAndPersist(null, "fingbg-2", "desc-" + marker.toUpperCase(), 0, 5, true, false, true, false, false);
 		BusinessGroup group3 = businessGroupDao.createAndPersist(null, "fingbg-3", "desc-" + marker + "-desc", 0, 5, true, false, true, false, false);
@@ -569,7 +549,10 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		Assert.assertTrue(groups.contains(group3));
 		
 		//check same search with the views
-		List<BusinessGroupView> groupViews = businessGroupDao.findBusinessGroupViews(params, null, 0, -1);
+
+		BusinessGroupQueryParams searchParams = new BusinessGroupQueryParams();
+		searchParams.setDescription("*" + marker + "*");
+		List<BusinessGroupRow> groupViews = businessGroupDao.searchBusinessGroupsWithMemberships(searchParams, identity);
 		Assert.assertNotNull(groupViews);
 		Assert.assertEquals(3, groupViews.size() );
 		Assert.assertTrue(contains(groupViews, group1));
@@ -580,6 +563,7 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 	@Test
 	public void findBusinessGroupsByNameOrDesc() {
 		String marker = UUID.randomUUID().toString();
+		Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("bg-search-6");
 		BusinessGroup group1 = businessGroupDao.createAndPersist(null, "fingbg-1", marker.toUpperCase() + "-desc", 0, 5, true, false, true, false, false);
 		BusinessGroup group2 = businessGroupDao.createAndPersist(null, "fingbg-2", "fingbg-2-desc", 0, 5, true, false, true, false, false);
 		BusinessGroup group3 = businessGroupDao.createAndPersist(null, marker.toUpperCase() + "-xxx", "desc-fingb-desc", 0, 5, true, false, true, false, false);
@@ -595,7 +579,9 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		Assert.assertTrue(groups.contains(group3));
 		
 		//check the same search with the views
-		List<BusinessGroupView> groupViews = businessGroupDao.findBusinessGroupViews(params, null, 0, -1);
+		BusinessGroupQueryParams searchParams = new BusinessGroupQueryParams();
+		searchParams.setNameOrDesc(marker);
+		List<BusinessGroupRow> groupViews = businessGroupDao.searchBusinessGroupsWithMemberships(searchParams, identity);
 		Assert.assertNotNull(groupViews);
 		Assert.assertEquals(2, groupViews.size() );
 		Assert.assertTrue(contains(groupViews, group1));
@@ -606,6 +592,7 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 	@Test
 	public void findBusinessGroupsByNameOrDescFuzzy() {
 		String marker = UUID.randomUUID().toString();
+		Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("bg-search-7");
 		BusinessGroup group1 = businessGroupDao.createAndPersist(null, "fingbg-1", marker + "-desc", 0, 5, true, false, true, false, false);
 		BusinessGroup group2 = businessGroupDao.createAndPersist(null, "fingbg-2", "desc-" + marker.toUpperCase(), 0, 5, true, false, true, false, false);
 		BusinessGroup group3 = businessGroupDao.createAndPersist(null, "fingbg-3", "desc-" + marker + "-desc", 0, 5, true, false, true, false, false);
@@ -621,7 +608,9 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		Assert.assertTrue(groups.contains(group3));
 		
 		//check the same search with the views
-		List<BusinessGroupView> groupViews = businessGroupDao.findBusinessGroupViews(params, null, 0, -1);
+		BusinessGroupQueryParams searchParams = new BusinessGroupQueryParams();
+		searchParams.setNameOrDesc("*" + marker + "*");
+		List<BusinessGroupRow> groupViews = businessGroupDao.searchBusinessGroupsWithMemberships(searchParams, identity);
 		Assert.assertNotNull(groupViews);
 		Assert.assertEquals(3, groupViews.size() );
 		Assert.assertTrue(contains(groupViews, group1));
@@ -641,18 +630,11 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		BusinessGroup group2 = businessGroupDao.createAndPersist(id2, "fingbgown-2", "fingbgown-2-desc", 0, 5, true, false, true, false, false);
 		BusinessGroup group3 = businessGroupDao.createAndPersist(id3, "fingbgown-3", "fingbgown-3-desc", 0, 5, true, false, true, false, false);
 		dbInstance.commitAndCloseSession();
-
-		SearchBusinessGroupParams params = new SearchBusinessGroupParams();
-		params.setOwnerName(marker);
-		List<BusinessGroup> groups = businessGroupDao.findBusinessGroups(params, null, 0, -1);
-		Assert.assertNotNull(groups);
-		Assert.assertEquals(2, groups.size() );
-		Assert.assertTrue(groups.contains(group1));
-		Assert.assertFalse(groups.contains(group2));
-		Assert.assertTrue(groups.contains(group3));
 		
 		//check the same with the views
-		List<BusinessGroupView> groupViews = businessGroupDao.findBusinessGroupViews(params, null, 0, -1);
+		BusinessGroupQueryParams searchParams = new BusinessGroupQueryParams();
+		searchParams.setOwnerName(marker);
+		List<BusinessGroupRow> groupViews = businessGroupDao.searchBusinessGroupsWithMemberships(searchParams, id1);
 		Assert.assertNotNull(groupViews);
 		Assert.assertEquals(2, groupViews.size() );
 		Assert.assertTrue(contains(groupViews, group1));
@@ -671,18 +653,11 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		BusinessGroup group2 = businessGroupDao.createAndPersist(id2, "fingbg-own-1-2", "fingbg-own-1-2-desc", 0, 5, true, false, true, false, false);
 		BusinessGroup group3 = businessGroupDao.createAndPersist(id3, "fingbg-own-1-3", "fingbg-own-1-3-desc", 0, 5, true, false, true, false, false);
 		dbInstance.commitAndCloseSession();
-
-		SearchBusinessGroupParams params = new SearchBusinessGroupParams();
-		params.setOwnerName("*" + marker + "*");
-		List<BusinessGroup> groups = businessGroupDao.findBusinessGroups(params, null, 0, -1);
-		Assert.assertNotNull(groups);
-		Assert.assertEquals(3, groups.size() );
-		Assert.assertTrue(groups.contains(group1));
-		Assert.assertTrue(groups.contains(group2));
-		Assert.assertTrue(groups.contains(group3));
 		
 		//check the same with the views
-		List<BusinessGroupView> groupViews = businessGroupDao.findBusinessGroupViews(params, null, 0, -1);
+		BusinessGroupQueryParams searchParams = new BusinessGroupQueryParams();
+		searchParams.setOwnerName("*" + marker + "*");
+		List<BusinessGroupRow> groupViews = businessGroupDao.searchBusinessGroupsWithMemberships(searchParams, id1);
 		Assert.assertNotNull(groupViews);
 		Assert.assertEquals(3, groupViews.size() );
 		Assert.assertTrue(contains(groupViews, group1));
@@ -690,6 +665,35 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		Assert.assertTrue(contains(groupViews, group3));
 	}
 	
+	@Test
+	public void findBusinessGroupWithAuthorConnection() {
+		Identity author = JunitTestHelper.createAndPersistIdentityAsUser("bdao-5-" + UUID.randomUUID().toString());
+		RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry();
+		repositoryEntryRelationDao.addRole(author, re, GroupRoles.owner.name());
+		
+		BusinessGroup group1 = businessGroupDao.createAndPersist(null, "gdlo", "gdlo-desc", 0, 5, true, false, false, false, false);
+		BusinessGroup group2 = businessGroupDao.createAndPersist(author, "gdmo", "gdmo-desc", 0, 5, true, false, false, false, false);
+		BusinessGroup group3 = businessGroupDao.createAndPersist(author, "gdmo", "gdmo-desc", 0, 5, true, false, false, false, false);
+		businessGroupRelationDao.addRelationToResource(group1, re);
+		businessGroupRelationDao.addRelationToResource(group3, re);
+		dbInstance.commitAndCloseSession();
+		
+		//check 
+		BusinessGroupQueryParams params = new BusinessGroupQueryParams();
+		params.setAuthorConnection(true);
+		List<StatisticsBusinessGroupRow> groups = businessGroupDao.searchBusinessGroupsForSelection(params, author);
+		Assert.assertNotNull(groups);
+		Assert.assertEquals(2, groups.size());
+		
+		Set<Long> retrievedGroupkey = new HashSet<Long>();
+		for(StatisticsBusinessGroupRow group:groups) {
+			retrievedGroupkey.add(group.getKey());
+		}
+		Assert.assertTrue(retrievedGroupkey.contains(group1.getKey()));
+		Assert.assertTrue(retrievedGroupkey.contains(group3.getKey()));
+		Assert.assertFalse(retrievedGroupkey.contains(group2.getKey()));
+	}
+	
 	@Test
 	public void findBusinessGroupsByIdentity() {
 		Identity id = JunitTestHelper.createAndPersistIdentityAsUser("is-in-grp-" + UUID.randomUUID().toString());
@@ -744,25 +748,35 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		
 		//The same tests with the views
 		//check owner on views
-		List<BusinessGroupView> ownedGroupViews = businessGroupDao.findBusinessGroupViews(paramsOwner, null, 0, 0);
+		BusinessGroupQueryParams queryParamsOwner = new BusinessGroupQueryParams();
+		queryParamsOwner.setOwner(true);
+		List<BusinessGroupRow> ownedGroupViews = businessGroupDao.searchBusinessGroupsWithMemberships(queryParamsOwner, id);
 		Assert.assertNotNull(ownedGroupViews);
 		Assert.assertEquals(1, ownedGroupViews.size());
 		Assert.assertTrue(contains(ownedGroupViews, group1));
 		
 		//check attendee on views
-		List<BusinessGroupView> attendeeGroupViews = businessGroupDao.findBusinessGroupViews(paramsAttendee, null, 0, 0);
+		BusinessGroupQueryParams queryParamsAttendee = new BusinessGroupQueryParams();
+		queryParamsAttendee.setAttendee(true);
+		List<BusinessGroupRow> attendeeGroupViews = businessGroupDao.searchBusinessGroupsWithMemberships(queryParamsAttendee, id);
 		Assert.assertNotNull(attendeeGroupViews);
 		Assert.assertEquals(1, attendeeGroupViews.size());
 		Assert.assertTrue(contains(attendeeGroupViews, group2));
 
 		//check waiting on views
-		List<BusinessGroupView> waitingGroupViews = businessGroupDao.findBusinessGroupViews(paramsWaiting, null, 0, 0);
+		BusinessGroupQueryParams queryParamsWaiting = new BusinessGroupQueryParams();
+		queryParamsWaiting.setWaiting(true);
+		List<BusinessGroupRow> waitingGroupViews = businessGroupDao.searchBusinessGroupsWithMemberships(queryParamsWaiting, id);
 		Assert.assertNotNull(waitingGroupViews);
 		Assert.assertEquals(1, waitingGroupViews.size());
 		Assert.assertTrue(contains(waitingGroupViews, group3));
 		
 		//check all on views
-		List<BusinessGroupView> allGroupViews = businessGroupDao.findBusinessGroupViews(paramsAll, null, 0, 0);
+		BusinessGroupQueryParams queryParamsAll = new BusinessGroupQueryParams();
+		queryParamsAll.setOwner(true);
+		queryParamsAll.setAttendee(true);
+		queryParamsAll.setWaiting(true);
+		List<BusinessGroupRow> allGroupViews = businessGroupDao.searchBusinessGroupsWithMemberships(queryParamsAll, id);
 		Assert.assertNotNull(allGroupViews);
 		Assert.assertEquals(3, allGroupViews.size());
 		Assert.assertTrue(contains(allGroupViews, group1));
@@ -781,17 +795,18 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		dbInstance.commitAndCloseSession();
 
 		//retrieve the group through its relation
-		SearchBusinessGroupParams params = new SearchBusinessGroupParams();
-		params.setIdentity(id);
+		BusinessGroupQueryParams params = new BusinessGroupQueryParams();
 		params.setOwner(true);
 		params.setAttendee(true);
 		params.setWaiting(true);
-		List<BusinessGroupView> groupViews = businessGroupDao.findBusinessGroupViews(params, re, 0, -1);
+		params.setRepositoryEntry(re);
+		List<BusinessGroupRow> groupViews =  businessGroupDao.searchBusinessGroupsWithMemberships(params, id);
 		Assert.assertNotNull(groupViews);
 		Assert.assertEquals(1, groupViews.size());
 		Assert.assertEquals(group.getKey(), groupViews.get(0).getKey());
 	}
 	
+
 	@Test
 	public void findBusinessGroupsByCourseTitle() {
 		//create a repository entry with a relation to a group
@@ -803,13 +818,12 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		dbInstance.commitAndCloseSession();
 
 		//retrieve the group through its relation
-		SearchBusinessGroupParams params = new SearchBusinessGroupParams();
-		params.setIdentity(id);
+		BusinessGroupQueryParams params = new BusinessGroupQueryParams();
 		params.setOwner(true);
 		params.setAttendee(true);
 		params.setWaiting(true);
 		params.setCourseTitle(re.getDisplayname());
-		List<BusinessGroupView> groupViews = businessGroupDao.findBusinessGroupViews(params, null, 0, -1);
+		List<BusinessGroupRow> groupViews = businessGroupDao.searchBusinessGroupsWithMemberships(params, id);
 		Assert.assertNotNull(groupViews);
 		Assert.assertEquals(1, groupViews.size());
 		Assert.assertEquals(group.getKey(), groupViews.get(0).getKey());
@@ -863,10 +877,11 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		Assert.assertEquals(1, groups.size());
 		Assert.assertTrue(groups.contains(group));
 	}
-	
+
 	@Test
 	public void findPublicGroups() {
 		//create a group with an access control
+		Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("bg-search-11");
 		BusinessGroup group = businessGroupDao.createAndPersist(null, "access-grp-1", "access-grp-1-desc", 0, 5, true, false, true, false, false);
 		//create and save an offer
 		Offer offer = acService.createOffer(group.getResource(), "TestBGWorkflow");
@@ -876,27 +891,17 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		dbInstance.commitAndCloseSession();
 			
 		//retrieve the offer
-		SearchBusinessGroupParams paramsAll = new SearchBusinessGroupParams();
-		paramsAll.setPublicGroups(Boolean.TRUE);
-		List<BusinessGroup> accessGroups = businessGroupDao.findBusinessGroups(paramsAll, null, 0, 0);
-		Assert.assertNotNull(accessGroups);
-		Assert.assertTrue(accessGroups.size() >= 1);
-		Assert.assertTrue(accessGroups.contains(group));
-		
-		for(BusinessGroup accessGroup:accessGroups) {
-			List<Offer> offers = acService.findOfferByResource(accessGroup.getResource(), true, new Date());
-			Assert.assertNotNull(offers);
-			Assert.assertFalse(offers.isEmpty());
-		}
-		
 		//check the search with the views
-		List<BusinessGroupView> accessGroupViews = businessGroupDao.findBusinessGroupViews(paramsAll, null, 0, 0);
+		BusinessGroupQueryParams queryAllParams = new BusinessGroupQueryParams();
+		queryAllParams.setPublicGroups(Boolean.TRUE);
+		List<OpenBusinessGroupRow> accessGroupViews = businessGroupDao.searchPublishedBusinessGroups(queryAllParams, identity);
 		Assert.assertNotNull(accessGroupViews);
 		Assert.assertTrue(accessGroupViews.size() >= 1);
 		Assert.assertTrue(contains(accessGroupViews, group));
 		
-		for(BusinessGroupView accessGroup:accessGroupViews) {
-			List<Offer> offers = acService.findOfferByResource(accessGroup.getResource(), true, new Date());
+		for(OpenBusinessGroupRow accessGroup:accessGroupViews) {
+			OLATResource resource = resourceManager.findResourceById(accessGroup.getResourceKey());
+			List<Offer> offers = acService.findOfferByResource(resource, true, new Date());
 			Assert.assertNotNull(offers);
 			Assert.assertFalse(offers.isEmpty());
 		}
@@ -905,6 +910,7 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 	@Test
 	public void findPublicGroupsLimitedDate() {
 		//create a group with an access control limited by a valid date
+		Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("bg-search-11");
 		BusinessGroup groupVisible = businessGroupDao.createAndPersist(null, "access-grp-2", "access-grp-2-desc", 0, 5, true, false, true, false, false);
 		//create and save an offer
 		Offer offer = acService.createOffer(groupVisible.getResource(), "TestBGWorkflow");
@@ -931,50 +937,39 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		dbInstance.commitAndCloseSession();
 			
 		//retrieve the offer
-		SearchBusinessGroupParams paramsAll = new SearchBusinessGroupParams();
+		BusinessGroupQueryParams paramsAll = new BusinessGroupQueryParams();
 		paramsAll.setPublicGroups(Boolean.TRUE);
-		List<BusinessGroup> accessGroups = businessGroupDao.findBusinessGroups(paramsAll, null, 0, 0);
+		List<BusinessGroupRow> accessGroups = businessGroupDao.searchBusinessGroupsWithMemberships(paramsAll, id);
 		Assert.assertNotNull(accessGroups);
 		Assert.assertTrue(accessGroups.size() >= 1);
-		Assert.assertTrue(accessGroups.contains(groupVisible));
-		Assert.assertFalse(accessGroups.contains(oldGroup));
+		Assert.assertTrue(contains(accessGroups, groupVisible));
+		Assert.assertFalse(contains(accessGroups, oldGroup));
 	}	
-	
+
 	@Test
 	public void findBusinessGroupsWithResources() {
 		//create a group attach to a resource
-		Identity owner = JunitTestHelper.createAndPersistIdentityAsUser("marker-" + UUID.randomUUID().toString());
+		Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("bg-search-10");
+		Identity owner = JunitTestHelper.createAndPersistIdentityAsRndUser("marker-");
 		RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry();
 		BusinessGroup group1 = businessGroupDao.createAndPersist(owner, "rsrc-grp-1", "rsrc-grp-1-desc", 0, 5, true, false, true, false, false);
 		BusinessGroup group2 = businessGroupDao.createAndPersist(owner, "rsrc-grp-2", "rsrc-grp-2-desc", 0, 5, true, false, true, false, false);
 		businessGroupRelationDao.addRelationToResource(group1, re);
 		dbInstance.commitAndCloseSession();
-		
-		//check the search function with resources
-		SearchBusinessGroupParams paramsWith = new SearchBusinessGroupParams();
-		paramsWith.setResources(Boolean.TRUE);
-		List<BusinessGroup> groupWith = businessGroupDao.findBusinessGroups(paramsWith, null, 0, 0);
-		Assert.assertNotNull(groupWith);
-		Assert.assertFalse(groupWith.isEmpty());
-		Assert.assertTrue(groupWith.contains(group1));
-
-		//check the search function without resources
-		SearchBusinessGroupParams paramsWithout = new SearchBusinessGroupParams();
-		paramsWithout.setResources(Boolean.FALSE);
-		List<BusinessGroup> groupWithout = businessGroupDao.findBusinessGroups(paramsWithout, null, 0, 0);
-		Assert.assertNotNull(groupWithout);
-		Assert.assertFalse(groupWithout.isEmpty());
-		Assert.assertTrue(groupWithout.contains(group2));
 
 		//check the same with the views
 		//check the search function with resources
-		List<BusinessGroupView> groupViewWith = businessGroupDao.findBusinessGroupViews(paramsWith, null, 0, 0);
+		BusinessGroupQueryParams queryWithParams = new BusinessGroupQueryParams();
+		queryWithParams.setResources(Boolean.TRUE);
+		List<BusinessGroupRow> groupViewWith = businessGroupDao.searchBusinessGroupsWithMemberships(queryWithParams, id);
 		Assert.assertNotNull(groupViewWith);
 		Assert.assertFalse(groupViewWith.isEmpty());
 		Assert.assertTrue(contains(groupViewWith, group1));
 
 		//check the search function without resources
-		List<BusinessGroupView> groupViewWithout = businessGroupDao.findBusinessGroupViews(paramsWithout, null, 0, 0);
+		BusinessGroupQueryParams queryWithoutParams = new BusinessGroupQueryParams();
+		queryWithoutParams.setResources(Boolean.FALSE);
+		List<BusinessGroupRow> groupViewWithout = businessGroupDao.searchBusinessGroupsWithMemberships(queryWithoutParams, id);
 		Assert.assertNotNull(groupViewWithout);
 		Assert.assertFalse(groupViewWithout.isEmpty());
 		Assert.assertTrue(contains(groupViewWithout, group2));
@@ -989,39 +984,18 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		markManager.setMark(group1.getResource(), marker, null, "[BusinessGroup:" + group1.getKey() + "]");
 		dbInstance.commitAndCloseSession();
 		
-		//check marked
-		SearchBusinessGroupParams paramsAll = new SearchBusinessGroupParams();
-		paramsAll.setIdentity(marker);
-		paramsAll.setMarked(Boolean.TRUE);
-		List<BusinessGroup> markedGroups = businessGroupDao.findBusinessGroups(paramsAll, null, 0, 0);
-		Assert.assertNotNull(markedGroups);
-		Assert.assertEquals(1, markedGroups.size());
-		Assert.assertTrue(markedGroups.contains(group1));
-		
-		//check not marked
-		SearchBusinessGroupParams paramsNotMarked = new SearchBusinessGroupParams();
-		paramsNotMarked.setIdentity(marker);
-		paramsNotMarked.setOwner(true);
-		paramsNotMarked.setMarked(Boolean.FALSE);
-		List<BusinessGroup> notMarkedGroups = businessGroupDao.findBusinessGroups(paramsNotMarked, null, 0, 0);
-		Assert.assertNotNull(notMarkedGroups);
-		Assert.assertEquals(1, notMarkedGroups.size());
-		Assert.assertTrue(notMarkedGroups.contains(group2));
-		
 		//check the search with the views
 		//check marked
-		List<BusinessGroupView> markedGroupViews = businessGroupDao.findBusinessGroupViews(paramsAll, null, 0, 0);
+		BusinessGroupQueryParams queryMarkedParams = new BusinessGroupQueryParams();
+		queryMarkedParams.setOwner(true);
+		queryMarkedParams.setMarked(true);
+		List<BusinessGroupRow> markedGroupViews = businessGroupDao.searchBusinessGroupsWithMemberships(queryMarkedParams, marker);
 		Assert.assertNotNull(markedGroupViews);
 		Assert.assertEquals(1, markedGroupViews.size());
 		Assert.assertTrue(contains(markedGroupViews, group1));
-		
-		//check not marked
-		List<BusinessGroupView> notMarkedGroupViews = businessGroupDao.findBusinessGroupViews(paramsNotMarked, null, 0, 0);
-		Assert.assertNotNull(notMarkedGroupViews);
-		Assert.assertEquals(1, notMarkedGroupViews.size());
-		Assert.assertTrue(contains(notMarkedGroupViews, group2));
+		Assert.assertFalse(contains(markedGroupViews, group2));
 	}
-	
+
 	@Test
 	public void findMarkedBusinessGroupCrossContamination() {
 		Identity marker1 = JunitTestHelper.createAndPersistIdentityAsUser("marker-1-" + UUID.randomUUID().toString());
@@ -1033,36 +1007,14 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		markManager.setMark(group2.getResource(), marker2, null, "[BusinessGroup:" + group2.getKey() + "]");
 		dbInstance.commitAndCloseSession();
 		
-		//check marked
-		SearchBusinessGroupParams paramsMarker1 = new SearchBusinessGroupParams();
-		paramsMarker1.setIdentity(marker1);
-		paramsMarker1.setMarked(Boolean.TRUE);
-		List<BusinessGroup> markedGroups = businessGroupDao.findBusinessGroups(paramsMarker1, null, 0, 0);
-		Assert.assertNotNull(markedGroups);
-		Assert.assertEquals(1, markedGroups.size());
-		Assert.assertTrue(markedGroups.contains(group1));
-		
-		//check not marked
-		SearchBusinessGroupParams paramsMarker2 = new SearchBusinessGroupParams();
-		paramsMarker2.setIdentity(marker2);
-		paramsMarker2.setMarked(Boolean.TRUE);
-		List<BusinessGroup> markedGroups2 = businessGroupDao.findBusinessGroups(paramsMarker2, null, 0, 0);
-		Assert.assertNotNull(markedGroups2);
-		Assert.assertEquals(1, markedGroups2.size());
-		Assert.assertTrue(markedGroups2.contains(group2));
-		
 		//check the search with views
 		//check marked
-		List<BusinessGroupView> markedGroupViews = businessGroupDao.findBusinessGroupViews(paramsMarker1, null, 0, 0);
+		BusinessGroupQueryParams queryParamsMarker1 = new BusinessGroupQueryParams();
+		queryParamsMarker1.setMarked(true);
+		List<BusinessGroupRow> markedGroupViews = businessGroupDao.searchBusinessGroupsWithMemberships(queryParamsMarker1, marker1);
 		Assert.assertNotNull(markedGroupViews);
 		Assert.assertEquals(1, markedGroupViews.size());
 		Assert.assertTrue(contains(markedGroupViews, group1));
-		
-		//check not marked
-		List<BusinessGroupView> markedGroupsView2 = businessGroupDao.findBusinessGroupViews(paramsMarker2, null, 0, 0);
-		Assert.assertNotNull(markedGroupsView2);
-		Assert.assertEquals(1, markedGroupsView2.size());
-		Assert.assertTrue(contains(markedGroupsView2, group2));
 	}
 	
 	@Test
@@ -1073,9 +1025,9 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		dbInstance.commitAndCloseSession();
 		
 		//check marked
-		SearchBusinessGroupParams headlessParams = new SearchBusinessGroupParams();
+		BusinessGroupQueryParams headlessParams = new BusinessGroupQueryParams();
 		headlessParams.setHeadless(true);
-		List<BusinessGroupView> groups = businessGroupDao.findBusinessGroupViews(headlessParams, null, 0, 0);
+		List<BusinessGroupRow> groups = businessGroupDao.searchBusinessGroupsWithMemberships(headlessParams, owner);
 		Assert.assertNotNull(groups);
 		Assert.assertFalse(groups.isEmpty());
 		Assert.assertTrue(contains(groups, headlessGroup));
@@ -1103,96 +1055,6 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		Assert.assertFalse(originalKeys.contains(group3.getKey()));
 	}
 	
-	@Test
-	public void findBusinessGroupsNumOfMembers() {
-		Identity owner = JunitTestHelper.createAndPersistIdentityAsUser("head-1-" + UUID.randomUUID().toString());
-		Identity part1 = JunitTestHelper.createAndPersistIdentityAsUser("head-1-" + UUID.randomUUID().toString());
-		Identity part2 = JunitTestHelper.createAndPersistIdentityAsUser("head-1-" + UUID.randomUUID().toString());
-		BusinessGroup groupWith1 = businessGroupDao.createAndPersist(owner, "headless-grp", "headless-grp-desc", 0, 5, true, false, true, false, false);
-		BusinessGroup groupWith3 = businessGroupDao.createAndPersist(owner, "headed-grp", "headed-grp-desc", 0, 5, true, false, true, false, false);
-		businessGroupRelationDao.addRole(part1, groupWith3, GroupRoles.participant.name());
-		businessGroupRelationDao.addRole(part2, groupWith3, GroupRoles.participant.name());
-		dbInstance.commitAndCloseSession();
-		
-		//check groups with more than 2 members
-		SearchBusinessGroupParams paramsWithMoreThan2 = new SearchBusinessGroupParams();
-		paramsWithMoreThan2.setNumOfMembers(2);
-		paramsWithMoreThan2.setNumOfMembersBigger(true);
-		List<BusinessGroupView> groupsWithMoreThan2 = businessGroupDao.findBusinessGroupViews(paramsWithMoreThan2, null, 0, 0);
-		Assert.assertNotNull(groupsWithMoreThan2);
-		Assert.assertFalse(groupsWithMoreThan2.isEmpty());
-		Assert.assertTrue(contains(groupsWithMoreThan2, groupWith3));
-		Assert.assertFalse(contains(groupsWithMoreThan2, groupWith1));
-		
-		//check groups with more than 2 members
-		SearchBusinessGroupParams paramsWithLessThan2 = new SearchBusinessGroupParams();
-		paramsWithLessThan2.setNumOfMembers(2);
-		paramsWithLessThan2.setNumOfMembersBigger(false);
-		List<BusinessGroupView> groupsWithLessThan2 = businessGroupDao.findBusinessGroupViews(paramsWithLessThan2, null, 0, 0);
-		Assert.assertNotNull(groupsWithLessThan2);
-		Assert.assertFalse(groupsWithLessThan2.isEmpty());
-		Assert.assertTrue(contains(groupsWithLessThan2, groupWith1));
-		Assert.assertFalse(contains(groupsWithLessThan2, groupWith3));
-	}
-	
-	
-	@Test
-	public void findBusinessGroupOrdered() {
-		BusinessGroup group1 = businessGroupDao.createAndPersist(null, "a_ordered-grp-3", "marked-grp-1-desc", 0, 5, true, false, true, false, false);
-		BusinessGroup group2 = businessGroupDao.createAndPersist(null, "z_ordered-grp-4", "marked-grp-2-desc", 0, 5, true, false, true, false, false);
-		dbInstance.commitAndCloseSession();
-		
-		//check the query order by name
-		SearchBusinessGroupParams params = new SearchBusinessGroupParams();
-		List<BusinessGroup> orderedByName = businessGroupDao.findBusinessGroups(params, null, 0, 0, BusinessGroupOrder.nameAsc);
-		Assert.assertNotNull(orderedByName);
-		Assert.assertFalse(orderedByName.isEmpty());
-		int index1 = orderedByName.indexOf(group1);
-		int index2 = orderedByName.indexOf(group2);
-		Assert.assertTrue(index1 < index2);
-
-		//check the query order by creation date
-		List<BusinessGroup> orderedByCreationDate = businessGroupDao.findBusinessGroups(params, null, 0, 0, BusinessGroupOrder.creationDateAsc);
-		Assert.assertNotNull(orderedByCreationDate);
-		Assert.assertFalse(orderedByCreationDate.isEmpty());
-		int index3 = orderedByCreationDate.indexOf(group1);
-		int index4 = orderedByCreationDate.indexOf(group2);
-		Assert.assertTrue(index3 < index4);
-		
-		//check the query order by creation date
-		List<BusinessGroup> orderedBy = businessGroupDao.findBusinessGroups(params, null, 0, 0, BusinessGroupOrder.nameAsc, BusinessGroupOrder.creationDateDesc);
-		Assert.assertNotNull(orderedBy);
-		Assert.assertFalse(orderedBy.isEmpty());
-		int index5 = orderedBy.indexOf(group1);
-		int index6 = orderedBy.indexOf(group2);
-		Assert.assertTrue(index5 < index6);
-		
-		//The find views must return exactly the same results
-		//views: check the query order by name
-		List<BusinessGroupView> orderedViewByName = businessGroupDao.findBusinessGroupViews(params, null, 0, 0, BusinessGroupOrder.nameAsc);
-		Assert.assertNotNull(orderedViewByName);
-		Assert.assertFalse(orderedViewByName.isEmpty());
-		int indexView1 = indexOf(orderedViewByName, group1);
-		int indexView2 = indexOf(orderedViewByName, group2);
-		Assert.assertTrue(indexView1 < indexView2);
-
-		//check the query order by creation date
-		List<BusinessGroupView> orderedViewByCreationDate = businessGroupDao.findBusinessGroupViews(params, null, 0, 0, BusinessGroupOrder.creationDateAsc);
-		Assert.assertNotNull(orderedViewByCreationDate);
-		Assert.assertFalse(orderedViewByCreationDate.isEmpty());
-		int indexView3 = indexOf(orderedViewByCreationDate, group1);
-		int indexView4 = indexOf(orderedViewByCreationDate, group2);
-		Assert.assertTrue(indexView3 < indexView4);
-		
-		//check the query order by creation date
-		List<BusinessGroupView> orderedViewBy = businessGroupDao.findBusinessGroupViews(params, null, 0, 0, BusinessGroupOrder.nameAsc, BusinessGroupOrder.creationDateDesc);
-		Assert.assertNotNull(orderedViewBy);
-		Assert.assertFalse(orderedViewBy.isEmpty());
-		int indexView5 = indexOf(orderedViewBy, group1);
-		int indexView6 = indexOf(orderedViewBy, group2);
-		Assert.assertTrue(indexView5 < indexView6);
-	}
-	
 	@Test
 	public void isIdentityInBusinessGroups() {
 		Identity id = JunitTestHelper.createAndPersistIdentityAsUser("is-in-grp-" + UUID.randomUUID().toString());
@@ -1365,27 +1227,14 @@ public class BusinessGroupDAOTest extends OlatTestCase {
 		}
 	}
 	
-	private boolean contains(List<BusinessGroupView> views, BusinessGroup group) {
-		if(views != null && !views.isEmpty()) {
-			for(BusinessGroupView view:views) {
-				if(view.getKey().equals(group.getKey())) {
+	private boolean contains(List<? extends BusinessGroupRef> rows, BusinessGroup group) {
+		if(rows != null && !rows.isEmpty()) {
+			for(BusinessGroupRef row:rows) {
+				if(row.getKey().equals(group.getKey())) {
 					return true; 
 				}
 			}
 		}
 		return false;
 	}
-	
-	private int indexOf(List<BusinessGroupView> views, BusinessGroup group) {
-		int index = -1;
-		if(views != null && !views.isEmpty()) {
-			for(BusinessGroupView view:views) {
-				index++;
-				if(view.getKey().equals(group.getKey())) {
-					break; 
-				}
-			}
-		}
-		return index;
-	}
 }
diff --git a/src/test/java/org/olat/group/test/BusinessGroupServiceTest.java b/src/test/java/org/olat/group/test/BusinessGroupServiceTest.java
index 702989ae63aea7191ade77005e834d37b70988c9..5c8e9db31c1d7c91ae32f764b3ac4e5fda5614a0 100644
--- a/src/test/java/org/olat/group/test/BusinessGroupServiceTest.java
+++ b/src/test/java/org/olat/group/test/BusinessGroupServiceTest.java
@@ -474,10 +474,10 @@ public class BusinessGroupServiceTest extends OlatTestCase {
 		Identity ident2 = JunitTestHelper.createAndPersistIdentityAsUser("move-w1-2-" + UUID.randomUUID().toString());
 		Identity ident3 = JunitTestHelper.createAndPersistIdentityAsUser("move-w1-3-" + UUID.randomUUID().toString());
 		BusinessGroup group = businessGroupService.createBusinessGroup(null, "move-bg-1", "move-desc", 0, 10, true, false, null);
+		dbInstance.commitAndCloseSession();
 		businessGroupService.addToWaitingList(admin, Collections.singletonList(ident1), group, null);
 		businessGroupService.addToWaitingList(admin, Collections.singletonList(ident2), group, null);
 		businessGroupService.addParticipants(admin, JunitTestHelper.getAdminRoles(), Collections.singletonList(ident3), group, null);
-		
 		dbInstance.commitAndCloseSession();
 		
 		//move id1 from waiting-list to participant
@@ -501,6 +501,7 @@ public class BusinessGroupServiceTest extends OlatTestCase {
 		Identity ident2 = JunitTestHelper.createAndPersistIdentityAsUser("move-w2-2-" + UUID.randomUUID().toString());
 		Identity ident3 = JunitTestHelper.createAndPersistIdentityAsUser("move-w2-3-" + UUID.randomUUID().toString());
 		BusinessGroup group = businessGroupService.createBusinessGroup(null, "move-bg-1", "move-desc", 0, 10, true, false, null);
+		dbInstance.commitAndCloseSession();
 		//add id1
 		businessGroupService.addToWaitingList(ident1, Collections.singletonList(ident1), group, null);
 		dbInstance.commitAndCloseSession();
@@ -534,6 +535,7 @@ public class BusinessGroupServiceTest extends OlatTestCase {
 		Identity ident2 = JunitTestHelper.createAndPersistIdentityAsUser("move-w3-2-" + UUID.randomUUID().toString());
 		Identity ident3 = JunitTestHelper.createAndPersistIdentityAsUser("move-w3-3-" + UUID.randomUUID().toString());
 		BusinessGroup group = businessGroupService.createBusinessGroup(null, "move-bg-3", "move-desc", 0, 10, true, false, null);
+		dbInstance.commitAndCloseSession();
 		businessGroupService.addToWaitingList(ident1, Collections.singletonList(ident1), group, null);
 		businessGroupService.addToWaitingList(ident2, Collections.singletonList(ident2), group, null);
 		businessGroupService.addToWaitingList(ident3, Collections.singletonList(ident3), group, null);
@@ -632,6 +634,7 @@ public class BusinessGroupServiceTest extends OlatTestCase {
 		Identity ident1 = JunitTestHelper.createAndPersistIdentityAsUser("move-w4-1-" + UUID.randomUUID().toString());
 		Roles rolesId1 = securityManager.getRoles(ident1);
 		BusinessGroup group = businessGroupService.createBusinessGroup(null, "move-bg-4", "move-desc", 0, 10, true, false, null);
+		dbInstance.commitAndCloseSession();
 		businessGroupService.addParticipants(ident1, rolesId1, Collections.singletonList(ident1), group, null);
 		dbInstance.commitAndCloseSession();
 
@@ -657,6 +660,7 @@ public class BusinessGroupServiceTest extends OlatTestCase {
 		Identity ident2 = JunitTestHelper.createAndPersistIdentityAsUser("move-w5-2-" + UUID.randomUUID().toString());;
 		Roles rolesId1 = securityManager.getRoles(ident1);
 		BusinessGroup group = businessGroupService.createBusinessGroup(null, "move-bg-5", "move-desc", 0, 1, true, true, null);
+		dbInstance.commitAndCloseSession();
 		businessGroupService.addParticipants(ident1, rolesId1, Collections.singletonList(ident1), group, null);
 		businessGroupService.addToWaitingList(ident2, Collections.singletonList(ident2), group, null);
 		dbInstance.commitAndCloseSession();
diff --git a/src/test/java/org/olat/restapi/ContactsTest.java b/src/test/java/org/olat/restapi/ContactsTest.java
index f82d9dd7baccb4eb56a3c8f15e4973d395553f34..c7c716dde9e0d1bbaaf136d2bbed7ef7fa30576d 100644
--- a/src/test/java/org/olat/restapi/ContactsTest.java
+++ b/src/test/java/org/olat/restapi/ContactsTest.java
@@ -97,38 +97,41 @@ public class ContactsTest extends OlatJerseyTestCase {
 		// create groups without waiting list
 		g1 = businessGroupService.createBusinessGroup(null, "rest-g1", null, 0, 10, false, false, c1);
 		g2 = businessGroupService.createBusinessGroup(null, "rest-g2", null, 0, 10, false, false, c1);
+		DBFactory.getInstance().commit();
     
 		//permission to see owners and participants
 		businessGroupService.updateDisplayMembers(g1, false, false, false, false, false, false, false);
 		businessGroupService.updateDisplayMembers(g2, true, true, false, false, false, false, false);
     
 		// members g1
-	businessGroupRelationDao.addRole(owner1, g1, GroupRoles.coach.name());
-	businessGroupRelationDao.addRole(owner2, g1, GroupRoles.coach.name());
-	businessGroupRelationDao.addRole(part1, g1, GroupRoles.participant.name());
-	businessGroupRelationDao.addRole(part2, g1, GroupRoles.participant.name());
+		businessGroupRelationDao.addRole(owner1, g1, GroupRoles.coach.name());
+		businessGroupRelationDao.addRole(owner2, g1, GroupRoles.coach.name());
+		businessGroupRelationDao.addRole(part1, g1, GroupRoles.participant.name());
+		businessGroupRelationDao.addRole(part2, g1, GroupRoles.participant.name());
     
-    // members g2
-	businessGroupRelationDao.addRole(owner1, g2, GroupRoles.coach.name());
-	businessGroupRelationDao.addRole(part1, g2, GroupRoles.participant.name());
+		// members g2
+		businessGroupRelationDao.addRole(owner1, g2, GroupRoles.coach.name());
+		businessGroupRelationDao.addRole(part1, g2, GroupRoles.participant.name());
     
     
-    // 2) context two: right groups
+		// 2) context two: right groups
 		RepositoryEntry c2 =  JunitTestHelper.createAndPersistRepositoryEntry();
-    // groups
-    g3 = businessGroupService.createBusinessGroup(null, "rest-g3", null, -1, -1, false, false, c2);
-    businessGroupService.updateDisplayMembers(g3, false, true, false, false, false, false, false);
-    g4 = businessGroupService.createBusinessGroup(null, "rest-g4", null, -1, -1, false, false, c2);
-    businessGroupService.updateDisplayMembers(g4, false, true, false, false, false, false, false);
-    // members -> default participants are visible
-	businessGroupRelationDao.addRole(owner1, g3, GroupRoles.participant.name());
-	businessGroupRelationDao.addRole(part3, g3, GroupRoles.participant.name());
+		// groups
+		g3 = businessGroupService.createBusinessGroup(null, "rest-g3", null, -1, -1, false, false, c2);
+		g4 = businessGroupService.createBusinessGroup(null, "rest-g4", null, -1, -1, false, false, c2);
+		DBFactory.getInstance().commit();
+		
+		businessGroupService.updateDisplayMembers(g3, false, true, false, false, false, false, false);
+		businessGroupService.updateDisplayMembers(g4, false, true, false, false, false, false, false);
+		// members -> default participants are visible
+		businessGroupRelationDao.addRole(owner1, g3, GroupRoles.participant.name());
+		businessGroupRelationDao.addRole(part3, g3, GroupRoles.participant.name());
     
-	businessGroupRelationDao.addRole(owner2, g4, GroupRoles.participant.name());
-	businessGroupRelationDao.addRole(part3, g4, GroupRoles.participant.name());
+		businessGroupRelationDao.addRole(owner2, g4, GroupRoles.participant.name());
+		businessGroupRelationDao.addRole(part3, g4, GroupRoles.participant.name());
     
-    DBFactory.getInstance().commitAndCloseSession(); // simulate user clicks
-    initialized = true;
+		DBFactory.getInstance().commitAndCloseSession(); // simulate user clicks
+		initialized = true;
 	}
 	
 	@Test
diff --git a/src/test/java/org/olat/restapi/GroupFoldersTest.java b/src/test/java/org/olat/restapi/GroupFoldersTest.java
index 1eea4dad39bae54d5b3c164d2c5a385c8753e99e..041a7ca45e15cb3df9a89386ed51249b08a08ad1 100644
--- a/src/test/java/org/olat/restapi/GroupFoldersTest.java
+++ b/src/test/java/org/olat/restapi/GroupFoldersTest.java
@@ -133,6 +133,7 @@ public class GroupFoldersTest extends OlatJerseyTestCase {
 	    // create groups without waiting list
 	    g1 = businessGroupService.createBusinessGroup(null, "rest-g1", null, 0, 10, false, false, c1);
 	    g2 = businessGroupService.createBusinessGroup(null, "rest-g2", null, 0, 10, false, false, c1);
+	    DBFactory.getInstance().commitAndCloseSession();
 	    
 	    //permission to see owners and participants
 	    businessGroupService.updateDisplayMembers(g1, false, false, false, false, false, false, false);
@@ -147,8 +148,6 @@ public class GroupFoldersTest extends OlatJerseyTestCase {
 	    // members g2
 	    businessGroupRelationDao.addRole(owner1, g2, GroupRoles.coach.name());
 	    businessGroupRelationDao.addRole(part1, g2, GroupRoles.participant.name());
-	    
-	    DBFactory.getInstance().commitAndCloseSession(); // simulate user clicks
     
 	    //3) collaboration tools
 	    CollaborationTools collabTools1 = CollaborationToolsFactory.getInstance().getOrCreateCollaborationTools(g1);
diff --git a/src/test/java/org/olat/restapi/GroupMgmtTest.java b/src/test/java/org/olat/restapi/GroupMgmtTest.java
index 4dda70aa0a8c81cf10908f1c0293167626fbc204..4b47671f48a009ff999e672c7b93dd28dfb014b2 100644
--- a/src/test/java/org/olat/restapi/GroupMgmtTest.java
+++ b/src/test/java/org/olat/restapi/GroupMgmtTest.java
@@ -143,11 +143,11 @@ public class GroupMgmtTest extends OlatJerseyTestCase {
 		// create groups without waiting list
 		g1 = businessGroupService.createBusinessGroup(null, "rest-g1", null, 0, 10, false, false, c1);
 		g2 = businessGroupService.createBusinessGroup(null, "rest-g2", null, 0, 10, false, false, c1);
-    
+		DBFactory.getInstance().commit();
 		//permission to see owners and participants
 		businessGroupService.updateDisplayMembers(g1, false, false, false, false, false, false, false);
 		businessGroupService.updateDisplayMembers(g2, true, true, false, false, false, false, false);
-    
+		
 		// members g1
 		businessGroupRelationDao.addRole(owner1, g1, GroupRoles.coach.name());
 		businessGroupRelationDao.addRole(owner2, g1, GroupRoles.coach.name());
@@ -164,12 +164,11 @@ public class GroupMgmtTest extends OlatJerseyTestCase {
 		// groups
 		g3 = businessGroupService.createBusinessGroup(null, "rest-g3", null, -1, -1, false, false, c2);
 		g4 = businessGroupService.createBusinessGroup(null, "rest-g4", null, -1, -1, false, false, c2);
+		DBFactory.getInstance().commit();
 		// members
 		businessGroupRelationDao.addRole(owner1, g3, GroupRoles.participant.name());
 		businessGroupRelationDao.addRole(owner2, g4, GroupRoles.participant.name());
     
-		DBFactory.getInstance().closeSession(); // simulate user clicks
-    
 		//3) collaboration tools
 		CollaborationTools collabTools1 = CollaborationToolsFactory.getInstance().getOrCreateCollaborationTools(g1);
 		collabTools1.setToolEnabled(CollaborationTools.TOOL_FORUM, true);