Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Convert.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Convert.cs	(revision 12753)
+++ 	(revision )
@@ -1,363 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Data.Linq;
-using System.Linq;
-using DT = HeuristicLab.Services.Hive.Common.DataTransfer;
-
-namespace HeuristicLab.Services.Hive.DataAccess {
-  public static class Convert {
-    #region Job
-    public static DT.Job ToDto(Job source) {
-      if (source == null) return null;
-      return new DT.Job {
-        Id = source.JobId,
-        CoresNeeded = source.CoresNeeded,
-        ExecutionTime = TimeSpan.FromMilliseconds(source.ExecutionTimeMs),
-        MemoryNeeded = source.MemoryNeeded,
-        ParentJobId = source.ParentJobId,
-        Priority = source.Priority,
-        PluginsNeededIds = (source.RequiredPlugins == null ? new List<Guid>() : source.RequiredPlugins.Select(x => x.PluginId).ToList()),
-        LastHeartbeat = source.LastHeartbeat,
-        State = source.State,
-        StateLog = (source.StateLogs == null ? new List<DT.StateLog>() : source.StateLogs.Select(x => Convert.ToDto(x)).OrderBy(x => x.DateTime).ToList()),
-        IsParentJob = source.IsParentJob,
-        FinishWhenChildJobsFinished = source.FinishWhenChildJobsFinished,
-        Command = source.Command,
-        LastJobDataUpdate = (source.JobData == null ? DateTime.MinValue : source.JobData.LastUpdate),
-        HiveExperimentId = source.HiveExperimentId,
-        IsPrivileged = source.IsPrivileged
-      };
-    }
-    public static Job ToEntity(DT.Job source) {
-      if (source == null) return null;
-      var entity = new Job(); ToEntity(source, entity);
-      return entity;
-    }
-    public static void ToEntity(DT.Job source, Job target) {
-      if ((source != null) && (target != null)) {
-        target.JobId = source.Id;
-        target.CoresNeeded = source.CoresNeeded;
-        target.ExecutionTimeMs = source.ExecutionTime.TotalMilliseconds;
-        target.MemoryNeeded = source.MemoryNeeded;
-        target.ParentJobId = source.ParentJobId;
-        target.Priority = source.Priority;
-        target.LastHeartbeat = source.LastHeartbeat;
-        target.State = source.State;
-        if (target.StateLogs == null) target.StateLogs = new EntitySet<StateLog>();
-        foreach (DT.StateLog sl in source.StateLog.Where(x => x.Id == Guid.Empty)) {
-          target.StateLogs.Add(Convert.ToEntity(sl));
-        }
-        target.IsParentJob = source.IsParentJob;
-        target.FinishWhenChildJobsFinished = source.FinishWhenChildJobsFinished;
-        target.Command = source.Command;
-        // RequiredPlugins are added by Dao
-        target.HiveExperimentId = source.HiveExperimentId;
-        target.IsPrivileged = source.IsPrivileged;
-      }
-    }
-    #endregion
-
-    #region JobData
-    public static DT.JobData ToDto(JobData source) {
-      if (source == null) return null;
-      return new DT.JobData { JobId = source.JobId, Data = source.Data.ToArray(), LastUpdate = source.LastUpdate };
-    }
-    public static JobData ToEntity(DT.JobData source) {
-      if (source == null) return null;
-      var entity = new JobData(); ToEntity(source, entity);
-      return entity;
-    }
-    public static void ToEntity(DT.JobData source, JobData target) {
-      if ((source != null) && (target != null)) {
-        target.JobId = source.JobId; target.Data = new Binary(source.Data); target.LastUpdate = source.LastUpdate;
-      }
-    }
-    #endregion
-
-    #region StateLog
-    public static DT.StateLog ToDto(StateLog source) {
-      if (source == null) return null;
-      return new DT.StateLog { Id = source.StateLogId, DateTime = source.DateTime, Exception = source.Exception, JobId = source.JobId, SlaveId = source.SlaveId, State = source.State, UserId = source.UserId };
-    }
-    public static StateLog ToEntity(DT.StateLog source) {
-      if (source == null) return null;
-      var entity = new StateLog(); ToEntity(source, entity);
-      return entity;
-    }
-    public static void ToEntity(DT.StateLog source, StateLog target) {
-      if ((source != null) && (target != null)) {
-        target.StateLogId = source.Id; target.DateTime = source.DateTime; target.Exception = source.Exception; target.JobId = source.JobId; target.SlaveId = source.SlaveId; target.State = source.State; target.UserId = source.UserId;
-      }
-    }
-    #endregion
-
-    #region Downtimes
-    public static DT.Downtime ToDto(Downtime source) {
-      if (source == null) return null;
-      return new DT.Downtime { Id = source.DowntimeId, AllDayEvent = source.AllDayEvent, EndDate = source.EndDate, Recurring = source.Recurring, RecurringId = source.RecurringId, ResourceId = source.ResourceId, StartDate = source.StartDate };
-    }
-    public static Downtime ToEntity(DT.Downtime source) {
-      if (source == null) return null;
-      var entity = new Downtime(); ToEntity(source, entity);
-      return entity;
-    }
-    public static void ToEntity(DT.Downtime source, Downtime target) {
-      if ((source != null) && (target != null)) {
-        target.DowntimeId = source.Id; target.AllDayEvent = source.AllDayEvent; target.EndDate = source.EndDate; target.Recurring = source.Recurring; target.RecurringId = source.RecurringId; target.ResourceId = source.ResourceId; target.StartDate = source.StartDate;
-      }
-    }
-    #endregion
-
-    #region HiveExperiment
-    public static DT.HiveExperiment ToDto(HiveExperiment source) {
-      if (source == null) return null;
-      return new DT.HiveExperiment { Id = source.HiveExperimentId, Description = source.Description, Name = source.Name, OwnerUserId = source.OwnerUserId, DateCreated = source.DateCreated, ResourceNames = source.ResourceIds, LastAccessed = source.LastAccessed };
-    }
-    public static HiveExperiment ToEntity(DT.HiveExperiment source) {
-      if (source == null) return null;
-      var entity = new HiveExperiment(); ToEntity(source, entity);
-      return entity;
-    }
-    public static void ToEntity(DT.HiveExperiment source, HiveExperiment target) {
-      if ((source != null) && (target != null)) {
-        target.HiveExperimentId = source.Id; target.Description = source.Description; target.Name = source.Name; target.OwnerUserId = source.OwnerUserId; target.DateCreated = source.DateCreated; target.ResourceIds = source.ResourceNames; target.LastAccessed = source.LastAccessed;
-      }
-    }
-    #endregion
-
-    #region HiveExperimentPermission
-    public static DT.HiveExperimentPermission ToDto(HiveExperimentPermission source) {
-      if (source == null) return null;
-      return new DT.HiveExperimentPermission { HiveExperimentId = source.HiveExperimentId, GrantedUserId = source.GrantedUserId, GrantedByUserId = source.GrantedByUserId, Permission = source.Permission };
-    }
-    public static HiveExperimentPermission ToEntity(DT.HiveExperimentPermission source) {
-      if (source == null) return null;
-      var entity = new HiveExperimentPermission(); ToEntity(source, entity);
-      return entity;
-    }
-    public static void ToEntity(DT.HiveExperimentPermission source, HiveExperimentPermission target) {
-      if ((source != null) && (target != null)) {
-        target.HiveExperimentId = source.HiveExperimentId; target.GrantedUserId = source.GrantedUserId; target.GrantedByUserId = source.GrantedByUserId; target.Permission = source.Permission;
-      }
-    }
-    #endregion
-
-    #region Plugin
-    public static DT.Plugin ToDto(Plugin source) {
-      if (source == null) return null;
-      return new DT.Plugin { Id = source.PluginId, Name = source.Name, Version = new Version(source.Version), UserId = source.UserId, DateCreated = source.DateCreated, Hash = source.Hash };
-    }
-    public static Plugin ToEntity(DT.Plugin source) {
-      if (source == null) return null;
-      var entity = new Plugin(); ToEntity(source, entity);
-      return entity;
-    }
-    public static void ToEntity(DT.Plugin source, Plugin target) {
-      if ((source != null) && (target != null)) {
-        target.PluginId = source.Id; target.Name = source.Name; target.Version = source.Version.ToString(); target.UserId = source.UserId; target.DateCreated = source.DateCreated; target.Hash = source.Hash;
-      }
-    }
-    #endregion
-
-    #region PluginData
-    public static DT.PluginData ToDto(PluginData source) {
-      if (source == null) return null;
-      return new DT.PluginData { Id = source.PluginDataId, PluginId = source.PluginId, Data = source.Data.ToArray(), FileName = source.FileName };
-    }
-    public static PluginData ToEntity(DT.PluginData source) {
-      if (source == null) return null;
-      var entity = new PluginData(); ToEntity(source, entity);
-      return entity;
-    }
-    public static void ToEntity(DT.PluginData source, PluginData target) {
-      if ((source != null) && (target != null)) {
-        target.PluginDataId = source.Id; target.PluginId = source.PluginId; target.Data = new Binary(source.Data); target.FileName = source.FileName;
-      }
-    }
-    #endregion
-
-    #region Slave
-    public static DT.Slave ToDto(Slave source) {
-      if (source == null) return null;
-      return new DT.Slave {
-        Id = source.ResourceId,
-        ParentResourceId = source.ParentResourceId,
-        Cores = source.Cores,
-        CpuSpeed = source.CpuSpeed,
-        FreeCores = source.FreeCores,
-        FreeMemory = source.FreeMemory,
-        IsAllowedToCalculate = source.IsAllowedToCalculate,
-        Memory = source.Memory,
-        Name = source.Name,
-        SlaveState = source.SlaveState,
-        CpuArchitecture = source.CpuArchitecture,
-        OperatingSystem = source.OperatingSystem,
-        LastHeartbeat = source.LastHeartbeat,
-        CpuUtilization = source.CpuUtilization
-      };
-    }
-    public static Slave ToEntity(DT.Slave source) {
-      if (source == null) return null;
-      var entity = new Slave(); ToEntity(source, entity);
-      return entity;
-    }
-    public static void ToEntity(DT.Slave source, Slave target) {
-      if ((source != null) && (target != null)) {
-        target.ResourceId = source.Id;
-        target.ParentResourceId = source.ParentResourceId;
-        target.Cores = source.Cores;
-        target.CpuSpeed = source.CpuSpeed;
-        target.FreeCores = source.FreeCores;
-        target.FreeMemory = source.FreeMemory;
-        target.IsAllowedToCalculate = source.IsAllowedToCalculate;
-        target.Memory = source.Memory;
-        target.Name = source.Name;
-        target.SlaveState = source.SlaveState;
-        target.CpuArchitecture = source.CpuArchitecture;
-        target.OperatingSystem = source.OperatingSystem;
-        target.LastHeartbeat = source.LastHeartbeat;
-        target.CpuUtilization = source.CpuUtilization;
-      }
-    }
-    #endregion
-
-    #region SlaveGroup
-    public static DT.SlaveGroup ToDto(SlaveGroup source) {
-      if (source == null) return null;
-      return new DT.SlaveGroup { Id = source.ResourceId, Name = source.Name, ParentResourceId = source.ParentResourceId };
-    }
-    public static SlaveGroup ToEntity(DT.SlaveGroup source) {
-      if (source == null) return null;
-      var entity = new SlaveGroup(); ToEntity(source, entity);
-      return entity;
-    }
-    public static void ToEntity(DT.SlaveGroup source, SlaveGroup target) {
-      if ((source != null) && (target != null)) {
-        target.ResourceId = source.Id; target.Name = source.Name; target.ParentResourceId = source.ParentResourceId;
-      }
-    }
-    #endregion
-
-    #region Resource
-    public static DT.Resource ToDto(Resource source) {
-      if (source == null) return null;
-      return new DT.Resource { Id = source.ResourceId, Name = source.Name, ParentResourceId = source.ParentResourceId };
-    }
-    public static Resource ToEntity(DT.Resource source) {
-      if (source == null) return null;
-      var entity = new Resource(); ToEntity(source, entity);
-      return entity;
-    }
-    public static void ToEntity(DT.Resource source, Resource target) {
-      if ((source != null) && (target != null)) {
-        target.ResourceId = source.Id; target.Name = source.Name; target.ParentResourceId = source.ParentResourceId;
-      }
-    }
-    #endregion
-
-    #region Statistics
-    public static DT.Statistics ToDto(Statistics source) {
-      if (source == null) return null;
-      return new DT.Statistics {
-        Id = source.StatisticsId,
-        TimeStamp = source.Timestamp,
-        SlaveStatistics = source.SlaveStatistics.Select(x => Convert.ToDto(x)).ToArray(),
-        UserStatistics = source.UserStatistics.Select(x => Convert.ToDto(x)).ToArray()
-      };
-    }
-    public static Statistics ToEntity(DT.Statistics source) {
-      if (source == null) return null;
-      var entity = new Statistics(); ToEntity(source, entity);
-      return entity;
-    }
-    public static void ToEntity(DT.Statistics source, Statistics target) {
-      if ((source != null) && (target != null)) {
-        target.StatisticsId = source.Id;
-        target.Timestamp = source.TimeStamp;
-
-      }
-    }
-    #endregion
-
-    #region SlaveStatistics
-    public static DT.SlaveStatistics ToDto(SlaveStatistics source) {
-      if (source == null) return null;
-      return new DT.SlaveStatistics {
-        Id = source.StatisticsId,
-        SlaveId = source.SlaveId,
-        Cores = source.Cores,
-        CpuUtilization = source.CpuUtilization,
-        FreeCores = source.FreeCores,
-        FreeMemory = source.FreeMemory,
-        Memory = source.Memory
-      };
-    }
-    public static SlaveStatistics ToEntity(DT.SlaveStatistics source) {
-      if (source == null) return null;
-      var entity = new SlaveStatistics(); ToEntity(source, entity);
-      return entity;
-    }
-    public static void ToEntity(DT.SlaveStatistics source, SlaveStatistics target) {
-      if ((source != null) && (target != null)) {
-        target.StatisticsId = source.Id;
-        target.SlaveId = source.SlaveId;
-        target.Cores = source.Cores;
-        target.CpuUtilization = source.CpuUtilization;
-        target.FreeCores = source.FreeCores;
-        target.FreeMemory = source.FreeMemory;
-        target.Memory = source.Memory;
-      }
-    }
-    #endregion
-
-    #region UserStatistics
-    public static DT.UserStatistics ToDto(UserStatistics source) {
-      if (source == null) return null;
-      return new DT.UserStatistics {
-        Id = source.StatisticsId,
-        UserId = source.UserId,
-        UsedCores = source.UsedCores,
-        ExecutionTime = TimeSpan.FromMilliseconds(source.ExecutionTimeMs),
-        ExecutionTimeFinishedJobs = TimeSpan.FromMilliseconds(source.ExecutionTimeMsFinishedJobs),
-        StartToEndTime = TimeSpan.FromMilliseconds(source.StartToEndTimeMs)
-      };
-    }
-    public static UserStatistics ToEntity(DT.UserStatistics source) {
-      if (source == null) return null;
-      var entity = new UserStatistics(); ToEntity(source, entity);
-      return entity;
-    }
-    public static void ToEntity(DT.UserStatistics source, UserStatistics target) {
-      if ((source != null) && (target != null)) {
-        target.StatisticsId = source.Id;
-        target.UserId = source.UserId;
-        target.UsedCores = source.UsedCores;
-        target.ExecutionTimeMs = source.ExecutionTime.TotalMilliseconds;
-        target.ExecutionTimeMsFinishedJobs = source.ExecutionTimeFinishedJobs.TotalMilliseconds;
-        target.StartToEndTimeMs = source.StartToEndTime.TotalMilliseconds;
-      }
-    }
-    #endregion
-  }
-}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/AssignedResourceDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/AssignedResourceDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/AssignedResourceDao.cs	(revision 12878)
@@ -0,0 +1,58 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos {
+  public class AssignedResourceDao : GenericDao<Guid, AssignedResource> {
+    public AssignedResourceDao(DataContext dataContext) : base(dataContext) { }
+
+    public override AssignedResource GetById(Guid id) {
+      throw new NotImplementedException();
+    }
+
+    public IQueryable<AssignedResource> GetByTaskId(Guid taskId) {
+      return Table.Where(x => x.TaskId == taskId);
+    }
+
+    public bool TaskIsAllowedToBeCalculatedBySlave(Guid taskId, Guid slaveId) {
+      return DataContext.ExecuteQuery<int>(TaskIsAllowedToBeCalculatedBySlaveQueryString, slaveId, taskId).First() > 0;
+    }
+
+    #region String queries
+    private const string TaskIsAllowedToBeCalculatedBySlaveQueryString = @"
+      WITH pr AS (
+        SELECT ResourceId, ParentResourceId
+        FROM [Resource]
+        WHERE ResourceId = {0}
+        UNION ALL
+        SELECT r.ResourceId, r.ParentResourceId
+        FROM [Resource] r JOIN pr ON r.ResourceId = pr.ParentResourceId
+      )
+      SELECT COUNT(ar.TaskId)
+      FROM pr JOIN AssignedResources ar ON pr.ResourceId = ar.ResourceId
+      WHERE ar.TaskId = {1}
+    ";
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/DowntimeDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/DowntimeDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/DowntimeDao.cs	(revision 12878)
@@ -0,0 +1,46 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos {
+  public class DowntimeDao : GenericDao<Guid, Downtime> {
+    public DowntimeDao(DataContext dataContext) : base(dataContext) { }
+
+    public override Downtime GetById(Guid id) {
+      return GetByIdQuery(DataContext, id);
+    }
+
+    public IQueryable<Downtime> GetByResourceId(Guid id) {
+      return Table.Where(x => x.ResourceId == id);
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, Downtime> GetByIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid downtimeId) =>
+        (from downtime in db.GetTable<Downtime>()
+         where downtime.DowntimeId == downtimeId
+         select downtime).SingleOrDefault());
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/GenericDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/GenericDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/GenericDao.cs	(revision 12878)
@@ -0,0 +1,125 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Data.Linq;
+using System.Linq;
+using System.Linq.Expressions;
+using HeuristicLab.Services.Hive.DataAccess.Interfaces;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos {
+  public abstract class GenericDao<PK, T> : IGenericDao<PK, T> where T : class {
+    private readonly DataContext dataContext;
+    protected DataContext DataContext {
+      get { return dataContext; }
+    }
+
+    protected Table<T> Table {
+      get { return dataContext.GetTable<T>(); }
+    }
+
+    protected GenericDao(DataContext dataContext) {
+      this.dataContext = dataContext;
+    }
+
+    #region IGenericDao<PK,T> Members
+    public abstract T GetById(PK id);
+
+    public IQueryable<T> Get(Expression<Func<T, bool>> predicate) {
+      return Table.Where(predicate);
+    }
+
+    public IQueryable<T> GetAll() {
+      return Table;
+    }
+
+    public T Save(T entity) {
+      Table.InsertOnSubmit(entity);
+      return entity;
+    }
+
+    public IEnumerable<T> Save(params T[] entities) {
+      return entities.Select(Save).ToList();
+    }
+
+    public IEnumerable<T> Save(IEnumerable<T> entities) {
+      return entities.Select(Save).ToList();
+    }
+
+    public T SaveOrAttach(T entity) {
+      if (Table.Contains(entity)) {
+        if (Table.GetOriginalEntityState(entity) == null) {
+          Table.Attach(entity);
+        }
+      } else {
+        Table.InsertOnSubmit(entity);
+      }
+      return entity;
+    }
+
+    public IEnumerable<T> SaveOrAttach(params T[] entities) {
+      return entities.Select(SaveOrAttach).ToList();
+    }
+
+    public IEnumerable<T> SaveOrAttach(IEnumerable<T> entities) {
+      return entities.Select(SaveOrAttach).ToList();
+    }
+
+    public void Delete(PK id) {
+      T entity = GetById(id);
+      if (entity != null) {
+        Table.DeleteOnSubmit(entity);
+      }
+    }
+
+    public virtual void Delete(IEnumerable<PK> ids) {
+      foreach (var id in ids) {
+        Delete(id);
+      }
+    }
+
+    public void Delete(T entity) {
+      Table.DeleteOnSubmit(entity);
+    }
+
+    public void Delete(IEnumerable<T> entities) {
+      foreach (var entity in entities) {
+        Delete(entity);
+      }
+    }
+
+    public bool Exists(T entity) {
+      return ExistsQuery(DataContext, entity);
+    }
+
+    public bool Exists(PK id) {
+      return GetById(id) != null;
+    }
+    #endregion
+
+    #region Compiled queries
+    private static readonly Func<DataContext, T, bool> ExistsQuery =
+      CompiledQuery.Compile((DataContext db, T entity) =>
+        db.GetTable<T>().Contains(entity));
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimClientDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimClientDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimClientDao.cs	(revision 12878)
@@ -0,0 +1,67 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos.HiveStatistics {
+  public class DimClientDao : GenericDao<Guid, DimClient> {
+    public DimClientDao(DataContext dataContext) : base(dataContext) { }
+
+    public override DimClient GetById(Guid id) {
+      return GetByIdQuery(DataContext, id);
+    }
+
+    public IQueryable<DimClient> GetActiveClients() {
+      return Table.Where(x => x.ExpirationTime == null);
+    }
+
+    public IQueryable<DimClient> GetExpiredClients() {
+      return Table.Where(x => x.ExpirationTime != null);
+    }
+
+    public int UpdateExpirationTime(IEnumerable<Guid> ids, DateTime time) {
+      string paramIds = string.Join(",", ids.Select(x => string.Format("'{0}'", x)));
+      if (!string.IsNullOrWhiteSpace(paramIds)) {
+        string query = string.Format(UpdateExpirationTimeQuery, "{0}", paramIds);
+        return DataContext.ExecuteCommand(query, time);
+      }
+      return 0;
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, DimClient> GetByIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid id) =>
+        (from dimClient in db.GetTable<DimClient>()
+         where dimClient.Id == id
+         select dimClient).SingleOrDefault());
+    #endregion
+
+    #region String queries
+    private const string UpdateExpirationTimeQuery =
+      @"UPDATE [statistics].[DimClient] 
+           SET ExpirationTime = {0} 
+         WHERE Id IN ({1});";
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimJobDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimJobDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimJobDao.cs	(revision 12878)
@@ -0,0 +1,54 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos.HiveStatistics {
+  public class DimJobDao : GenericDao<Guid, DimJob> {
+    public DimJobDao(DataContext dataContext) : base(dataContext) { }
+
+    public override DimJob GetById(Guid id) {
+      return GetByIdQuery(DataContext, id);
+    }
+
+    public IQueryable<DimJob> GetByUserId(Guid id) {
+      return Table.Where(x => x.UserId == id);
+    }
+
+    public IQueryable<DimJob> GetNotCompletedJobs() {
+      return Table.Where(x => x.DateCompleted == null);
+    }
+
+    public IQueryable<DimJob> GetCompletedJobs() {
+      return Table.Where(x => x.DateCompleted != null);
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, DimJob> GetByIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid id) =>
+        (from dimJob in db.GetTable<DimJob>()
+         where dimJob.JobId == id
+         select dimJob).SingleOrDefault());
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimTimeDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimTimeDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimTimeDao.cs	(revision 12878)
@@ -0,0 +1,64 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos.HiveStatistics {
+  public class DimTimeDao : GenericDao<DateTime, DimTime> {
+    public DimTimeDao(DataContext dataContext) : base(dataContext) { }
+
+    public override DimTime GetById(DateTime id) {
+      return GetByIdQuery(DataContext, id);
+    }
+
+    public DimTime GetLastEntry() {
+      return GetLastEntryQuery(DataContext);
+    }
+
+    public int DeleteUnusedTimes() {
+      return DataContext.ExecuteCommand(DeleteUnusedTimeEntriesStringQuery);
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, DateTime, DimTime> GetByIdQuery =
+      CompiledQuery.Compile((DataContext db, DateTime id) =>
+        (from dimTime in db.GetTable<DimTime>()
+         where dimTime.Time == id
+         select dimTime).SingleOrDefault());
+
+    private static readonly Func<DataContext, DimTime> GetLastEntryQuery =
+      CompiledQuery.Compile((DataContext db) =>
+        (from dimTime in db.GetTable<DimTime>()
+         orderby dimTime.Time descending
+         select dimTime).FirstOrDefault());
+    #endregion
+
+    #region String queries
+    private const string DeleteUnusedTimeEntriesStringQuery = @"
+      DELETE FROM [statistics].[DimTime]
+      WHERE NOT EXISTS (SELECT [Time] FROM [statistics].[FactClientInfo] fci
+                        WHERE fci.[Time] = [statistics].[DimTime].[Time]);    
+    ";
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimUserDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimUserDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimUserDao.cs	(revision 12878)
@@ -0,0 +1,42 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos.HiveStatistics {
+  public class DimUserDao : GenericDao<Guid, DimUser> {
+    public DimUserDao(DataContext dataContext) : base(dataContext) { }
+
+    public override DimUser GetById(Guid id) {
+      return GetByIdQuery(DataContext, id);
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, DimUser> GetByIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid id) =>
+        (from dimUser in db.GetTable<DimUser>()
+         where dimUser.UserId == id
+         select dimUser).SingleOrDefault());
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/FactClientInfoDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/FactClientInfoDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/FactClientInfoDao.cs	(revision 12878)
@@ -0,0 +1,67 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos.HiveStatistics {
+
+  public class LastUpdateTimestamp {
+    public Guid ResourceId { get; set; }
+    public DateTime? Timestamp { get; set; }
+  }
+
+  public class FactClientInfoDao : GenericDao<Guid, FactClientInfo> {
+    private Table<DimClient> DimClientTable {
+      get { return DataContext.GetTable<DimClient>(); }
+    }
+
+    private Table<DimUser> DimUserTable {
+      get { return DataContext.GetTable<DimUser>(); }
+    }
+
+    private Table<DimTime> DimTimeTable {
+      get { return DataContext.GetTable<DimTime>(); }
+    }
+
+    public FactClientInfoDao(DataContext dataContext) : base(dataContext) { }
+
+    public override FactClientInfo GetById(Guid id) {
+      throw new NotImplementedException();
+    }
+
+    public IQueryable<LastUpdateTimestamp> GetLastUpdateTimestamps() {
+      return from cf in Table
+             join r in DimClientTable on cf.ClientId equals r.Id
+             group cf by r.ResourceId
+               into grpFacts
+               select new LastUpdateTimestamp {
+                 ResourceId = grpFacts.Key,
+                 Timestamp = grpFacts.Max(x => x.Time),
+               };
+    }
+
+    public IQueryable<FactClientInfo> GetByClientId(Guid id) {
+      return Table.Where(x => x.ClientId == id);
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/FactTaskDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/FactTaskDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/FactTaskDao.cs	(revision 12878)
@@ -0,0 +1,120 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos.HiveStatistics {
+  public class FactTaskDao : GenericDao<Guid, FactTask> {
+
+    private static readonly TaskState[] CompletedStates = { TaskState.Finished, TaskState.Aborted, TaskState.Failed };
+
+    private Table<DimClient> DimClientTable {
+      get { return DataContext.GetTable<DimClient>(); }
+    }
+    private Table<DimJob> DimJobTable {
+      get { return DataContext.GetTable<DimJob>(); }
+    }
+
+    public FactTaskDao(DataContext dataContext) : base(dataContext) { }
+
+    public override FactTask GetById(Guid id) {
+      return GetByIdQuery(DataContext, id);
+    }
+
+    public IQueryable<FactTask> GetNotFinishedTasks() {
+      return Table.Where(x => x.EndTime == null);
+    }
+
+    public IQueryable<FactTask> GetByJobId(Guid id) {
+      return Table.Where(x => x.JobId == id);
+    }
+
+    public DateTime? GetLastCompletedTaskFromJob(Guid id) {
+      return GetLastCompletedTaskFromJobQuery(DataContext, id);
+    }
+
+    public IQueryable<FactTask> GetByClientId(Guid id) {
+      return Table.Where(x => x.LastClientId == id);
+    }
+
+    public IQueryable<FactTask> GetTasksWithException() {
+      return Table.Where(x => x.Exception.Trim() != string.Empty);
+    }
+
+    public IQueryable<FactTask> GetByGroupId(Guid id) {
+      return from factTask in Table
+             join client in DimClientTable on factTask.LastClientId equals client.Id
+             where client.ResourceGroupId == id
+             select factTask;
+    }
+
+    public IQueryable<FactTask> GetByUserId(Guid id) {
+      return from factTask in Table
+             join job in DimJobTable on factTask.JobId equals job.JobId
+             where job.UserId == id
+             select factTask;
+    }
+
+    public IQueryable<FactTask> GetCompletedTasks() {
+      return Table.Where(x => CompletedStates.Contains(x.TaskState));
+    }
+
+    public override void Delete(IEnumerable<Guid> ids) {
+      string paramIds = string.Join(",", ids.Select(x => string.Format("'{0}'", x)));
+      if (!string.IsNullOrWhiteSpace(paramIds)) {
+        string query = string.Format(BatchDeleteQuery, paramIds);
+        DataContext.ExecuteCommand(query);
+      }
+    }
+
+    public void DeleteByJobId(Guid jobId) {
+      DataContext.ExecuteCommand(DeleteByJobIdQuery, jobId);
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, FactTask> GetByIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid id) =>
+        (from factTask in db.GetTable<FactTask>()
+         where factTask.TaskId == id
+         select factTask).SingleOrDefault());
+
+
+    private static readonly Func<DataContext, Guid, DateTime?> GetLastCompletedTaskFromJobQuery =
+      CompiledQuery.Compile((DataContext db, Guid id) =>
+        (from factTask in db.GetTable<FactTask>()
+         where factTask.JobId == id && factTask.EndTime != null
+         select factTask.EndTime).Max());
+    #endregion
+
+    #region String queries
+    private const string BatchDeleteQuery =
+      @"DELETE FROM [statistics].[FactTask]
+         WHERE TaskId IN ({0});";
+
+    private const string DeleteByJobIdQuery =
+      @"DELETE FROM [statistics].[FactTask]
+         WHERE JobId = {0};";
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/JobDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/JobDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/JobDao.cs	(revision 12878)
@@ -0,0 +1,42 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos {
+  public class JobDao : GenericDao<Guid, Job> {
+    public JobDao(DataContext dataContext) : base(dataContext) { }
+
+    public override Job GetById(Guid id) {
+      return GetByIdQuery(DataContext, id);
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, Job> GetByIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid jobId) =>
+        (from job in db.GetTable<Job>()
+         where job.JobId == jobId
+         select job).SingleOrDefault());
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/JobPermissionDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/JobPermissionDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/JobPermissionDao.cs	(revision 12878)
@@ -0,0 +1,71 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos {
+  public class JobPermissionDao : GenericDao<Guid, JobPermission> {
+    public JobPermissionDao(DataContext dataContext) : base(dataContext) { }
+
+    public override JobPermission GetById(Guid id) {
+      throw new NotImplementedException();
+    }
+
+    public JobPermission GetByJobAndUserId(Guid jobId, Guid userId) {
+      return GetByJobAndUserIdQuery(DataContext, jobId, userId);
+    }
+
+    public IQueryable<JobPermission> GetByJobId(Guid jobId) {
+      return Table.Where(x => x.JobId == jobId);
+    }
+
+    public void SetJobPermission(Guid jobId, Guid grantedByUserId, Guid grantedUserId, Permission permission) {
+      var jobPermission = GetByJobAndUserId(jobId, grantedUserId);
+      if (jobPermission != null) {
+        if (permission == Permission.NotAllowed) {
+          Delete(jobPermission);
+        } else {
+          jobPermission.Permission = permission;
+          jobPermission.GrantedByUserId = grantedByUserId;
+        }
+      } else {
+        if (permission != Permission.NotAllowed) {
+          Save(new JobPermission {
+            JobId = jobId,
+            GrantedByUserId = grantedByUserId,
+            GrantedUserId = grantedUserId,
+            Permission = permission
+          });
+        }
+      }
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, Guid, JobPermission> GetByJobAndUserIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid jobId, Guid userId) =>
+        (from jobPermission in db.GetTable<JobPermission>()
+         where jobPermission.JobId == jobId && jobPermission.GrantedUserId == userId
+         select jobPermission).SingleOrDefault());
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/LifecycleDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/LifecycleDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/LifecycleDao.cs	(revision 12878)
@@ -0,0 +1,63 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos {
+  public class LifecycleDao : GenericDao<int, Lifecycle> {
+    public LifecycleDao(DataContext dataContext) : base(dataContext) { }
+
+    public override Lifecycle GetById(int id) {
+      return GetByIdQuery(DataContext, id);
+    }
+
+    public Lifecycle GetLastLifecycle() {
+      return GetLastLifecycleQuery(DataContext);
+    }
+
+    public void UpdateLifecycle() {
+      var entity = GetLastLifecycle();
+      if (entity != null) {
+        entity.LastCleanup = DateTime.Now;
+      } else {
+        Save(new Lifecycle {
+          LifecycleId = 0,
+          LastCleanup = DateTime.Now
+        });
+      }
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, int, Lifecycle> GetByIdQuery =
+     CompiledQuery.Compile((DataContext db, int lifecycleId) =>
+       (from lifecycle in db.GetTable<Lifecycle>()
+        where lifecycle.LifecycleId == lifecycleId
+        select lifecycle).SingleOrDefault());
+
+    private static readonly Func<DataContext, Lifecycle> GetLastLifecycleQuery =
+      CompiledQuery.Compile((DataContext db) =>
+        (from lifecycle in db.GetTable<Lifecycle>()
+         select lifecycle).SingleOrDefault());
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/PluginDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/PluginDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/PluginDao.cs	(revision 12878)
@@ -0,0 +1,70 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos {
+  public class PluginDao : GenericDao<Guid, Plugin> {
+    public PluginDao(DataContext dataContext) : base(dataContext) { }
+
+    public override Plugin GetById(Guid id) {
+      return GetByIdQuery(DataContext, id);
+    }
+
+    public IEnumerable<Plugin> GetByHash(byte[] hash) {
+      return GetByHashQuery(DataContext).Where(x => x.Hash.SequenceEqual(hash));
+    }
+
+    public int DeleteUnusedPlugins() {
+      return DataContext.ExecuteCommand(DeleteUnusedPluginsStringQuery);
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, Plugin> GetByIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid pluginId) =>
+        (from plugin in db.GetTable<Plugin>()
+         where plugin.PluginId == pluginId
+         select plugin).SingleOrDefault());
+
+    private static readonly Func<DataContext, IEnumerable<Plugin>> GetByHashQuery =
+      CompiledQuery.Compile((DataContext db) =>
+        (from plugin in db.GetTable<Plugin>()
+         where plugin.Hash != null
+         select plugin));
+    #endregion
+
+    #region String queries
+    private const string DeleteUnusedPluginsStringQuery = @"
+      DELETE FROM [Plugin]
+      WHERE  [Plugin].[PluginId] NOT IN (
+        SELECT DISTINCT rp.[PluginId] 
+        FROM [RequiredPlugins] rp
+        WHERE EXISTS (SELECT [TaskId] 
+                      FROM [Task] t
+                      WHERE t.[TaskId] = rp.[TaskId])
+      );
+    ";
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/PluginDataDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/PluginDataDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/PluginDataDao.cs	(revision 12878)
@@ -0,0 +1,42 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos {
+  public class PluginDataDao : GenericDao<Guid, PluginData> {
+    public PluginDataDao(DataContext dataContext) : base(dataContext) { }
+
+    public override PluginData GetById(Guid id) {
+      return GetByIdQuery(DataContext, id);
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, PluginData> GetByIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid pluginDataId) =>
+        (from pluginData in db.GetTable<PluginData>()
+         where pluginData.PluginDataId == pluginDataId
+         select pluginData).SingleOrDefault());
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/RequiredPluginDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/RequiredPluginDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/RequiredPluginDao.cs	(revision 12878)
@@ -0,0 +1,42 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos {
+  public class RequiredPluginDao : GenericDao<Guid, RequiredPlugin> {
+    public RequiredPluginDao(DataContext dataContext) : base(dataContext) { }
+
+    public override RequiredPlugin GetById(Guid id) {
+      return GetByIdQuery(DataContext, id);
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, RequiredPlugin> GetByIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid requiredPluginId) =>
+        (from requiredPlugin in db.GetTable<RequiredPlugin>()
+         where requiredPlugin.RequiredPluginId == requiredPluginId
+         select requiredPlugin).SingleOrDefault());
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ResourceDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ResourceDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ResourceDao.cs	(revision 12878)
@@ -0,0 +1,56 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos {
+  public class ResourceDao : GenericDao<Guid, Resource> {
+    public ResourceDao(DataContext dataContext) : base(dataContext) { }
+
+    public override Resource GetById(Guid id) {
+      return GetByIdQuery(DataContext, id);
+    }
+
+    public Resource GetByName(string name) {
+      return GetByNameQuery(DataContext, name);
+    }
+
+    public IQueryable<Resource> GetResourcesWithValidOwner() {
+      return Table.Where(x => x.OwnerUserId != null);
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, Resource> GetByIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid resourceId) =>
+        (from resource in db.GetTable<Resource>()
+         where resource.ResourceId == resourceId
+         select resource).SingleOrDefault());
+
+    private static readonly Func<DataContext, string, Resource> GetByNameQuery =
+     CompiledQuery.Compile((DataContext db, string name) =>
+       (from resource in db.GetTable<Resource>()
+        where resource.Name == name
+        select resource).FirstOrDefault());
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ResourcePermissionDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ResourcePermissionDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ResourcePermissionDao.cs	(revision 12878)
@@ -0,0 +1,62 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos {
+  public class ResourcePermissionDao : GenericDao<Guid, ResourcePermission> {
+    public ResourcePermissionDao(DataContext dataContext) : base(dataContext) { }
+
+    public override ResourcePermission GetById(Guid id) {
+      throw new NotImplementedException();
+    }
+
+    public IEnumerable<ResourcePermission> GetByResourceId(Guid id) {
+      return GetByResourceIdGetByIdQuery(DataContext, id);
+    }
+
+    public void DeleteByResourceAndGrantedUserId(Guid resourceId, IEnumerable<Guid> grantedUserId) {
+      string paramIds = string.Join(",", grantedUserId.Select(x => string.Format("'{0}'", x)));
+      if (!string.IsNullOrWhiteSpace(paramIds)) {
+        string query = string.Format(DeleteByGrantedUserQuery, resourceId, paramIds);
+        DataContext.ExecuteCommand(query);
+      }
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, IEnumerable<ResourcePermission>> GetByResourceIdGetByIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid resourceId) =>
+        from resourcePermission in db.GetTable<ResourcePermission>()
+        where resourcePermission.ResourceId == resourceId
+        select resourcePermission);
+    #endregion
+
+    #region String queries
+    private const string DeleteByGrantedUserQuery =
+      @"DELETE FROM [ResourcePermission]
+         WHERE ResourceId = '{0}'
+           AND GrantedUserId IN ({1});";
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/SlaveDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/SlaveDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/SlaveDao.cs	(revision 12878)
@@ -0,0 +1,164 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+
+using System;
+using System.Collections.Generic;
+using System.Data.Linq;
+using System.Linq;
+using System.Linq.Expressions;
+using HeuristicLab.Services.Hive.DataAccess.Interfaces;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos {
+  public class SlaveDao : IGenericDao<Guid, Slave> {
+
+    private readonly DataContext dataContext;
+    private Table<Resource> Table {
+      get { return dataContext.GetTable<Resource>(); }
+    }
+
+    private IQueryable<Slave> Entities {
+      get { return Table.OfType<Slave>(); }
+    }
+
+    public SlaveDao(DataContext dataContext) {
+      this.dataContext = dataContext;
+    }
+
+    #region IGenericDao<Guid,Slave> Members
+    public Slave GetById(Guid id) {
+      return GetByIdQuery(dataContext, id);
+    }
+
+    public IQueryable<Slave> Get(Expression<Func<Slave, bool>> predicate) {
+      return Entities.Where(predicate);
+    }
+
+    public IQueryable<Slave> GetAll() {
+      return Entities;
+    }
+
+    public IQueryable<Slave> GetOnlineSlaves() {
+      return Entities.Where(x => x.SlaveState != SlaveState.Offline);
+    }
+
+    public Slave Save(Slave entity) {
+      Table.InsertOnSubmit(entity);
+      return entity;
+    }
+
+    public IEnumerable<Slave> Save(params Slave[] entities) {
+      return entities.Select(Save).ToList();
+    }
+
+    public IEnumerable<Slave> Save(IEnumerable<Slave> entities) {
+      return entities.Select(Save).ToList();
+    }
+
+    public Slave SaveOrAttach(Slave entity) {
+      if (Table.Contains(entity)) {
+        if (Table.GetOriginalEntityState(entity) == null) {
+          Table.Attach(entity);
+        }
+      } else {
+        Table.InsertOnSubmit(entity);
+      }
+      return entity;
+    }
+
+    public IEnumerable<Slave> SaveOrAttach(params Slave[] entities) {
+      return entities.Select(SaveOrAttach).ToList();
+    }
+
+    public IEnumerable<Slave> SaveOrAttach(IEnumerable<Slave> entities) {
+      return entities.Select(SaveOrAttach).ToList();
+    }
+
+    public void Delete(Guid id) {
+      Slave entity = GetById(id);
+      if (entity != null) {
+        Table.DeleteOnSubmit(entity);
+      }
+    }
+
+    public void Delete(IEnumerable<Guid> ids) {
+      foreach (var id in ids) {
+        Delete(id);
+      }
+    }
+
+    public void Delete(Slave entity) {
+      Table.DeleteOnSubmit(entity);
+    }
+
+    public void Delete(IEnumerable<Slave> entities) {
+      foreach (var entity in entities) {
+        Delete(entity);
+      }
+    }
+
+    public bool Exists(Slave entity) {
+      return ExistsQuery(dataContext, entity);
+    }
+
+    public bool Exists(Guid id) {
+      return GetById(id) != null;
+    }
+    #endregion
+
+    public bool SlaveHasToShutdownComputer(Guid slaveId) {
+      return dataContext.ExecuteQuery<int>(DowntimeQueryString, slaveId, DateTime.Now, DowntimeType.Shutdown.ToString()).FirstOrDefault() > 0;
+    }
+
+    public bool SlaveIsAllowedToCalculate(Guid slaveId) {
+      return dataContext.ExecuteQuery<int>(DowntimeQueryString, slaveId, DateTime.Now, DowntimeType.Offline.ToString()).FirstOrDefault() == 0;
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, Slave> GetByIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid slaveId) =>
+        (from slave in db.GetTable<Resource>().OfType<Slave>()
+         where slave.ResourceId == slaveId
+         select slave).SingleOrDefault());
+
+    private static readonly Func<DataContext, Slave, bool> ExistsQuery =
+      CompiledQuery.Compile((DataContext db, Slave entity) =>
+        db.GetTable<Resource>().OfType<Slave>().Contains(entity));
+    #endregion
+
+    #region String queries
+    private const string DowntimeQueryString = @"
+      WITH pr AS (
+        SELECT ResourceId, ParentResourceId
+        FROM [Resource]
+        WHERE ResourceId = {0}
+        UNION ALL
+        SELECT r.ResourceId, r.ParentResourceId
+        FROM [Resource] r JOIN pr ON r.ResourceId = pr.ParentResourceId
+      )
+      SELECT COUNT(dt.DowntimeId)
+      FROM pr JOIN [Downtime] dt ON pr.ResourceId = dt.ResourceId
+      WHERE {1} BETWEEN dt.StartDate AND dt.EndDate
+        AND dt.DowntimeType = {2}
+    ";
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/SlaveGroupDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/SlaveGroupDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/SlaveGroupDao.cs	(revision 12878)
@@ -0,0 +1,134 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+
+using System;
+using System.Collections.Generic;
+using System.Data.Linq;
+using System.Linq;
+using System.Linq.Expressions;
+using HeuristicLab.Services.Hive.DataAccess.Interfaces;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos {
+  public class SlaveGroupDao : IGenericDao<Guid, SlaveGroup> {
+    private readonly DataContext dataContext;
+    private Table<Resource> Table {
+      get { return dataContext.GetTable<Resource>(); }
+    }
+
+    private IQueryable<SlaveGroup> Entities {
+      get { return Table.OfType<SlaveGroup>(); }
+    }
+
+    public SlaveGroupDao(DataContext dataContext) {
+      this.dataContext = dataContext;
+    }
+
+    #region IGenericDao<Guid,SlaveGroup> Members
+    public SlaveGroup GetById(Guid id) {
+      return GetByIdQuery(dataContext, id);
+    }
+
+    public IQueryable<SlaveGroup> Get(Expression<Func<SlaveGroup, bool>> predicate) {
+      return Entities.Where(predicate);
+    }
+
+    public IQueryable<SlaveGroup> GetAll() {
+      return Entities;
+    }
+
+    public SlaveGroup Save(SlaveGroup entity) {
+      Table.InsertOnSubmit(entity);
+      return entity;
+    }
+
+    public IEnumerable<SlaveGroup> Save(params SlaveGroup[] entities) {
+      return entities.Select(Save).ToList();
+    }
+
+    public IEnumerable<SlaveGroup> Save(IEnumerable<SlaveGroup> entities) {
+      return entities.Select(Save).ToList();
+    }
+
+    public SlaveGroup SaveOrAttach(SlaveGroup entity) {
+      if (Table.Contains(entity)) {
+        if (Table.GetOriginalEntityState(entity) == null) {
+          Table.Attach(entity);
+        }
+      } else {
+        Table.InsertOnSubmit(entity);
+      }
+      return entity;
+    }
+
+    public IEnumerable<SlaveGroup> SaveOrAttach(params SlaveGroup[] entities) {
+      return entities.Select(SaveOrAttach).ToList();
+    }
+
+    public IEnumerable<SlaveGroup> SaveOrAttach(IEnumerable<SlaveGroup> entities) {
+      return entities.Select(SaveOrAttach).ToList();
+    }
+
+    public void Delete(Guid id) {
+      SlaveGroup entity = GetById(id);
+      if (entity != null) {
+        Table.DeleteOnSubmit(entity);
+      }
+    }
+
+    public void Delete(IEnumerable<Guid> ids) {
+      foreach (var id in ids) {
+        Delete(id);
+      }
+    }
+
+    public void Delete(SlaveGroup entity) {
+      Table.DeleteOnSubmit(entity);
+    }
+
+    public void Delete(IEnumerable<SlaveGroup> entities) {
+      foreach (var entity in entities) {
+        Delete(entity);
+      }
+    }
+
+    public bool Exists(SlaveGroup entity) {
+      return ExistsQuery(dataContext, entity);
+    }
+
+    public bool Exists(Guid id) {
+      return GetById(id) != null;
+    }
+    #endregion
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, SlaveGroup> GetByIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid slaveGroupId) =>
+        (from slaveGroup in db.GetTable<Resource>().OfType<SlaveGroup>()
+         where slaveGroup.ResourceId == slaveGroupId
+         select slaveGroup).SingleOrDefault());
+
+    private static readonly Func<DataContext, SlaveGroup, bool> ExistsQuery =
+      CompiledQuery.Compile((DataContext db, SlaveGroup slaveGroup) =>
+        db.GetTable<Resource>().OfType<SlaveGroup>().Contains(slaveGroup));
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/StateLogDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/StateLogDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/StateLogDao.cs	(revision 12878)
@@ -0,0 +1,57 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos {
+  public class StateLogDao : GenericDao<Guid, StateLog> {
+    private Table<Task> TaskTable {
+      get { return DataContext.GetTable<Task>(); }
+    }
+
+    public StateLogDao(DataContext dataContext) : base(dataContext) { }
+
+    public override StateLog GetById(Guid id) {
+      return GetByIdQuery(DataContext, id);
+    }
+
+    public StateLog GetLastStateLogFromTask(Task task) {
+      return GetLastStateLogFromTaskQuery(DataContext, task);
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, StateLog> GetByIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid stateLogId) =>
+        (from stateLog in db.GetTable<StateLog>()
+         where stateLog.StateLogId == stateLogId
+         select stateLog).SingleOrDefault());
+
+    private static readonly Func<DataContext, Task, StateLog> GetLastStateLogFromTaskQuery =
+      CompiledQuery.Compile((DataContext db, Task task) =>
+        (from stateLog in db.GetTable<StateLog>()
+         where stateLog.TaskId == task.TaskId
+         orderby stateLog.DateTime descending
+         select stateLog).First(x => x.SlaveId != null));
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/TaskDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/TaskDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/TaskDao.cs	(revision 12878)
@@ -0,0 +1,124 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos {
+  public class TaskDao : GenericDao<Guid, Task> {
+    private Table<AssignedResource> AssignedResourceTable {
+      get { return DataContext.GetTable<AssignedResource>(); }
+    }
+
+    public TaskDao(DataContext dataContext) : base(dataContext) { }
+
+    public override Task GetById(Guid id) {
+      return GetByIdQuery(DataContext, id);
+    }
+
+    public IQueryable<Task> GetAllChildTasks() {
+      return Table.Where(x => !x.IsParentTask);
+    }
+
+    public IQueryable<Task> GetByJobId(Guid id) {
+      return Table.Where(x => x.JobId == id);
+    }
+    public class TaskPriorityInfo {
+      public Guid JobId { get; set; }
+      public Guid TaskId { get; set; }
+      public int Priority { get; set; }
+    }
+
+    public IEnumerable<TaskPriorityInfo> GetWaitingTasks(Slave slave) {
+      //Originally we checked here if there are parent tasks which should be calculated (with GetParentTasks(resourceIds, count, false);).
+      //Because there is at the moment no case where this makes sense (there don't exist parent tasks which need to be calculated), 
+      //we skip this step because it's wasted runtime
+      return DataContext.ExecuteQuery<TaskPriorityInfo>(GetWaitingTasksQueryString, slave.ResourceId, Enum.GetName(typeof(TaskState), TaskState.Waiting), slave.FreeCores, slave.FreeMemory).ToList();
+    }
+
+    /// <summary>
+    /// returns all parent tasks which are waiting for their child tasks to finish
+    /// </summary>
+    /// <param name="resourceIds">list of resourceids which for which the task should be valid</param>
+    /// <param name="count">maximum number of task to return</param>
+    /// <param name="finished">if true, all parent task which have FinishWhenChildJobsFinished=true are returned, otherwise only FinishWhenChildJobsFinished=false are returned</param>
+    /// <returns></returns>
+    public IEnumerable<Task> GetParentTasks(IEnumerable<Guid> resourceIds, int count, bool finished) {
+      var query = from ar in AssignedResourceTable
+                  where resourceIds.Contains(ar.ResourceId)
+                     && ar.Task.State == TaskState.Waiting
+                     && ar.Task.IsParentTask
+                     && (finished ? ar.Task.FinishWhenChildJobsFinished : !ar.Task.FinishWhenChildJobsFinished)
+                     && (from child in Table
+                         where child.ParentTaskId == ar.Task.TaskId
+                         select child.State == TaskState.Finished
+                             || child.State == TaskState.Aborted
+                             || child.State == TaskState.Failed).All(x => x)
+                     && (from child in Table // avoid returning WaitForChildTasks task where no child-task exist (yet)
+                         where child.ParentTaskId == ar.Task.TaskId
+                         select child).Any()
+                  orderby ar.Task.Priority descending
+                  select ar.Task;
+      return count == 0 ? query.ToArray() : query.Take(count).ToArray();
+    }
+
+    public void UpdateExecutionTime(Guid taskId, double executionTime) {
+      DataContext.ExecuteCommand(UpdateExecutionTimeQuery, executionTime, DateTime.Now, taskId);
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, Task> GetByIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid taskId) =>
+        (from task in db.GetTable<Task>()
+         where task.TaskId == taskId
+         select task).SingleOrDefault());
+    #endregion
+
+    #region String queries
+    private const string GetWaitingTasksQueryString = @"
+      WITH pr AS (
+        SELECT ResourceId, ParentResourceId
+        FROM [Resource]
+        WHERE ResourceId = {0}
+        UNION ALL
+        SELECT r.ResourceId, r.ParentResourceId
+        FROM [Resource] r JOIN pr ON r.ResourceId = pr.ParentResourceId
+      )
+      SELECT DISTINCT t.TaskId, t.JobId, t.Priority
+      FROM pr JOIN AssignedResources ar ON ar.ResourceId = pr.ResourceId
+          JOIN Task t ON t.TaskId = ar.TaskId
+      WHERE NOT (t.IsParentTask = 1 AND t.FinishWhenChildJobsFinished = 1)
+          AND t.TaskState = {1}
+          AND t.CoresNeeded <= {2}
+          AND t.MemoryNeeded <= {3}
+    ";
+
+    private const string UpdateExecutionTimeQuery = @"
+      UPDATE [Task] 
+         SET ExecutionTimeMs = {0},
+             LastHeartbeat = {1} 
+       WHERE TaskId = {2}
+    ";
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/TaskDataDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/TaskDataDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/TaskDataDao.cs	(revision 12878)
@@ -0,0 +1,42 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos {
+  public class TaskDataDao : GenericDao<Guid, TaskData> {
+    public TaskDataDao(DataContext dataContext) : base(dataContext) { }
+
+    public override TaskData GetById(Guid id) {
+      return GetByIdQuery(DataContext, id);
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, TaskData> GetByIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid taskId) =>
+        (from taskData in db.GetTable<TaskData>()
+         where taskData.TaskId == taskId
+         select taskData).SingleOrDefault());
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/UserPriorityDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/UserPriorityDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/UserPriorityDao.cs	(revision 12878)
@@ -0,0 +1,42 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos {
+  public class UserPriorityDao : GenericDao<Guid, UserPriority> {
+    public UserPriorityDao(DataContext dataContext) : base(dataContext) { }
+
+    public override UserPriority GetById(Guid id) {
+      return GetByIdQuery(DataContext, id);
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, UserPriority> GetByIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid userId) =>
+        (from userPriority in db.GetTable<UserPriority>()
+         where userPriority.UserId == userId
+         select userPriority).SingleOrDefault());
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Data/TableInformation.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Data/TableInformation.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Data/TableInformation.cs	(revision 12878)
@@ -0,0 +1,31 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Services.Hive.DataAccess.Data {
+  public class TableInformation {
+    public string Name { get; set; }
+    public int Rows { get; set; }
+    public int Reserved { get; set; }
+    public int Data { get; set; }
+    public int IndexSize { get; set; }
+    public int Unused { get; set; }
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HeuristicLab.Services.Hive.DataAccess-3.3.csproj
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HeuristicLab.Services.Hive.DataAccess-3.3.csproj	(revision 12753)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HeuristicLab.Services.Hive.DataAccess-3.3.csproj	(revision 12878)
@@ -104,7 +104,34 @@
   <ItemGroup>
     <None Include="Plugin.cs.frame" />
+    <Compile Include="Daos\AssignedResourceDao.cs" />
+    <Compile Include="Daos\DowntimeDao.cs" />
+    <Compile Include="Daos\GenericDao.cs" />
+    <Compile Include="Daos\HiveStatistics\DimClientDao.cs" />
+    <Compile Include="Daos\HiveStatistics\DimJobDao.cs" />
+    <Compile Include="Daos\HiveStatistics\DimTimeDao.cs" />
+    <Compile Include="Daos\HiveStatistics\DimUserDao.cs" />
+    <Compile Include="Daos\HiveStatistics\FactClientInfoDao.cs" />
+    <Compile Include="Daos\HiveStatistics\FactTaskDao.cs" />
+    <Compile Include="Daos\JobDao.cs" />
+    <Compile Include="Daos\JobPermissionDao.cs" />
+    <Compile Include="Daos\LifecycleDao.cs" />
+    <Compile Include="Daos\PluginDao.cs" />
+    <Compile Include="Daos\PluginDataDao.cs" />
+    <Compile Include="Daos\RequiredPluginDao.cs" />
+    <Compile Include="Daos\ResourceDao.cs" />
+    <Compile Include="Daos\ResourcePermissionDao.cs" />
+    <Compile Include="Daos\SlaveDao.cs" />
+    <Compile Include="Daos\SlaveGroupDao.cs" />
+    <Compile Include="Daos\StateLogDao.cs" />
+    <Compile Include="Daos\TaskDao.cs" />
+    <Compile Include="Daos\TaskDataDao.cs" />
+    <Compile Include="Daos\UserPriorityDao.cs" />
+    <Compile Include="Data\TableInformation.cs" />
+    <Compile Include="Interfaces\IGenericDao.cs" />
     <Compile Include="Enums\Command.cs" />
     <Compile Include="Enums\DowntimeType.cs" />
     <Compile Include="Enums\CpuArchitecture.cs" />
+    <Compile Include="Interfaces\IPersistenceManager.cs" />
+    <Compile Include="Manager\PersistenceManager.cs" />
     <Compile Include="Plugin.cs" />
     <Compile Include="HiveDataContext.cs">
@@ -116,5 +143,4 @@
       <DependentUpon>HiveDataContext.dbml</DependentUpon>
     </Compile>
-    <Compile Include="ITransactionManager.cs" />
     <Compile Include="Enums\TaskState.cs" />
     <Compile Include="Logger.cs" />
@@ -128,5 +154,4 @@
     </Compile>
     <Compile Include="Enums\SlaveState.cs" />
-    <Compile Include="TransactionManager.cs" />
   </ItemGroup>
   <ItemGroup>
@@ -155,7 +180,7 @@
   <ItemGroup>
     <Content Include="SQL Scripts\Initialize Hive Database.sql" />
-    <Content Include="SQL Scripts\Migrate to Filestream.sql" />
     <Content Include="SQL Scripts\Prepare Hive Database.sql" />
   </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <PropertyGroup>
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDao.cs	(revision 12753)
+++ 	(revision )
@@ -1,830 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Linq.Expressions;
-using HeuristicLab.Services.Hive.Common.DataTransfer;
-using DT = HeuristicLab.Services.Hive.Common.DataTransfer;
-
-namespace HeuristicLab.Services.Hive.DataAccess {
-  public class HiveDao : IHiveDao {
-    public static HiveDataContext CreateContext(bool longRunning = false) {
-      var context = new HiveDataContext(Settings.Default.HeuristicLab_Hive_LinqConnectionString);
-      if (longRunning) context.CommandTimeout = (int)Settings.Default.LongRunningDatabaseCommandTimeout.TotalSeconds;
-      return context;
-    }
-
-    public HiveDao() { }
-
-    #region Job Methods
-    public DT.Job GetJob(Guid id) {
-      using (var db = CreateContext()) {
-        return Convert.ToDto(db.Jobs.SingleOrDefault(x => x.JobId == id));
-      }
-    }
-
-    public IEnumerable<DT.Job> GetJobs(Expression<Func<Job, bool>> predicate) {
-      using (var db = CreateContext()) {
-        return db.Jobs.Where(predicate).Select(x => Convert.ToDto(x)).ToArray();
-      }
-    }
-
-    public Guid AddJob(DT.Job dto) {
-      using (var db = CreateContext()) {
-        var entity = Convert.ToEntity(dto);
-        db.Jobs.InsertOnSubmit(entity);
-        db.SubmitChanges();
-        foreach (Guid pluginId in dto.PluginsNeededIds) {
-          db.RequiredPlugins.InsertOnSubmit(new RequiredPlugin() { JobId = entity.JobId, PluginId = pluginId });
-        }
-        db.SubmitChanges();
-        return entity.JobId;
-      }
-    }
-
-    public void UpdateJob(DT.Job dto) {
-      using (var db = CreateContext()) {
-        var entity = db.Jobs.FirstOrDefault(x => x.JobId == dto.Id);
-        if (entity == null) db.Jobs.InsertOnSubmit(Convert.ToEntity(dto));
-        else Convert.ToEntity(dto, entity);
-        foreach (Guid pluginId in dto.PluginsNeededIds) {
-          if (db.RequiredPlugins.Count(p => p.PluginId == pluginId) == 0) {
-            db.RequiredPlugins.InsertOnSubmit(new RequiredPlugin() { JobId = entity.JobId, PluginId = pluginId });
-          }
-        }
-        db.SubmitChanges();
-      }
-    }
-
-    public void DeleteJob(Guid id) {
-      using (var db = CreateContext()) {
-        var entity = db.Jobs.FirstOrDefault(x => x.JobId == id);
-        if (entity != null) db.Jobs.DeleteOnSubmit(entity);
-        db.SubmitChanges(); // JobData and child jobs are deleted by db-trigger
-      }
-    }
-
-    /// <summary>
-    /// returns all parent jobs which are waiting for their child jobs to finish
-    /// </summary>
-    /// <param name="resourceIds">list of resourceids which for which the jobs should be valid</param>
-    /// <param name="count">maximum number of jobs to return</param>
-    /// <param name="finished">if true, all parent jobs which have FinishWhenChildJobsFinished=true are returned, otherwise only FinishWhenChildJobsFinished=false are returned</param>
-    /// <returns></returns>
-    public IEnumerable<DT.Job> GetParentJobs(IEnumerable<Guid> resourceIds, int count, bool finished) {
-      using (var db = CreateContext()) {
-        var query = from ar in db.AssignedResources
-                    where resourceIds.Contains(ar.ResourceId)
-                       && ar.Job.State == JobState.Waiting
-                       && ar.Job.IsParentJob
-                       && (finished ? ar.Job.FinishWhenChildJobsFinished : !ar.Job.FinishWhenChildJobsFinished)
-                       && (from child in db.Jobs
-                           where child.ParentJobId == ar.Job.JobId
-                           select child.State == JobState.Finished
-                               || child.State == JobState.Aborted
-                               || child.State == JobState.Failed).All(x => x)
-                       && (from child in db.Jobs // avoid returning WaitForChildJobs jobs where no child-jobs exist (yet)
-                           where child.ParentJobId == ar.Job.JobId
-                           select child).Count() > 0
-                    orderby ar.Job.Priority descending, db.Random()
-                    select Convert.ToDto(ar.Job);
-        return count == 0 ? query.ToArray() : query.Take(count).ToArray();
-      }
-    }
-
-    public IEnumerable<DT.Job> GetWaitingJobs(DT.Slave slave, int count) {
-      using (var db = CreateContext()) {
-        var resourceIds = GetParentResources(slave.Id).Select(r => r.Id);
-        var waitingParentJobs = GetParentJobs(resourceIds, count, false);
-        if (count > 0 && waitingParentJobs.Count() >= count) return waitingParentJobs.Take(count).ToArray();
-
-        var query = from ar in db.AssignedResources
-                    where resourceIds.Contains(ar.ResourceId)
-                       && !(ar.Job.IsParentJob && ar.Job.FinishWhenChildJobsFinished)
-                       && ar.Job.State == JobState.Waiting
-                       && ar.Job.CoresNeeded <= slave.FreeCores
-                       && ar.Job.MemoryNeeded <= slave.FreeMemory
-                    orderby ar.Job.Priority descending, db.Random() // take random job to avoid the race condition that occurs when this method is called concurrently (the same job would be returned)
-                    select Convert.ToDto(ar.Job);
-        var waitingJobs = (count == 0 ? query : query.Take(count)).ToArray();
-        return waitingJobs.Union(waitingParentJobs).OrderByDescending(x => x.Priority);
-      }
-    }
-
-    public DT.Job UpdateJobState(Guid jobId, JobState jobState, Guid? slaveId, Guid? userId, string exception) {
-      using (var db = CreateContext()) {
-        var job = db.Jobs.SingleOrDefault(x => x.JobId == jobId);
-        job.State = jobState;
-        db.StateLogs.InsertOnSubmit(new StateLog {
-          JobId = jobId,
-          State = jobState,
-          SlaveId = slaveId,
-          UserId = userId,
-          Exception = exception,
-          DateTime = DateTime.Now
-        });
-        db.SubmitChanges();
-        job = db.Jobs.SingleOrDefault(x => x.JobId == jobId);
-        return Convert.ToDto(job);
-      }
-    }
-    #endregion
-
-    #region JobData Methods
-    public DT.JobData GetJobData(Guid id) {
-      using (var db = CreateContext(true)) {
-        return Convert.ToDto(db.JobDatas.SingleOrDefault(x => x.JobId == id));
-      }
-    }
-
-    public IEnumerable<DT.JobData> GetJobDatas(Expression<Func<JobData, bool>> predicate) {
-      using (var db = CreateContext(true)) {
-        return db.JobDatas.Where(predicate).Select(x => Convert.ToDto(x)).ToArray();
-      }
-    }
-
-    public Guid AddJobData(DT.JobData dto) {
-      using (var db = CreateContext(true)) {
-        var entity = Convert.ToEntity(dto);
-        db.JobDatas.InsertOnSubmit(entity);
-        db.SubmitChanges();
-        return entity.JobId;
-      }
-    }
-
-    public void UpdateJobData(DT.JobData dto) {
-      using (var db = CreateContext(true)) {
-        var entity = db.JobDatas.FirstOrDefault(x => x.JobId == dto.JobId);
-        if (entity == null) db.JobDatas.InsertOnSubmit(Convert.ToEntity(dto));
-        else Convert.ToEntity(dto, entity);
-        db.SubmitChanges();
-      }
-    }
-
-    public void DeleteJobData(Guid id) {
-      using (var db = CreateContext()) {
-        var entity = db.JobDatas.FirstOrDefault(x => x.JobId == id); // check if all the byte[] is loaded into memory here. otherwise work around to delete without loading it
-        if (entity != null) db.JobDatas.DeleteOnSubmit(entity);
-        db.SubmitChanges();
-      }
-    }
-    #endregion
-
-    #region StateLog Methods
-    public DT.StateLog GetStateLog(Guid id) {
-      using (var db = CreateContext()) {
-        return Convert.ToDto(db.StateLogs.SingleOrDefault(x => x.StateLogId == id));
-      }
-    }
-
-    public IEnumerable<DT.StateLog> GetStateLogs(Expression<Func<StateLog, bool>> predicate) {
-      using (var db = CreateContext()) {
-        return db.StateLogs.Where(predicate).Select(x => Convert.ToDto(x)).ToArray();
-      }
-    }
-
-    public Guid AddStateLog(DT.StateLog dto) {
-      using (var db = CreateContext()) {
-        var entity = Convert.ToEntity(dto);
-        db.StateLogs.InsertOnSubmit(entity);
-        db.SubmitChanges();
-        return entity.StateLogId;
-      }
-    }
-
-    public void UpdateStateLog(DT.StateLog dto) {
-      using (var db = CreateContext()) {
-        var entity = db.StateLogs.FirstOrDefault(x => x.StateLogId == dto.Id);
-        if (entity == null) db.StateLogs.InsertOnSubmit(Convert.ToEntity(dto));
-        else Convert.ToEntity(dto, entity);
-        db.SubmitChanges();
-      }
-    }
-
-    public void DeleteStateLog(Guid id) {
-      using (var db = CreateContext()) {
-        var entity = db.StateLogs.FirstOrDefault(x => x.StateLogId == id);
-        if (entity != null) db.StateLogs.DeleteOnSubmit(entity);
-        db.SubmitChanges();
-      }
-    }
-    #endregion
-
-    #region HiveExperiment Methods
-    public DT.HiveExperiment GetHiveExperiment(Guid id) {
-      using (var db = CreateContext()) {
-        return AddStatsToExperiment(db, Convert.ToDto(db.HiveExperiments.SingleOrDefault(x => x.HiveExperimentId == id)));
-      }
-    }
-
-    private DT.HiveExperiment AddStatsToExperiment(HiveDataContext db, DT.HiveExperiment exp) {
-      if (exp == null)
-        return null;
-
-      var jobs = db.Jobs.Where(j => j.HiveExperimentId == exp.Id);
-      exp.JobCount = jobs.Count();
-      exp.CalculatingCount = jobs.Count(j => j.State == JobState.Calculating);
-      exp.FinishedCount = jobs.Count(j => j.State == JobState.Finished);
-      return exp;
-    }
-
-    public IEnumerable<DT.HiveExperiment> GetHiveExperiments(Expression<Func<HiveExperiment, bool>> predicate) {
-      using (var db = CreateContext()) {
-        return db.HiveExperiments.Where(predicate).Select(x => AddStatsToExperiment(db, Convert.ToDto(x))).ToArray();
-      }
-    }
-
-    public Guid AddHiveExperiment(DT.HiveExperiment dto) {
-      using (var db = CreateContext()) {
-        var entity = Convert.ToEntity(dto);
-        db.HiveExperiments.InsertOnSubmit(entity);
-        db.SubmitChanges();
-        return entity.HiveExperimentId;
-      }
-    }
-
-    public void UpdateHiveExperiment(DT.HiveExperiment dto) {
-      using (var db = CreateContext()) {
-        var entity = db.HiveExperiments.FirstOrDefault(x => x.HiveExperimentId == dto.Id);
-        if (entity == null) db.HiveExperiments.InsertOnSubmit(Convert.ToEntity(dto));
-        else Convert.ToEntity(dto, entity);
-        db.SubmitChanges();
-      }
-    }
-
-    public void DeleteHiveExperiment(Guid id) {
-      using (var db = CreateContext()) {
-        var entity = db.HiveExperiments.FirstOrDefault(x => x.HiveExperimentId == id);
-        if (entity != null) db.HiveExperiments.DeleteOnSubmit(entity);
-        db.SubmitChanges();
-      }
-    }
-    #endregion
-
-    #region HiveExperimentPermission Methods
-    public DT.HiveExperimentPermission GetHiveExperimentPermission(Guid hiveExperimentId, Guid grantedUserId) {
-      using (var db = CreateContext()) {
-        return Convert.ToDto(db.HiveExperimentPermissions.SingleOrDefault(x => x.HiveExperimentId == hiveExperimentId && x.GrantedUserId == grantedUserId));
-      }
-    }
-
-    public IEnumerable<DT.HiveExperimentPermission> GetHiveExperimentPermissions(Expression<Func<HiveExperimentPermission, bool>> predicate) {
-      using (var db = CreateContext()) {
-        return db.HiveExperimentPermissions.Where(predicate).Select(x => Convert.ToDto(x)).ToArray();
-      }
-    }
-
-    public void AddHiveExperimentPermission(DT.HiveExperimentPermission dto) {
-      using (var db = CreateContext()) {
-        var entity = Convert.ToEntity(dto);
-        db.HiveExperimentPermissions.InsertOnSubmit(entity);
-        db.SubmitChanges();
-      }
-    }
-
-    public void UpdateHiveExperimentPermission(DT.HiveExperimentPermission dto) {
-      using (var db = CreateContext()) {
-        var entity = db.HiveExperimentPermissions.FirstOrDefault(x => x.HiveExperimentId == dto.HiveExperimentId && x.GrantedUserId == dto.GrantedUserId);
-        if (entity == null) db.HiveExperimentPermissions.InsertOnSubmit(Convert.ToEntity(dto));
-        else Convert.ToEntity(dto, entity);
-        db.SubmitChanges();
-      }
-    }
-
-    public void DeleteHiveExperimentPermission(Guid hiveExperimentId, Guid grantedUserId) {
-      using (var db = CreateContext()) {
-        var entity = db.HiveExperimentPermissions.FirstOrDefault(x => x.HiveExperimentId == hiveExperimentId && x.GrantedUserId == grantedUserId);
-        if (entity != null) db.HiveExperimentPermissions.DeleteOnSubmit(entity);
-        db.SubmitChanges();
-      }
-    }
-
-    /// <summary>
-    /// Sets the permissions for a experiment. makes sure that only one permission per user exists.
-    /// </summary>
-    public void SetHiveExperimentPermission(Guid hiveExperimentId, Guid grantedByUserId, Guid grantedUserId, Permission permission) {
-      using (var db = CreateContext()) {
-        HiveExperimentPermission hiveExperimentPermission = db.HiveExperimentPermissions.SingleOrDefault(x => x.HiveExperimentId == hiveExperimentId && x.GrantedUserId == grantedUserId);
-        if (hiveExperimentPermission != null) {
-          if (permission == Permission.NotAllowed) {
-            // not allowed, delete
-            db.HiveExperimentPermissions.DeleteOnSubmit(hiveExperimentPermission);
-          } else {
-            // update
-            hiveExperimentPermission.Permission = permission;
-            hiveExperimentPermission.GrantedByUserId = grantedByUserId; // update grantedByUserId, always the last "granter" is stored
-          }
-        } else {
-          // insert
-          if (permission != Permission.NotAllowed) {
-            hiveExperimentPermission = new HiveExperimentPermission() { HiveExperimentId = hiveExperimentId, GrantedByUserId = grantedByUserId, GrantedUserId = grantedUserId, Permission = permission };
-            db.HiveExperimentPermissions.InsertOnSubmit(hiveExperimentPermission);
-          }
-        }
-        db.SubmitChanges();
-      }
-    }
-    #endregion
-
-    #region Plugin Methods
-    public DT.Plugin GetPlugin(Guid id) {
-      using (var db = CreateContext()) {
-        return Convert.ToDto(db.Plugins.SingleOrDefault(x => x.PluginId == id));
-      }
-    }
-
-    public IEnumerable<DT.Plugin> GetPlugins(Expression<Func<Plugin, bool>> predicate) {
-      using (var db = CreateContext()) {
-        return db.Plugins.Where(predicate).Select(x => Convert.ToDto(x)).ToArray();
-      }
-    }
-
-    public Guid AddPlugin(DT.Plugin dto) {
-      using (var db = CreateContext()) {
-        var entity = Convert.ToEntity(dto);
-        db.Plugins.InsertOnSubmit(entity);
-        db.SubmitChanges();
-        return entity.PluginId;
-      }
-    }
-
-    public void UpdatePlugin(DT.Plugin dto) {
-      using (var db = CreateContext()) {
-        var entity = db.Plugins.FirstOrDefault(x => x.PluginId == dto.Id);
-        if (entity == null) db.Plugins.InsertOnSubmit(Convert.ToEntity(dto));
-        else Convert.ToEntity(dto, entity);
-        db.SubmitChanges();
-      }
-    }
-
-    public void DeletePlugin(Guid id) {
-      using (var db = CreateContext()) {
-        var entity = db.Plugins.FirstOrDefault(x => x.PluginId == id);
-        if (entity != null) db.Plugins.DeleteOnSubmit(entity);
-        db.SubmitChanges();
-      }
-    }
-    #endregion
-
-    #region PluginData Methods
-    public DT.PluginData GetPluginData(Guid id) {
-      using (var db = CreateContext()) {
-        return Convert.ToDto(db.PluginDatas.SingleOrDefault(x => x.PluginDataId == id));
-      }
-    }
-
-    public IEnumerable<DT.PluginData> GetPluginDatas(Expression<Func<PluginData, bool>> predicate) {
-      using (var db = CreateContext()) {
-        return db.PluginDatas.Where(predicate).Select(x => Convert.ToDto(x)).ToArray();
-      }
-    }
-
-    public Guid AddPluginData(DT.PluginData dto) {
-      using (var db = CreateContext()) {
-        var entity = Convert.ToEntity(dto);
-        db.PluginDatas.InsertOnSubmit(entity);
-        db.SubmitChanges();
-        return entity.PluginDataId;
-      }
-    }
-
-    public void UpdatePluginData(DT.PluginData dto) {
-      using (var db = CreateContext()) {
-        var entity = db.PluginDatas.FirstOrDefault(x => x.PluginId == dto.PluginId);
-        if (entity == null) db.PluginDatas.InsertOnSubmit(Convert.ToEntity(dto));
-        else Convert.ToEntity(dto, entity);
-        db.SubmitChanges();
-      }
-    }
-
-    public void DeletePluginData(Guid id) {
-      using (var db = CreateContext()) {
-        var entity = db.PluginDatas.FirstOrDefault(x => x.PluginDataId == id);
-        if (entity != null) db.PluginDatas.DeleteOnSubmit(entity);
-        db.SubmitChanges();
-      }
-    }
-    #endregion
-
-    #region Slave Methods
-    public DT.Slave GetSlave(Guid id) {
-      using (var db = CreateContext()) {
-        return Convert.ToDto(db.Resources.OfType<Slave>().SingleOrDefault(x => x.ResourceId == id));
-      }
-    }
-
-    public IEnumerable<DT.Slave> GetSlaves(Expression<Func<Slave, bool>> predicate) {
-      using (var db = CreateContext()) {
-        return db.Resources.OfType<Slave>().Where(predicate).Select(x => Convert.ToDto(x)).ToArray();
-      }
-    }
-
-    public Guid AddSlave(DT.Slave dto) {
-      using (var db = CreateContext()) {
-        var entity = Convert.ToEntity(dto);
-        db.Resources.InsertOnSubmit(entity);
-        db.SubmitChanges();
-        return entity.ResourceId;
-      }
-    }
-
-    public void UpdateSlave(DT.Slave dto) {
-      using (var db = CreateContext()) {
-        var entity = db.Resources.OfType<Slave>().FirstOrDefault(x => x.ResourceId == dto.Id);
-        if (entity == null) db.Resources.InsertOnSubmit(Convert.ToEntity(dto));
-        else Convert.ToEntity(dto, entity);
-        db.SubmitChanges();
-      }
-    }
-
-    public void DeleteSlave(Guid id) {
-      using (var db = CreateContext()) {
-        var entity = db.Resources.OfType<Slave>().FirstOrDefault(x => x.ResourceId == id);
-        if (entity != null) db.Resources.DeleteOnSubmit(entity);
-        db.SubmitChanges();
-      }
-    }
-    #endregion
-
-    #region SlaveGroup Methods
-    public DT.SlaveGroup GetSlaveGroup(Guid id) {
-      using (var db = CreateContext()) {
-        return Convert.ToDto(db.Resources.OfType<SlaveGroup>().SingleOrDefault(x => x.ResourceId == id));
-      }
-    }
-
-    public IEnumerable<DT.SlaveGroup> GetSlaveGroups(Expression<Func<SlaveGroup, bool>> predicate) {
-      using (var db = CreateContext()) {
-        return db.Resources.OfType<SlaveGroup>().Where(predicate).Select(x => Convert.ToDto(x)).ToArray();
-      }
-    }
-
-    public Guid AddSlaveGroup(DT.SlaveGroup dto) {
-      using (var db = CreateContext()) {
-        if (dto.Id == Guid.Empty)
-          dto.Id = Guid.NewGuid();
-        var entity = Convert.ToEntity(dto);
-        db.Resources.InsertOnSubmit(entity);
-        db.SubmitChanges();
-        return entity.ResourceId;
-      }
-    }
-
-    public void UpdateSlaveGroup(DT.SlaveGroup dto) {
-      using (var db = CreateContext()) {
-        var entity = db.Resources.OfType<SlaveGroup>().FirstOrDefault(x => x.ResourceId == dto.Id);
-        if (entity == null) db.Resources.InsertOnSubmit(Convert.ToEntity(dto));
-        else Convert.ToEntity(dto, entity);
-        db.SubmitChanges();
-      }
-    }
-
-    public void DeleteSlaveGroup(Guid id) {
-      using (var db = CreateContext()) {
-        var entity = db.Resources.OfType<SlaveGroup>().FirstOrDefault(x => x.ResourceId == id);
-        if (entity != null) {
-          if (db.Resources.Where(r => r.ParentResourceId == id).Count() > 0) {
-            throw new InvalidOperationException("Cannot delete SlaveGroup as long as there are Slaves in the group");
-          }
-          db.Resources.DeleteOnSubmit(entity);
-        }
-        db.SubmitChanges();
-      }
-    }
-    #endregion
-
-    #region Resource Methods
-    public DT.Resource GetResource(Guid id) {
-      using (var db = CreateContext()) {
-        return Convert.ToDto(db.Resources.SingleOrDefault(x => x.ResourceId == id));
-      }
-    }
-
-    public IEnumerable<DT.Resource> GetResources(Expression<Func<Resource, bool>> predicate) {
-      using (var db = CreateContext()) {
-        return db.Resources.Where(predicate).Select(x => Convert.ToDto(x)).ToArray();
-      }
-    }
-
-    public Guid AddResource(DT.Resource dto) {
-      using (var db = CreateContext()) {
-        var entity = Convert.ToEntity(dto);
-        db.Resources.InsertOnSubmit(entity);
-        db.SubmitChanges();
-        return entity.ResourceId;
-      }
-    }
-
-    public void UpdateResource(DT.Resource dto) {
-      using (var db = CreateContext()) {
-        var entity = db.Resources.FirstOrDefault(x => x.ResourceId == dto.Id);
-        if (entity == null) db.Resources.InsertOnSubmit(Convert.ToEntity(dto));
-        else Convert.ToEntity(dto, entity);
-        db.SubmitChanges();
-      }
-    }
-
-    public void DeleteResource(Guid id) {
-      using (var db = CreateContext()) {
-        var entity = db.Resources.FirstOrDefault(x => x.ResourceId == id);
-        if (entity != null) db.Resources.DeleteOnSubmit(entity);
-        db.SubmitChanges();
-      }
-    }
-
-    public void AssignJobToResource(Guid jobId, Guid resourceId) {
-      using (var db = CreateContext()) {
-        var job = db.Jobs.Where(x => x.JobId == jobId).Single();
-        job.AssignedResources.Add(new AssignedResource() { JobId = jobId, ResourceId = resourceId });
-        db.SubmitChanges();
-      }
-    }
-
-    public IEnumerable<DT.Resource> GetAssignedResources(Guid jobId) {
-      using (var db = CreateContext()) {
-        var job = db.Jobs.Where(x => x.JobId == jobId).Single();
-        return job.AssignedResources.Select(x => Convert.ToDto(x.Resource)).ToArray();
-      }
-    }
-
-    /// <summary>
-    /// Returns all parent resources of a resource (the given resource is also added)
-    /// </summary>
-    public IEnumerable<DT.Resource> GetParentResources(Guid resourceId) {
-      using (var db = CreateContext()) {
-        var resources = new List<Resource>();
-        CollectParentResources(resources, db.Resources.Where(r => r.ResourceId == resourceId).Single());
-        return resources.Select(r => Convert.ToDto(r)).ToArray();
-      }
-    }
-
-    private void CollectParentResources(List<Resource> resources, Resource resource) {
-      if (resource == null) return;
-      resources.Add(resource);
-      CollectParentResources(resources, resource.ParentResource);
-    }
-
-    /// <summary>
-    /// Returns all child resources of a resource (without the given resource)
-    /// </summary>
-    public IEnumerable<DT.Resource> GetChildResources(Guid resourceId) {
-      using (var db = CreateContext()) {
-        var childs = new List<DT.Resource>();
-        foreach (var child in db.Resources.Where(x => x.ParentResourceId == resourceId)) {
-          childs.Add(Convert.ToDto(child));
-          childs.AddRange(GetChildResources(child.ResourceId));
-        }
-        return childs;
-      }
-    }
-
-    public IEnumerable<DT.Job> GetJobsByResourceId(Guid resourceId) {
-      using (var db = CreateContext()) {
-        var resources = GetChildResources(resourceId).Select(x => x.Id).ToList();
-        resources.Add(resourceId);
-
-        var jobs = db.Jobs.Where(j =>
-          j.State == JobState.Calculating &&
-          j.StateLogs.OrderByDescending(x => x.DateTime).First().SlaveId.HasValue &&
-          resources.Contains(j.StateLogs.OrderByDescending(x => x.DateTime).First().SlaveId.Value));
-        return jobs.Select(j => Convert.ToDto(j)).ToArray();
-      }
-    }
-    #endregion
-
-    #region Authorization Methods
-    public Permission GetPermissionForJob(Guid jobId, Guid userId) {
-      using (var db = CreateContext()) {
-        return GetPermissionForExperiment(GetExperimentForJob(jobId), userId);
-      }
-    }
-
-    public Permission GetPermissionForExperiment(Guid experimentId, Guid userId) {
-      using (var db = CreateContext()) {
-        HiveExperiment hiveExperiment = db.HiveExperiments.SingleOrDefault(x => x.HiveExperimentId == experimentId);
-        if (hiveExperiment == null) return Permission.NotAllowed;
-        if (hiveExperiment.OwnerUserId == userId) return Permission.Full;
-        HiveExperimentPermission permission = db.HiveExperimentPermissions.SingleOrDefault(p => p.HiveExperimentId == experimentId && p.GrantedUserId == userId);
-        return permission != null ? permission.Permission : Permission.NotAllowed;
-      }
-    }
-
-    public Guid GetExperimentForJob(Guid jobId) {
-      using (var db = CreateContext()) {
-        return db.Jobs.Single(j => j.JobId == jobId).HiveExperimentId;
-      }
-    }
-    #endregion
-
-    #region Lifecycle Methods
-    public DateTime GetLastCleanup() {
-      using (var db = CreateContext()) {
-        var entity = db.Lifecycles.SingleOrDefault();
-        return entity != null ? entity.LastCleanup : DateTime.MinValue;
-      }
-    }
-
-    public void SetLastCleanup(DateTime datetime) {
-      using (var db = CreateContext()) {
-        var entity = db.Lifecycles.SingleOrDefault();
-        if (entity != null) {
-          entity.LastCleanup = datetime;
-        } else {
-          entity = new Lifecycle();
-          entity.LifecycleId = 0; // always only one entry with ID:0
-          entity.LastCleanup = datetime;
-          db.Lifecycles.InsertOnSubmit(entity);
-        }
-        db.SubmitChanges();
-      }
-    }
-    #endregion
-
-    #region Downtime Methods
-    public DT.Downtime GetDowntime(Guid id) {
-      using (var db = CreateContext()) {
-        return Convert.ToDto(db.Downtimes.SingleOrDefault(x => x.DowntimeId == id));
-      }
-    }
-
-    public IEnumerable<DT.Downtime> GetDowntimes(Expression<Func<Downtime, bool>> predicate) {
-      using (var db = CreateContext()) {
-        return db.Downtimes.Where(predicate).Select(x => Convert.ToDto(x)).ToArray();
-      }
-    }
-
-    public Guid AddDowntime(DT.Downtime dto) {
-      using (var db = CreateContext()) {
-        var entity = Convert.ToEntity(dto);
-        db.Downtimes.InsertOnSubmit(entity);
-        db.SubmitChanges();
-        return entity.DowntimeId;
-      }
-    }
-
-    public void UpdateDowntime(DT.Downtime dto) {
-      using (var db = CreateContext()) {
-        var entity = db.Downtimes.FirstOrDefault(x => x.DowntimeId == dto.Id);
-        if (entity == null) db.Downtimes.InsertOnSubmit(Convert.ToEntity(dto));
-        else Convert.ToEntity(dto, entity);
-        db.SubmitChanges();
-      }
-    }
-
-    public void DeleteDowntime(Guid id) {
-      using (var db = CreateContext()) {
-        var entity = db.Downtimes.FirstOrDefault(x => x.DowntimeId == id);
-        if (entity != null) db.Downtimes.DeleteOnSubmit(entity);
-        db.SubmitChanges();
-      }
-    }
-    #endregion
-
-    #region Statistics Methods
-    public DT.Statistics GetStatistic(Guid id) {
-      using (var db = CreateContext()) {
-        return Convert.ToDto(db.Statistics.SingleOrDefault(x => x.StatisticsId == id));
-      }
-    }
-
-    public IEnumerable<DT.Statistics> GetStatistics(Expression<Func<Statistics, bool>> predicate) {
-      using (var db = CreateContext()) {
-        return db.Statistics.Where(predicate).Select(x => Convert.ToDto(x)).ToArray();
-      }
-    }
-
-    public Guid AddStatistics(DT.Statistics dto) {
-      using (var db = CreateContext()) {
-        var entity = Convert.ToEntity(dto);
-        db.Statistics.InsertOnSubmit(entity);
-        db.SubmitChanges();
-        foreach (var slaveStat in dto.SlaveStatistics) {
-          slaveStat.Id = entity.StatisticsId;
-          db.SlaveStatistics.InsertOnSubmit(Convert.ToEntity(slaveStat));
-        }
-        foreach (var userStat in dto.UserStatistics) {
-          userStat.Id = entity.StatisticsId;
-          db.UserStatistics.InsertOnSubmit(Convert.ToEntity(userStat));
-        }
-        db.SubmitChanges();
-        return entity.StatisticsId;
-      }
-    }
-
-    public void DeleteStatistics(Guid id) {
-      using (var db = CreateContext()) {
-        var entity = db.Statistics.FirstOrDefault(x => x.StatisticsId == id);
-        if (entity != null) db.Statistics.DeleteOnSubmit(entity);
-        db.SubmitChanges();
-      }
-    }
-
-    public List<DT.UserStatistics> GetUserStatistics() {
-      using (var db = CreateContext()) {
-        var userStats = new Dictionary<Guid, DT.UserStatistics>();
-
-        var usedCoresByUser = from job in db.Jobs
-                              where job.State == JobState.Calculating
-                              group job by job.HiveExperiment.OwnerUserId into g
-                              select new { UserId = g.Key, UsedCores = g.Count() };
-
-        foreach (var item in usedCoresByUser) {
-          if (!userStats.ContainsKey(item.UserId)) {
-            userStats.Add(item.UserId, new DT.UserStatistics() { UserId = item.UserId });
-          }
-          userStats[item.UserId].UsedCores += item.UsedCores;
-        }
-
-        var executionTimesByUser = from job in db.Jobs
-                                   group job by job.HiveExperiment.OwnerUserId into g
-                                   select new { UserId = g.Key, ExecutionTime = TimeSpan.FromMilliseconds(g.Select(x => x.ExecutionTimeMs).Sum()) };
-        foreach (var item in executionTimesByUser) {
-          if (!userStats.ContainsKey(item.UserId)) {
-            userStats.Add(item.UserId, new DT.UserStatistics() { UserId = item.UserId });
-          }
-          userStats[item.UserId].ExecutionTime += item.ExecutionTime;
-        }
-
-        // execution times only of finished jobs - necessary to compute efficieny
-        var executionTimesFinishedJobs = from job in db.Jobs
-                                         where job.State == JobState.Finished
-                                         group job by job.HiveExperiment.OwnerUserId into g
-                                         select new { UserId = g.Key, ExecutionTimeFinishedJobs = TimeSpan.FromMilliseconds(g.Select(x => x.ExecutionTimeMs).Sum()) };
-
-        foreach (var item in executionTimesFinishedJobs) {
-          if (!userStats.ContainsKey(item.UserId)) {
-            userStats.Add(item.UserId, new DT.UserStatistics() { UserId = item.UserId });
-          }
-          userStats[item.UserId].ExecutionTimeFinishedJobs += item.ExecutionTimeFinishedJobs;
-        }
-
-        // start to end times only of finished jobs - necessary to compute efficiency
-        var startToEndTimesFinishedJobs = from job in db.Jobs
-                                          where job.State == JobState.Finished
-                                          group job by job.HiveExperiment.OwnerUserId into g
-                                          select new {
-                                            UserId = g.Key,
-                                            StartToEndTime = new TimeSpan(g.Select(x => x.StateLogs.OrderByDescending(sl => sl.DateTime).First().DateTime - x.StateLogs.OrderBy(sl => sl.DateTime).First().DateTime).Sum(ts => ts.Ticks))
-                                          };
-        foreach (var item in startToEndTimesFinishedJobs) {
-          if (!userStats.ContainsKey(item.UserId)) {
-            userStats.Add(item.UserId, new DT.UserStatistics() { UserId = item.UserId });
-          }
-          userStats[item.UserId].StartToEndTime += item.StartToEndTime;
-        }
-
-        // also consider executiontimes of DeletedJobStats 
-        var deletedJobsExecutionTimesByUsers = from del in db.DeletedJobStatistics
-                                               group del by del.UserId into g
-                                               select new {
-                                                 UserId = g.Key,
-                                                 ExecutionTime = TimeSpan.FromMilliseconds(g.Select(x => x.ExecutionTimeMs).Sum()),
-                                                 ExecutionTimeFinishedJobs = TimeSpan.FromMilliseconds(g.Select(x => x.ExecutionTimeMsFinishedJobs).Sum()),
-                                                 StartToEndTime = TimeSpan.FromMilliseconds(g.Select(x => x.StartToEndTimeMs).Sum())
-                                               };
-        foreach (var item in deletedJobsExecutionTimesByUsers) {
-          if (!userStats.ContainsKey(item.UserId)) {
-            userStats.Add(item.UserId, new DT.UserStatistics() { UserId = item.UserId });
-          }
-          userStats[item.UserId].ExecutionTime += item.ExecutionTime;
-          userStats[item.UserId].ExecutionTimeFinishedJobs += item.ExecutionTimeFinishedJobs;
-          userStats[item.UserId].StartToEndTime += item.StartToEndTime;
-        }
-
-        return userStats.Values.ToList();
-      }
-    }
-    #endregion
-
-    #region Helpers
-    private void CollectChildJobs(HiveDataContext db, Guid parentJobId, List<Job> collection) {
-      var jobs = db.Jobs.Where(j => j.ParentJobId == parentJobId);
-      foreach (var job in jobs) {
-        collection.Add(job);
-        if (job.IsParentJob)
-          CollectChildJobs(db, job.JobId, collection);
-      }
-    }
-    #endregion
-  }
-}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDataContext.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDataContext.cs	(revision 12753)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDataContext.cs	(revision 12878)
@@ -30,4 +30,8 @@
       throw new NotImplementedException();
     }
+
+    partial void OnCreated() {
+      LogFactory.GetLogger(this.GetType().Namespace).Log("HiveDataContext created");
+    }
   }
 }
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDataContext.dbml
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDataContext.dbml	(revision 12753)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDataContext.dbml	(revision 12878)
@@ -156,44 +156,4 @@
     </Type>
   </Table>
-  <Table Name="" Member="DeletedJobStatistics">
-    <Type Name="DeletedJobStatistics">
-      <Column Name="UserId" Type="System.Guid" DbType="UniqueIdentifier NOT NULL" CanBeNull="false" />
-      <Column Name="ExecutionTimeS" Storage="_ExecutionTime" Type="System.Double" DbType="float NOT NULL" CanBeNull="false" />
-      <Column Name="ExecutionTimeSFinishedJobs" Storage="_ExecutionTimeFinishedJobs" Type="System.Double" DbType="float NOT NULL" CanBeNull="false" />
-      <Column Name="StartToEndTimeS" Storage="_StartToEndTime" Type="System.Double" DbType="float NOT NULL" CanBeNull="false" />
-      <Column Name="DeletedJobStatisticsId" Type="System.Guid" DbType="UniqueIdentifier NOT NULL" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" />
-    </Type>
-  </Table>
-  <Table Name="" Member="UserStatistics">
-    <Type Name="UserStatistics">
-      <Column Name="StatisticsId" Type="System.Guid" DbType="UniqueIdentifier NOT NULL" IsPrimaryKey="true" CanBeNull="false" />
-      <Column Name="UserId" Type="System.Guid" DbType="UniqueIdentifier NOT NULL" IsPrimaryKey="true" CanBeNull="false" />
-      <Column Name="ExecutionTimeMs" Storage="_ExecutionTime" Type="System.Double" DbType="float NOT NULL" CanBeNull="false" />
-      <Column Name="UsedCores" Storage="_CoresUsed" Type="System.Int32" DbType="Int NOT NULL" CanBeNull="false" />
-      <Column Name="ExecutionTimeMsFinishedJobs" Storage="_ExecutionTimeFinishedJobs" Type="System.Double" DbType="float NOT NULL" CanBeNull="false" />
-      <Column Name="StartToEndTimeMs" Storage="_StartToEndTime" Type="System.Double" DbType="float NOT NULL" CanBeNull="false" />
-      <Association Name="Statistics_UserStatistics" Member="Statistics" ThisKey="StatisticsId" OtherKey="StatisticsId" Type="Statistics" IsForeignKey="true" />
-    </Type>
-  </Table>
-  <Table Name="" Member="SlaveStatistics">
-    <Type Name="SlaveStatistics">
-      <Column Name="StatisticsId" Type="System.Guid" DbType="UniqueIdentifier NOT NULL" IsPrimaryKey="true" CanBeNull="false" />
-      <Column Name="SlaveId" Type="System.Guid" DbType="UniqueIdentifier NOT NULL" IsPrimaryKey="true" CanBeNull="false" />
-      <Column Name="Cores" Type="System.Int32" DbType="Int NOT NULL" CanBeNull="false" />
-      <Column Name="FreeCores" Type="System.Int32" DbType="Int NOT NULL" CanBeNull="false" />
-      <Column Name="CpuUtilization" Type="System.Double" DbType="float NOT NULL" CanBeNull="false" />
-      <Column Name="Memory" Type="System.Int32" DbType="Int NOT NULL" CanBeNull="false" />
-      <Column Name="FreeMemory" Type="System.Int32" DbType="Int NOT NULL" CanBeNull="false" />
-      <Association Name="Statistics_SlaveStatistics" Member="Statistics" ThisKey="StatisticsId" OtherKey="StatisticsId" Type="Statistics" IsForeignKey="true" />
-    </Type>
-  </Table>
-  <Table Name="" Member="Statistics">
-    <Type Name="Statistics">
-      <Column Name="StatisticsId" Type="System.Guid" DbType="UniqueIdentifier NOT NULL" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" />
-      <Column Name="Timestamp" Type="System.DateTime" CanBeNull="false" />
-      <Association Name="Statistics_UserStatistics" Member="UserStatistics" ThisKey="StatisticsId" OtherKey="StatisticsId" Type="UserStatistics" />
-      <Association Name="Statistics_SlaveStatistics" Member="SlaveStatistics" ThisKey="StatisticsId" OtherKey="StatisticsId" Type="SlaveStatistics" />
-    </Type>
-  </Table>
   <Table Name="dbo.ResourcePermission" Member="ResourcePermissions">
     <Type Name="ResourcePermission">
@@ -210,3 +170,90 @@
     </Type>
   </Table>
+  <Table Name="[statistics].DimClient" Member="DimClients">
+    <Type Name="DimClient">
+      <Column Name="Id" Type="System.Guid" DbType="UniqueIdentifier NOT NULL" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" />
+      <Column Name="Name" Type="System.String" DbType="VarChar(MAX) NOT NULL" CanBeNull="false" />
+      <Column Name="ResourceId" Type="System.Guid" DbType="UniqueIdentifier NOT NULL" CanBeNull="false" />
+      <Column Name="ExpirationTime" Type="System.DateTime" DbType="DateTime" CanBeNull="true" />
+      <Column Name="ResourceGroupId" Type="System.Guid" DbType="UniqueIdentifier" CanBeNull="true" />
+      <Column Name="ResourceGroup2Id" Type="System.Guid" DbType="UniqueIdentifier" CanBeNull="true" />
+      <Column Name="GroupName" Type="System.String" CanBeNull="true" />
+      <Column Name="GroupName2" Type="System.String" CanBeNull="true" />
+      <Association Name="DimClient_FactTask" Member="FactTasks" ThisKey="Id" OtherKey="LastClientId" Type="FactTask" />
+      <Association Name="DimClient_FactClientInfo" Member="FactClientInfos" ThisKey="Id" OtherKey="ClientId" Type="FactClientInfo" />
+    </Type>
+  </Table>
+  <Table Name="[statistics].FactTask" Member="FactTasks">
+    <Type Name="FactTask">
+      <Column Name="TaskId" Type="System.Guid" DbType="UniqueIdentifier NOT NULL" IsPrimaryKey="true" CanBeNull="false" />
+      <Column Name="CalculatingTime" Storage="_TotalRuntime" Type="System.Int64" DbType="INT NOT NULL" CanBeNull="false" />
+      <Column Name="WaitingTime" Storage="_TotalWaitingTime" Type="System.Int64" DbType="INT NOT NULL" CanBeNull="false" />
+      <Column Name="TransferTime" Storage="_TotalTransferTime" Type="System.Int64" DbType="INT NOT NULL" CanBeNull="false" />
+      <Column Name="NumCalculationRuns" Type="System.Int32" DbType="Int NOT NULL" CanBeNull="false" />
+      <Column Name="NumRetries" Storage="_NumFails" Type="System.Int32" DbType="Int NOT NULL" CanBeNull="false" />
+      <Column Name="CoresRequired" Type="System.Int32" DbType="Int NOT NULL" CanBeNull="false" />
+      <Column Name="MemoryRequired" Type="System.Int32" DbType="Int NOT NULL" CanBeNull="false" />
+      <Column Name="Priority" Type="System.Int32" DbType="Int NOT NULL" CanBeNull="false" />
+      <Column Name="LastClientId" Type="System.Guid" DbType="UniqueIdentifier NOT NULL" CanBeNull="true" />
+      <Column Name="JobId" Type="System.Guid" DbType="UniqueIdentifier NOT NULL" CanBeNull="false" />
+      <Column Name="EndTime" Type="System.DateTime" DbType="DateTime NOT NULL" CanBeNull="true" />
+      <Column Name="TaskState" Type="global::HeuristicLab.Services.Hive.DataAccess.TaskState" DbType="varchar(30)" CanBeNull="false" />
+      <Column Name="Exception" Type="System.String" DbType="varchar(MAX)" CanBeNull="true" />
+      <Column Name="InitialWaitingTime" Storage="_InitialWaitingTimeMs" Type="System.Int64" DbType="INT" CanBeNull="false" />
+      <Column Name="StartTime" Type="System.DateTime" CanBeNull="true" />
+      <Association Name="DimClient_FactTask" Member="DimClient" ThisKey="LastClientId" OtherKey="Id" Type="DimClient" IsForeignKey="true" />
+      <Association Name="DimJob_FactTask" Member="DimJob" ThisKey="JobId" OtherKey="JobId" Type="DimJob" IsForeignKey="true" />
+    </Type>
+  </Table>
+  <Table Name="[statistics].DimJob" Member="DimJobs">
+    <Type Name="DimJob">
+      <Column Name="JobId" Type="System.Guid" DbType="UniqueIdentifier NOT NULL" IsPrimaryKey="true" CanBeNull="false" />
+      <Column Name="UserId" Type="System.Guid" DbType="UniqueIdentifier NOT NULL" CanBeNull="false" />
+      <Column Name="JobName" Type="System.String" DbType="VarChar(MAX) NOT NULL" CanBeNull="false" />
+      <Column Name="UserName" Type="System.String" DbType="VarChar(MAX) NOT NULL" CanBeNull="false" />
+      <Column Name="DateCreated" Type="System.DateTime" DbType="DateTime NOT NULL" CanBeNull="false" />
+      <Column Name="TotalTasks" Type="System.Int32" DbType="INT NOT NULL" CanBeNull="false" />
+      <Column Name="CompletedTasks" Type="System.Int32" DbType="INT NOT NULL" CanBeNull="false" />
+      <Column Name="DateCompleted" Type="System.DateTime" DbType="DateTime NULL" CanBeNull="true" />
+      <Association Name="DimJob_FactTask" Member="FactTasks" ThisKey="JobId" OtherKey="JobId" Type="FactTask" />
+    </Type>
+  </Table>
+  <Table Name="[statistics].DimTime" Member="DimTimes">
+    <Type Name="DimTime">
+      <Column Name="Time" Type="System.DateTime" DbType="DateTime NOT NULL" IsPrimaryKey="true" CanBeNull="false" />
+      <Column Name="Hour" Type="System.DateTime" DbType="DateTime NOT NULL" CanBeNull="false" />
+      <Column Name="Day" Type="System.DateTime" DbType="Date NOT NULL" CanBeNull="false" />
+      <Column Name="Month" Type="System.DateTime" DbType="Date NOT NULL" CanBeNull="false" />
+      <Column Name="Year" Type="System.DateTime" DbType="Date NOT NULL" CanBeNull="false" />
+      <Column Name="Minute" Type="System.DateTime" CanBeNull="false" />
+      <Association Name="DimTime_FactClientInfo" Member="FactClientInfos" ThisKey="Time" OtherKey="Time" Type="FactClientInfo" />
+    </Type>
+  </Table>
+  <Table Name="[statistics].DimUser" Member="DimUsers">
+    <Type Name="DimUser">
+      <Column Name="UserId" Type="System.Guid" DbType="UniqueIdentifier NOT NULL" IsPrimaryKey="true" CanBeNull="false" />
+      <Column Name="Name" Type="System.String" DbType="VarChar(MAX) NOT NULL" CanBeNull="false" />
+      <Association Name="DimUser_FactClientInfo" Member="FactClientInfos" ThisKey="UserId" OtherKey="UserId" Type="FactClientInfo" />
+    </Type>
+  </Table>
+  <Table Name="[statistics].FactClientInfo" Member="FactClientInfos">
+    <Type Name="FactClientInfo">
+      <Column Name="ClientId" Type="System.Guid" DbType="UniqueIdentifier NOT NULL" IsPrimaryKey="true" CanBeNull="false" />
+      <Column Name="Time" Type="System.DateTime" DbType="DateTime NOT NULL" IsPrimaryKey="true" CanBeNull="false" />
+      <Column Name="UserId" Type="System.Guid" DbType="UniqueIdentifier NULL" IsPrimaryKey="true" CanBeNull="false" />
+      <Column Name="NumUsedCores" Type="System.Int32" DbType="Int NOT NULL" CanBeNull="false" />
+      <Column Name="NumTotalCores" Type="System.Int32" DbType="Int NOT NULL" CanBeNull="false" />
+      <Column Name="UsedMemory" Type="System.Int32" DbType="Int NOT NULL" CanBeNull="false" />
+      <Column Name="TotalMemory" Type="System.Int32" DbType="Int NOT NULL" CanBeNull="false" />
+      <Column Name="CpuUtilization" Type="System.Double" DbType="Float NOT NULL" CanBeNull="false" />
+      <Column Name="IdleTime" Storage="_TotalTimeIdle" Type="System.Int64" DbType="INT NOT NULL" CanBeNull="false" />
+      <Column Name="OfflineTime" Storage="_TotalTimeOffline" Type="System.Int64" DbType="INT NOT NULL" CanBeNull="false" />
+      <Column Name="UnavailableTime" Storage="_TotalTimeUnavailable" Type="System.Int64" DbType="INT NOT NULL" CanBeNull="false" />
+      <Column Name="SlaveState" Type="global::HeuristicLab.Services.Hive.DataAccess.SlaveState" DbType="VarChar(15)" CanBeNull="false" />
+      <Column Name="IsAllowedToCalculate" Type="System.Boolean" DbType="BIT" CanBeNull="false" />
+      <Association Name="DimClient_FactClientInfo" Member="DimClient" ThisKey="ClientId" OtherKey="Id" Type="DimClient" IsForeignKey="true" />
+      <Association Name="DimTime_FactClientInfo" Member="DimTime" ThisKey="Time" OtherKey="Time" Type="DimTime" IsForeignKey="true" />
+      <Association Name="DimUser_FactClientInfo" Member="DimUser" ThisKey="UserId" OtherKey="UserId" Type="DimUser" IsForeignKey="true" />
+    </Type>
+  </Table>
 </Database>
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDataContext.dbml.layout
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDataContext.dbml.layout	(revision 12753)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDataContext.dbml.layout	(revision 12878)
@@ -1,58 +1,58 @@
 ﻿<?xml version="1.0" encoding="utf-8"?>
-<ordesignerObjectsDiagram dslVersion="1.0.0.0" absoluteBounds="0, 0, 24.25, 8.5" name="HiveDataContext">
+<ordesignerObjectsDiagram dslVersion="1.0.0.0" absoluteBounds="0, 0, 15.75, 17.875" name="HiveDataContext">
   <DataContextMoniker Name="/HiveDataContext" />
   <nestedChildShapes>
-    <classShape Id="a929c9dc-69f4-4488-ba1c-a2342bf81d89" absoluteBounds="8.875, 4.5, 2, 1.0961531575520827">
+    <classShape Id="a929c9dc-69f4-4488-ba1c-a2342bf81d89" absoluteBounds="8.875, 4.5, 2, 1.1939925130208327">
       <DataClassMoniker Name="/HiveDataContext/AssignedResource" />
       <nestedChildShapes>
-        <elementListCompartment Id="8b005775-f0ee-41b0-ae10-6d1151003708" absoluteBounds="8.89, 4.9600000000000009, 1.9700000000000002, 0.53615315755208326" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
-      </nestedChildShapes>
-    </classShape>
-    <classShape Id="7d998e56-4fba-41ca-a1a8-1dcdb9068edf" absoluteBounds="8.875, 5.875, 2, 1.7535424804687496">
+        <elementListCompartment Id="8b005775-f0ee-41b0-ae10-6d1151003708" absoluteBounds="8.89, 4.9600000000000009, 1.9700000000000002, 0.63399251302083326" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+      </nestedChildShapes>
+    </classShape>
+    <classShape Id="7d998e56-4fba-41ca-a1a8-1dcdb9068edf" absoluteBounds="8.875, 5.875, 2, 1.9631982421874996">
       <DataClassMoniker Name="/HiveDataContext/Plugin" />
       <nestedChildShapes>
-        <elementListCompartment Id="ec4ba325-6dff-4418-baad-59af81ae2024" absoluteBounds="8.89, 6.3350000000000009, 1.9700000000000002, 1.19354248046875" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
-      </nestedChildShapes>
-    </classShape>
-    <classShape Id="97b00810-fa30-457e-b484-b4e80b22f91b" absoluteBounds="6.5, 5.875, 2, 1.2605004882812496">
+        <elementListCompartment Id="ec4ba325-6dff-4418-baad-59af81ae2024" absoluteBounds="8.89, 6.3350000000000009, 1.9700000000000002, 1.4031982421875" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+      </nestedChildShapes>
+    </classShape>
+    <classShape Id="97b00810-fa30-457e-b484-b4e80b22f91b" absoluteBounds="6.5, 5.875, 2, 1.3862939453124996">
       <DataClassMoniker Name="/HiveDataContext/RequiredPlugin" />
       <nestedChildShapes>
-        <elementListCompartment Id="df6451e5-069e-4ca0-a909-61b8213b5047" absoluteBounds="6.5150000000000006, 6.3350000000000009, 1.9700000000000002, 0.70050048828125" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
-      </nestedChildShapes>
-    </classShape>
-    <classShape Id="706a4581-6daf-4e71-ae2a-87d50b27a051" absoluteBounds="11.25, 1, 2, 1.75354248046875">
+        <elementListCompartment Id="df6451e5-069e-4ca0-a909-61b8213b5047" absoluteBounds="6.5150000000000006, 6.3350000000000009, 1.9700000000000002, 0.8262939453125" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+      </nestedChildShapes>
+    </classShape>
+    <classShape Id="706a4581-6daf-4e71-ae2a-87d50b27a051" absoluteBounds="11.25, 1, 2, 1.9631982421875">
       <DataClassMoniker Name="/HiveDataContext/Resource" />
       <nestedChildShapes>
-        <elementListCompartment Id="8c24f5bf-2164-4d0f-832e-1730eb0066df" absoluteBounds="11.265, 1.46, 1.9700000000000002, 1.19354248046875" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
-      </nestedChildShapes>
-    </classShape>
-    <classShape Id="695bfc39-59f3-4e60-8644-f847964bf62c" absoluteBounds="6.5, 1, 2, 2.9039737955729166">
+        <elementListCompartment Id="8c24f5bf-2164-4d0f-832e-1730eb0066df" absoluteBounds="11.265, 1.46, 1.9700000000000002, 1.4031982421875" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+      </nestedChildShapes>
+    </classShape>
+    <classShape Id="695bfc39-59f3-4e60-8644-f847964bf62c" absoluteBounds="6.5, 1, 2, 3.3093082682291666">
       <DataClassMoniker Name="/HiveDataContext/Task" />
       <nestedChildShapes>
-        <elementListCompartment Id="a6a30e11-03d1-4869-82e6-b733f4ef9974" absoluteBounds="6.5150000000000006, 1.46, 1.9700000000000002, 2.3439737955729165" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
-      </nestedChildShapes>
-    </classShape>
-    <classShape Id="8d5712f7-7a1a-4a89-bd4d-fd60200d3306" absoluteBounds="13.5, 2.5, 2, 2.0822371419270826">
+        <elementListCompartment Id="a6a30e11-03d1-4869-82e6-b733f4ef9974" absoluteBounds="6.5150000000000006, 1.46, 1.9700000000000002, 2.7493082682291665" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+      </nestedChildShapes>
+    </classShape>
+    <classShape Id="8d5712f7-7a1a-4a89-bd4d-fd60200d3306" absoluteBounds="13.5, 2.5, 2, 2.3478011067708326">
       <DataClassMoniker Name="/HiveDataContext/Downtime" />
       <nestedChildShapes>
-        <elementListCompartment Id="7d8f121b-35bb-4753-a25f-3fac1562e68e" absoluteBounds="13.515, 2.9600000000000009, 1.9700000000000002, 1.5222371419270833" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
-      </nestedChildShapes>
-    </classShape>
-    <classShape Id="e6f840cc-2968-4be1-b234-eef624ccacbb" absoluteBounds="4.125, 2.625, 2, 1.7535424804687496">
+        <elementListCompartment Id="7d8f121b-35bb-4753-a25f-3fac1562e68e" absoluteBounds="13.515, 2.9600000000000009, 1.9700000000000002, 1.7878011067708333" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+      </nestedChildShapes>
+    </classShape>
+    <classShape Id="e6f840cc-2968-4be1-b234-eef624ccacbb" absoluteBounds="4.125, 2.625, 2, 1.9631982421874996">
       <DataClassMoniker Name="/HiveDataContext/Job" />
       <nestedChildShapes>
-        <elementListCompartment Id="0c65d4e1-256a-4a91-9a57-392f25e4de7f" absoluteBounds="4.1400000000000006, 3.0850000000000009, 1.9700000000000002, 1.19354248046875" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
-      </nestedChildShapes>
-    </classShape>
-    <classShape Id="26f4edfa-91dd-4941-a058-359f89e567a8" absoluteBounds="8.875, 0.75, 2, 2.9039737955729166">
+        <elementListCompartment Id="0c65d4e1-256a-4a91-9a57-392f25e4de7f" absoluteBounds="4.1400000000000006, 3.0850000000000009, 1.9700000000000002, 1.4031982421875" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+      </nestedChildShapes>
+    </classShape>
+    <classShape Id="26f4edfa-91dd-4941-a058-359f89e567a8" absoluteBounds="8.875, 0.75, 2, 3.3093082682291666">
       <DataClassMoniker Name="/HiveDataContext/Slave" />
       <nestedChildShapes>
-        <elementListCompartment Id="1e61f36b-08dc-4df7-8594-c9dcd95c0791" absoluteBounds="8.89, 1.21, 1.9700000000000002, 2.3439737955729165" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
-      </nestedChildShapes>
-    </classShape>
-    <classShape Id="bbd91675-92f2-4a69-8429-0950008fc8a4" absoluteBounds="13.5, 1, 2, 0.76745849609375">
+        <elementListCompartment Id="1e61f36b-08dc-4df7-8594-c9dcd95c0791" absoluteBounds="8.89, 1.21, 1.9700000000000002, 2.7493082682291665" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+      </nestedChildShapes>
+    </classShape>
+    <classShape Id="bbd91675-92f2-4a69-8429-0950008fc8a4" absoluteBounds="13.5, 1, 2, 0.8093896484375">
       <DataClassMoniker Name="/HiveDataContext/SlaveGroup" />
       <nestedChildShapes>
-        <elementListCompartment Id="5a790e8f-6e2e-4bf5-bd2b-f8a82224d9d7" absoluteBounds="13.5, 1, 0.125, 0.20745849609375" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+        <elementListCompartment Id="5a790e8f-6e2e-4bf5-bd2b-f8a82224d9d7" absoluteBounds="13.5, 1, 0.125, 0.2493896484375" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
       </nestedChildShapes>
     </classShape>
@@ -69,5 +69,5 @@
       </nodes>
     </inheritanceConnector>
-    <associationConnector edgePoints="[(11.8134963640734 : 2.75354248046875); (11.8134963640734 : 3.56770833333333); (11.1119791666667 : 3.56770833333333); (11.1119791666667 : 5.09699625651042); (10.875 : 5.09699625651042)]" manuallyRouted="true" fixedFrom="Algorithm" fixedTo="Algorithm">
+    <associationConnector edgePoints="[(11.8134963640734 : 2.9631982421875); (11.8134963640734 : 3.56770833333333); (11.1119791666667 : 3.56770833333333); (11.1119791666667 : 5.09699625651042); (10.875 : 5.09699625651042)]" manuallyRouted="true" fixedFrom="NotFixed" fixedTo="NotFixed">
       <AssociationMoniker Name="/HiveDataContext/Resource/Resource_AssignedResource" />
       <nodes>
@@ -76,14 +76,14 @@
       </nodes>
     </associationConnector>
-    <classShape Id="6bc13f26-f9a8-4597-b054-35be34190d12" absoluteBounds="4.125, 1, 2, 1.26050048828125">
+    <classShape Id="6bc13f26-f9a8-4597-b054-35be34190d12" absoluteBounds="4.125, 1, 2, 1.3862939453125">
       <DataClassMoniker Name="/HiveDataContext/TaskData" />
       <nestedChildShapes>
-        <elementListCompartment Id="a068522c-7974-4679-b356-e33c941c465b" absoluteBounds="4.14, 1.46, 1.9700000000000002, 0.70050048828125" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
-      </nestedChildShapes>
-    </classShape>
-    <classShape Id="ad25bd0f-80e8-4a06-abd8-190eb678eec7" absoluteBounds="11.25, 5.875, 2, 1.4248478190104166">
+        <elementListCompartment Id="a068522c-7974-4679-b356-e33c941c465b" absoluteBounds="4.14, 1.46, 1.9700000000000002, 0.8262939453125" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+      </nestedChildShapes>
+    </classShape>
+    <classShape Id="ad25bd0f-80e8-4a06-abd8-190eb678eec7" absoluteBounds="11.25, 5.875, 2, 1.5785953776041666">
       <DataClassMoniker Name="/HiveDataContext/PluginData" />
       <nestedChildShapes>
-        <elementListCompartment Id="acddb513-7de6-4bb4-8335-d6982fb2ef35" absoluteBounds="11.265, 6.3350000000000009, 1.9700000000000002, 0.86484781901041663" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+        <elementListCompartment Id="acddb513-7de6-4bb4-8335-d6982fb2ef35" absoluteBounds="11.265, 6.3350000000000009, 1.9700000000000002, 1.0185953776041665" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
       </nestedChildShapes>
     </classShape>
@@ -109,17 +109,17 @@
       </nodes>
     </associationConnector>
-    <classShape Id="00352397-340e-449a-8e23-6ddd216e8617" absoluteBounds="1.75, 1, 2, 1.9178898111979166">
+    <classShape Id="00352397-340e-449a-8e23-6ddd216e8617" absoluteBounds="1.75, 1, 2, 2.1554996744791666">
       <DataClassMoniker Name="/HiveDataContext/StateLog" />
       <nestedChildShapes>
-        <elementListCompartment Id="9a003897-deef-4bb5-b180-4c4bcdb7fadc" absoluteBounds="1.765, 1.46, 1.9700000000000002, 1.3578898111979165" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
-      </nestedChildShapes>
-    </classShape>
-    <classShape Id="4d800dc9-1b18-469f-b02c-d4554757c5e1" absoluteBounds="1.75, 3.625, 2, 1.4248478190104166">
+        <elementListCompartment Id="9a003897-deef-4bb5-b180-4c4bcdb7fadc" absoluteBounds="1.765, 1.46, 1.9700000000000002, 1.5954996744791665" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+      </nestedChildShapes>
+    </classShape>
+    <classShape Id="4d800dc9-1b18-469f-b02c-d4554757c5e1" absoluteBounds="1.75, 3.625, 2, 1.5785953776041666">
       <DataClassMoniker Name="/HiveDataContext/JobPermission" />
       <nestedChildShapes>
-        <elementListCompartment Id="dedd97d3-a9a2-45a2-9b95-d7366fb65a7f" absoluteBounds="1.765, 4.085, 1.9700000000000002, 0.86484781901041663" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
-      </nestedChildShapes>
-    </classShape>
-    <associationConnector edgePoints="[(11.25 : 1.98159912109375); (10.9375 : 1.98159912109375); (10.9375 : 0.6875); (2.75 : 0.6875); (2.75 : 1)]" fixedFrom="NotFixed" fixedTo="NotFixed">
+        <elementListCompartment Id="dedd97d3-a9a2-45a2-9b95-d7366fb65a7f" absoluteBounds="1.765, 4.085, 1.9700000000000002, 1.0185953776041665" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+      </nestedChildShapes>
+    </classShape>
+    <associationConnector edgePoints="[(11.25 : 1.44547136382195); (11.0260416666667 : 1.44547136382195); (11.0260416666667 : 0.5625); (2.75 : 0.5625); (2.75 : 1)]" manuallyRouted="true" fixedFrom="NotFixed" fixedTo="NotFixed">
       <AssociationMoniker Name="/HiveDataContext/Resource/Resource_StateLog" />
       <nodes>
@@ -128,48 +128,10 @@
       </nodes>
     </associationConnector>
-    <classShape Id="b4e7aaa8-a382-4560-a1fd-498de77e9340" absoluteBounds="1.75, 5.5, 2, 1.0961531575520827">
+    <classShape Id="b4e7aaa8-a382-4560-a1fd-498de77e9340" absoluteBounds="1.75, 5.5, 2, 1.1939925130208327">
       <DataClassMoniker Name="/HiveDataContext/Lifecycle" />
       <nestedChildShapes>
-        <elementListCompartment Id="03597a2c-5c5d-4c2c-b741-c49ab5aa34d5" absoluteBounds="1.7650000000000001, 5.96, 1.9700000000000002, 0.53615315755208326" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
-      </nestedChildShapes>
-    </classShape>
-    <classShape Id="cdddf4da-eaef-46a1-9cfd-987bb6b3d03e" absoluteBounds="17, 3.125, 2.5, 1.5891951497395827">
-      <DataClassMoniker Name="/HiveDataContext/DeletedJobStatistics" />
-      <nestedChildShapes>
-        <elementListCompartment Id="b8738381-f696-4dba-a517-47e9cd96a9a6" absoluteBounds="17.015, 3.585, 2.4699999999999998, 1.0291951497395833" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
-      </nestedChildShapes>
-    </classShape>
-    <classShape Id="25442617-ff41-49a0-b5d5-4cbe0b2f0f45" absoluteBounds="22, 4.5, 2, 1.7535424804687496">
-      <DataClassMoniker Name="/HiveDataContext/UserStatistics" />
-      <nestedChildShapes>
-        <elementListCompartment Id="6edf08e7-054a-4253-8d4f-5bf2dfec2d29" absoluteBounds="22.015, 4.96, 1.9700000000000002, 1.19354248046875" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
-      </nestedChildShapes>
-    </classShape>
-    <classShape Id="f78ec989-4862-4bac-87e3-9b0aad4bc037" absoluteBounds="19.875, 4.5, 2, 1.9178898111979166">
-      <DataClassMoniker Name="/HiveDataContext/SlaveStatistics" />
-      <nestedChildShapes>
-        <elementListCompartment Id="98cb46fe-820e-4041-aee8-04e8bed3df23" absoluteBounds="19.89, 4.96, 1.9700000000000002, 1.3578898111979165" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
-      </nestedChildShapes>
-    </classShape>
-    <classShape Id="4d9f0606-b7ee-4dae-a8ac-aff88d25a941" absoluteBounds="21, 3, 2, 1.0961531575520827">
-      <DataClassMoniker Name="/HiveDataContext/Statistics" />
-      <nestedChildShapes>
-        <elementListCompartment Id="17821282-8edf-40b7-9065-84f53391d5c1" absoluteBounds="21.015, 3.46, 1.9700000000000002, 0.53615315755208326" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
-      </nestedChildShapes>
-    </classShape>
-    <associationConnector edgePoints="[(21.4375 : 4.19399251302083); (21.4375 : 4.5)]" fixedFrom="NotFixed" fixedTo="NotFixed">
-      <AssociationMoniker Name="/HiveDataContext/Statistics/Statistics_SlaveStatistics" />
-      <nodes>
-        <classShapeMoniker Id="4d9f0606-b7ee-4dae-a8ac-aff88d25a941" />
-        <classShapeMoniker Id="f78ec989-4862-4bac-87e3-9b0aad4bc037" />
-      </nodes>
-    </associationConnector>
-    <associationConnector edgePoints="[(22.5 : 4.19399251302083); (22.5 : 4.5)]" fixedFrom="NotFixed" fixedTo="NotFixed">
-      <AssociationMoniker Name="/HiveDataContext/Statistics/Statistics_UserStatistics" />
-      <nodes>
-        <classShapeMoniker Id="4d9f0606-b7ee-4dae-a8ac-aff88d25a941" />
-        <classShapeMoniker Id="25442617-ff41-49a0-b5d5-4cbe0b2f0f45" />
-      </nodes>
-    </associationConnector>
+        <elementListCompartment Id="03597a2c-5c5d-4c2c-b741-c49ab5aa34d5" absoluteBounds="1.7650000000000001, 5.96, 1.9700000000000002, 0.63399251302083326" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+      </nestedChildShapes>
+    </classShape>
     <associationConnector edgePoints="[(13.25 : 2.73159912109375); (13.5 : 2.73159912109375)]" fixedFrom="NotFixed" fixedTo="NotFixed">
       <AssociationMoniker Name="/HiveDataContext/Resource/Resource_Downtime" />
@@ -179,5 +141,5 @@
       </nodes>
     </associationConnector>
-    <associationConnector edgePoints="[(7.96163946463664 : 4.30930826822917); (7.96163946463664 : 5.09699625651042); (8.875 : 5.09699625651042)]" fixedFrom="NotFixed" fixedTo="NotFixed">
+    <associationConnector edgePoints="[(8.0192961430407 : 3.90397379557292); (8.0192961430407 : 5.04807657877604); (8.875 : 5.04807657877604)]" fixedFrom="NotFixed" fixedTo="NotFixed">
       <AssociationMoniker Name="/HiveDataContext/Task/Task_AssignedResource" />
       <nodes>
@@ -186,5 +148,5 @@
       </nodes>
     </associationConnector>
-    <associationConnector edgePoints="[(7.16831973231832 : 4.30930826822917); (7.16831973231832 : 5.875)]" fixedFrom="NotFixed" fixedTo="NotFixed">
+    <associationConnector edgePoints="[(7.20145120722822 : 3.90397379557292); (7.20145120722822 : 5.875)]" fixedFrom="NotFixed" fixedTo="NotFixed">
       <AssociationMoniker Name="/HiveDataContext/Task/Task_RequiredPlugin" />
       <nodes>
@@ -193,5 +155,5 @@
       </nodes>
     </associationConnector>
-    <associationConnector edgePoints="[(7.20923076923077 : 1); (7.20923076923077 : 0.875); (7.80461538461539 : 0.875); (7.80461538461539 : 1)]" fixedFrom="NotFixed" fixedTo="NotFixed">
+    <associationConnector edgePoints="[(7.20923076923077 : 1); (7.20923076923077 : 0.770833333333333); (7.80461538461539 : 0.770833333333333); (7.80461538461539 : 1)]" manuallyRouted="true" fixedFrom="NotFixed" fixedTo="NotFixed">
       <AssociationMoniker Name="/HiveDataContext/Task/Task_Task" />
       <nodes>
@@ -228,8 +190,8 @@
       </nodes>
     </associationConnector>
-    <classShape Id="a3f352be-9f15-4e73-8d44-3e8ac02fb4cf" absoluteBounds="11.25, 3.875, 2, 1.2605004882812496">
+    <classShape Id="a3f352be-9f15-4e73-8d44-3e8ac02fb4cf" absoluteBounds="11.25, 3.875, 2, 1.3862939453124996">
       <DataClassMoniker Name="/HiveDataContext/ResourcePermission" />
       <nestedChildShapes>
-        <elementListCompartment Id="45e2f1a8-8a1e-4647-b649-10ec55976ab4" absoluteBounds="11.265, 4.335, 1.9700000000000002, 0.70050048828125" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+        <elementListCompartment Id="45e2f1a8-8a1e-4647-b649-10ec55976ab4" absoluteBounds="11.265, 4.335, 1.9700000000000002, 0.8262939453125" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
       </nestedChildShapes>
     </classShape>
@@ -241,10 +203,81 @@
       </nodes>
     </associationConnector>
-    <classShape Id="f9e8867f-fd15-4a72-8ca4-4f02cd3f141f" absoluteBounds="4.125, 5.5, 2, 1.0961531575520827">
+    <classShape Id="f9e8867f-fd15-4a72-8ca4-4f02cd3f141f" absoluteBounds="4.125, 5.5, 2, 1.1939925130208327">
       <DataClassMoniker Name="/HiveDataContext/UserPriority" />
       <nestedChildShapes>
-        <elementListCompartment Id="ee41f516-7d9c-4a1d-a1b8-bbe00a6ffea8" absoluteBounds="4.14, 5.96, 1.9700000000000002, 0.53615315755208326" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
-      </nestedChildShapes>
-    </classShape>
+        <elementListCompartment Id="ee41f516-7d9c-4a1d-a1b8-bbe00a6ffea8" absoluteBounds="4.14, 5.96, 1.9700000000000002, 0.63399251302083326" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+      </nestedChildShapes>
+    </classShape>
+    <classShape Id="b5b919c2-4efc-4f09-8f52-9d541a11e961" absoluteBounds="4.625, 15.25, 2, 2.3478011067708344">
+      <DataClassMoniker Name="/HiveDataContext/DimClient" />
+      <nestedChildShapes>
+        <elementListCompartment Id="30f62a7b-0b16-404e-b972-fb12bfe978dd" absoluteBounds="4.6400000000000006, 15.71, 1.9700000000000002, 1.7878011067708333" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+      </nestedChildShapes>
+    </classShape>
+    <classShape Id="04f52807-ce17-4d65-bd23-cc38c6dfbd7a" absoluteBounds="6.875, 11.25, 2, 3.8862125651041666">
+      <DataClassMoniker Name="/HiveDataContext/FactTask" />
+      <nestedChildShapes>
+        <elementListCompartment Id="63e3ddcb-a6fe-48e0-a674-e650a55a9f2c" absoluteBounds="6.8900000000000006, 11.71, 1.9700000000000002, 3.3262125651041665" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+      </nestedChildShapes>
+    </classShape>
+    <classShape Id="e0cb8641-a75e-4b9f-beda-3218c56938b1" absoluteBounds="8.125, 8.25, 2, 2.3478011067708344">
+      <DataClassMoniker Name="/HiveDataContext/DimJob" />
+      <nestedChildShapes>
+        <elementListCompartment Id="6b9e8260-7e4b-4357-9c26-eebebfd69504" absoluteBounds="8.14, 8.71, 1.9700000000000002, 1.7878011067708333" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+      </nestedChildShapes>
+    </classShape>
+    <classShape Id="a769f2ac-c8e3-4860-baa5-c46f46c38ed8" absoluteBounds="3.625, 8.5, 2, 1.9631982421875005">
+      <DataClassMoniker Name="/HiveDataContext/DimTime" />
+      <nestedChildShapes>
+        <elementListCompartment Id="694c4a5a-20fb-43a9-bc9a-7b59d794a7fb" absoluteBounds="3.6399999999999997, 8.96, 1.9700000000000002, 1.4031982421875" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+      </nestedChildShapes>
+    </classShape>
+    <classShape Id="66c34ced-4fdb-4a1d-b8dd-fe094679b7fb" absoluteBounds="0.625, 8.875, 2, 1.1939925130208344">
+      <DataClassMoniker Name="/HiveDataContext/DimUser" />
+      <nestedChildShapes>
+        <elementListCompartment Id="6181c560-fc74-4d43-b064-a90032bf17a5" absoluteBounds="0.64000000000000012, 9.335, 1.9700000000000002, 0.63399251302083326" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+      </nestedChildShapes>
+    </classShape>
+    <classShape Id="053a5cff-b18a-4ee5-8d43-48ed5c5dcfad" absoluteBounds="2.625, 11, 2, 3.3093082682291666">
+      <DataClassMoniker Name="/HiveDataContext/FactClientInfo" />
+      <nestedChildShapes>
+        <elementListCompartment Id="0a1cc913-6636-455c-95b3-302f533527db" absoluteBounds="2.6399999999999997, 11.46, 1.9700000000000002, 2.7493082682291665" name="DataPropertiesCompartment" titleTextColor="Black" itemTextColor="Black" />
+      </nestedChildShapes>
+    </classShape>
+    <associationConnector edgePoints="[(6.625 : 15.25); (6.875 : 15.1362125651042)]" fixedFrom="NotFixed" fixedTo="NotFixed">
+      <AssociationMoniker Name="/HiveDataContext/DimClient/DimClient_FactTask" />
+      <nodes>
+        <classShapeMoniker Id="b5b919c2-4efc-4f09-8f52-9d541a11e961" />
+        <classShapeMoniker Id="04f52807-ce17-4d65-bd23-cc38c6dfbd7a" />
+      </nodes>
+    </associationConnector>
+    <associationConnector edgePoints="[(8.5 : 10.5978011067708); (8.5 : 11.25)]" fixedFrom="NotFixed" fixedTo="NotFixed">
+      <AssociationMoniker Name="/HiveDataContext/DimJob/DimJob_FactTask" />
+      <nodes>
+        <classShapeMoniker Id="e0cb8641-a75e-4b9f-beda-3218c56938b1" />
+        <classShapeMoniker Id="04f52807-ce17-4d65-bd23-cc38c6dfbd7a" />
+      </nodes>
+    </associationConnector>
+    <associationConnector edgePoints="[(5.6249975 : 15.25); (5.6249975 : 12.6546541341146); (4.625 : 12.6546541341146)]" fixedFrom="NotFixed" fixedTo="NotFixed">
+      <AssociationMoniker Name="/HiveDataContext/DimClient/DimClient_FactClientInfo" />
+      <nodes>
+        <classShapeMoniker Id="b5b919c2-4efc-4f09-8f52-9d541a11e961" />
+        <classShapeMoniker Id="053a5cff-b18a-4ee5-8d43-48ed5c5dcfad" />
+      </nodes>
+    </associationConnector>
+    <associationConnector edgePoints="[(4.125 : 10.4631982421875); (4.125 : 11)]" fixedFrom="NotFixed" fixedTo="NotFixed">
+      <AssociationMoniker Name="/HiveDataContext/DimTime/DimTime_FactClientInfo" />
+      <nodes>
+        <classShapeMoniker Id="a769f2ac-c8e3-4860-baa5-c46f46c38ed8" />
+        <classShapeMoniker Id="053a5cff-b18a-4ee5-8d43-48ed5c5dcfad" />
+      </nodes>
+    </associationConnector>
+    <associationConnector edgePoints="[(1.59375 : 10.0689925130208); (1.59375 : 12.6546541341146); (2.625 : 12.6546541341146)]" fixedFrom="NotFixed" fixedTo="NotFixed">
+      <AssociationMoniker Name="/HiveDataContext/DimUser/DimUser_FactClientInfo" />
+      <nodes>
+        <classShapeMoniker Id="66c34ced-4fdb-4a1d-b8dd-fe094679b7fb" />
+        <classShapeMoniker Id="053a5cff-b18a-4ee5-8d43-48ed5c5dcfad" />
+      </nodes>
+    </associationConnector>
   </nestedChildShapes>
 </ordesignerObjectsDiagram>
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDataContext.designer.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDataContext.designer.cs	(revision 12753)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDataContext.designer.cs	(revision 12878)
@@ -3,5 +3,5 @@
 // <auto-generated>
 //     This code was generated by a tool.
-//     Runtime Version:4.0.30319.34014
+//     Runtime Version:4.0.30319.34209
 //
 //     Changes to this file may cause incorrect behavior and will be lost if
@@ -67,16 +67,4 @@
     partial void UpdateLifecycle(Lifecycle instance);
     partial void DeleteLifecycle(Lifecycle instance);
-    partial void InsertDeletedJobStatistics(DeletedJobStatistics instance);
-    partial void UpdateDeletedJobStatistics(DeletedJobStatistics instance);
-    partial void DeleteDeletedJobStatistics(DeletedJobStatistics instance);
-    partial void InsertUserStatistics(UserStatistics instance);
-    partial void UpdateUserStatistics(UserStatistics instance);
-    partial void DeleteUserStatistics(UserStatistics instance);
-    partial void InsertSlaveStatistics(SlaveStatistics instance);
-    partial void UpdateSlaveStatistics(SlaveStatistics instance);
-    partial void DeleteSlaveStatistics(SlaveStatistics instance);
-    partial void InsertStatistics(Statistics instance);
-    partial void UpdateStatistics(Statistics instance);
-    partial void DeleteStatistics(Statistics instance);
     partial void InsertResourcePermission(ResourcePermission instance);
     partial void UpdateResourcePermission(ResourcePermission instance);
@@ -85,4 +73,22 @@
     partial void UpdateUserPriority(UserPriority instance);
     partial void DeleteUserPriority(UserPriority instance);
+    partial void InsertDimClient(DimClient instance);
+    partial void UpdateDimClient(DimClient instance);
+    partial void DeleteDimClient(DimClient instance);
+    partial void InsertFactTask(FactTask instance);
+    partial void UpdateFactTask(FactTask instance);
+    partial void DeleteFactTask(FactTask instance);
+    partial void InsertDimJob(DimJob instance);
+    partial void UpdateDimJob(DimJob instance);
+    partial void DeleteDimJob(DimJob instance);
+    partial void InsertDimTime(DimTime instance);
+    partial void UpdateDimTime(DimTime instance);
+    partial void DeleteDimTime(DimTime instance);
+    partial void InsertDimUser(DimUser instance);
+    partial void UpdateDimUser(DimUser instance);
+    partial void DeleteDimUser(DimUser instance);
+    partial void InsertFactClientInfo(FactClientInfo instance);
+    partial void UpdateFactClientInfo(FactClientInfo instance);
+    partial void DeleteFactClientInfo(FactClientInfo instance);
     #endregion
 		
@@ -213,36 +219,4 @@
 		}
 		
-		public System.Data.Linq.Table<DeletedJobStatistics> DeletedJobStatistics
-		{
-			get
-			{
-				return this.GetTable<DeletedJobStatistics>();
-			}
-		}
-		
-		public System.Data.Linq.Table<UserStatistics> UserStatistics
-		{
-			get
-			{
-				return this.GetTable<UserStatistics>();
-			}
-		}
-		
-		public System.Data.Linq.Table<SlaveStatistics> SlaveStatistics
-		{
-			get
-			{
-				return this.GetTable<SlaveStatistics>();
-			}
-		}
-		
-		public System.Data.Linq.Table<Statistics> Statistics
-		{
-			get
-			{
-				return this.GetTable<Statistics>();
-			}
-		}
-		
 		public System.Data.Linq.Table<ResourcePermission> ResourcePermissions
 		{
@@ -258,4 +232,52 @@
 			{
 				return this.GetTable<UserPriority>();
+			}
+		}
+		
+		public System.Data.Linq.Table<DimClient> DimClients
+		{
+			get
+			{
+				return this.GetTable<DimClient>();
+			}
+		}
+		
+		public System.Data.Linq.Table<FactTask> FactTasks
+		{
+			get
+			{
+				return this.GetTable<FactTask>();
+			}
+		}
+		
+		public System.Data.Linq.Table<DimJob> DimJobs
+		{
+			get
+			{
+				return this.GetTable<DimJob>();
+			}
+		}
+		
+		public System.Data.Linq.Table<DimTime> DimTimes
+		{
+			get
+			{
+				return this.GetTable<DimTime>();
+			}
+		}
+		
+		public System.Data.Linq.Table<DimUser> DimUsers
+		{
+			get
+			{
+				return this.GetTable<DimUser>();
+			}
+		}
+		
+		public System.Data.Linq.Table<FactClientInfo> FactClientInfos
+		{
+			get
+			{
+				return this.GetTable<FactClientInfo>();
 			}
 		}
@@ -3528,774 +3550,4 @@
 	}
 	
-	[global::System.Data.Linq.Mapping.TableAttribute(Name="")]
-	public partial class DeletedJobStatistics : INotifyPropertyChanging, INotifyPropertyChanged
-	{
-		
-		private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
-		
-		private System.Guid _UserId;
-		
-		private double _ExecutionTime;
-		
-		private double _ExecutionTimeFinishedJobs;
-		
-		private double _StartToEndTime;
-		
-		private System.Guid _DeletedJobStatisticsId;
-		
-    #region Extensibility Method Definitions
-    partial void OnLoaded();
-    partial void OnValidate(System.Data.Linq.ChangeAction action);
-    partial void OnCreated();
-    partial void OnUserIdChanging(System.Guid value);
-    partial void OnUserIdChanged();
-    partial void OnExecutionTimeSChanging(double value);
-    partial void OnExecutionTimeSChanged();
-    partial void OnExecutionTimeSFinishedJobsChanging(double value);
-    partial void OnExecutionTimeSFinishedJobsChanged();
-    partial void OnStartToEndTimeSChanging(double value);
-    partial void OnStartToEndTimeSChanged();
-    partial void OnDeletedJobStatisticsIdChanging(System.Guid value);
-    partial void OnDeletedJobStatisticsIdChanged();
-    #endregion
-		
-		public DeletedJobStatistics()
-		{
-			OnCreated();
-		}
-		
-		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_UserId", DbType="UniqueIdentifier NOT NULL")]
-		public System.Guid UserId
-		{
-			get
-			{
-				return this._UserId;
-			}
-			set
-			{
-				if ((this._UserId != value))
-				{
-					this.OnUserIdChanging(value);
-					this.SendPropertyChanging();
-					this._UserId = value;
-					this.SendPropertyChanged("UserId");
-					this.OnUserIdChanged();
-				}
-			}
-		}
-		
-		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ExecutionTime", DbType="float NOT NULL")]
-		public double ExecutionTimeS
-		{
-			get
-			{
-				return this._ExecutionTime;
-			}
-			set
-			{
-				if ((this._ExecutionTime != value))
-				{
-					this.OnExecutionTimeSChanging(value);
-					this.SendPropertyChanging();
-					this._ExecutionTime = value;
-					this.SendPropertyChanged("ExecutionTimeS");
-					this.OnExecutionTimeSChanged();
-				}
-			}
-		}
-		
-		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ExecutionTimeFinishedJobs", DbType="float NOT NULL")]
-		public double ExecutionTimeSFinishedJobs
-		{
-			get
-			{
-				return this._ExecutionTimeFinishedJobs;
-			}
-			set
-			{
-				if ((this._ExecutionTimeFinishedJobs != value))
-				{
-					this.OnExecutionTimeSFinishedJobsChanging(value);
-					this.SendPropertyChanging();
-					this._ExecutionTimeFinishedJobs = value;
-					this.SendPropertyChanged("ExecutionTimeSFinishedJobs");
-					this.OnExecutionTimeSFinishedJobsChanged();
-				}
-			}
-		}
-		
-		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_StartToEndTime", DbType="float NOT NULL")]
-		public double StartToEndTimeS
-		{
-			get
-			{
-				return this._StartToEndTime;
-			}
-			set
-			{
-				if ((this._StartToEndTime != value))
-				{
-					this.OnStartToEndTimeSChanging(value);
-					this.SendPropertyChanging();
-					this._StartToEndTime = value;
-					this.SendPropertyChanged("StartToEndTimeS");
-					this.OnStartToEndTimeSChanged();
-				}
-			}
-		}
-		
-		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_DeletedJobStatisticsId", AutoSync=AutoSync.OnInsert, DbType="UniqueIdentifier NOT NULL", IsPrimaryKey=true, IsDbGenerated=true)]
-		public System.Guid DeletedJobStatisticsId
-		{
-			get
-			{
-				return this._DeletedJobStatisticsId;
-			}
-			set
-			{
-				if ((this._DeletedJobStatisticsId != value))
-				{
-					this.OnDeletedJobStatisticsIdChanging(value);
-					this.SendPropertyChanging();
-					this._DeletedJobStatisticsId = value;
-					this.SendPropertyChanged("DeletedJobStatisticsId");
-					this.OnDeletedJobStatisticsIdChanged();
-				}
-			}
-		}
-		
-		public event PropertyChangingEventHandler PropertyChanging;
-		
-		public event PropertyChangedEventHandler PropertyChanged;
-		
-		protected virtual void SendPropertyChanging()
-		{
-			if ((this.PropertyChanging != null))
-			{
-				this.PropertyChanging(this, emptyChangingEventArgs);
-			}
-		}
-		
-		protected virtual void SendPropertyChanged(String propertyName)
-		{
-			if ((this.PropertyChanged != null))
-			{
-				this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
-			}
-		}
-	}
-	
-	[global::System.Data.Linq.Mapping.TableAttribute(Name="")]
-	public partial class UserStatistics : INotifyPropertyChanging, INotifyPropertyChanged
-	{
-		
-		private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
-		
-		private System.Guid _StatisticsId;
-		
-		private System.Guid _UserId;
-		
-		private double _ExecutionTime;
-		
-		private int _CoresUsed;
-		
-		private double _ExecutionTimeFinishedJobs;
-		
-		private double _StartToEndTime;
-		
-		private EntityRef<Statistics> _Statistics;
-		
-    #region Extensibility Method Definitions
-    partial void OnLoaded();
-    partial void OnValidate(System.Data.Linq.ChangeAction action);
-    partial void OnCreated();
-    partial void OnStatisticsIdChanging(System.Guid value);
-    partial void OnStatisticsIdChanged();
-    partial void OnUserIdChanging(System.Guid value);
-    partial void OnUserIdChanged();
-    partial void OnExecutionTimeMsChanging(double value);
-    partial void OnExecutionTimeMsChanged();
-    partial void OnUsedCoresChanging(int value);
-    partial void OnUsedCoresChanged();
-    partial void OnExecutionTimeMsFinishedJobsChanging(double value);
-    partial void OnExecutionTimeMsFinishedJobsChanged();
-    partial void OnStartToEndTimeMsChanging(double value);
-    partial void OnStartToEndTimeMsChanged();
-    #endregion
-		
-		public UserStatistics()
-		{
-			this._Statistics = default(EntityRef<Statistics>);
-			OnCreated();
-		}
-		
-		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_StatisticsId", DbType="UniqueIdentifier NOT NULL", IsPrimaryKey=true)]
-		public System.Guid StatisticsId
-		{
-			get
-			{
-				return this._StatisticsId;
-			}
-			set
-			{
-				if ((this._StatisticsId != value))
-				{
-					if (this._Statistics.HasLoadedOrAssignedValue)
-					{
-						throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException();
-					}
-					this.OnStatisticsIdChanging(value);
-					this.SendPropertyChanging();
-					this._StatisticsId = value;
-					this.SendPropertyChanged("StatisticsId");
-					this.OnStatisticsIdChanged();
-				}
-			}
-		}
-		
-		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_UserId", DbType="UniqueIdentifier NOT NULL", IsPrimaryKey=true)]
-		public System.Guid UserId
-		{
-			get
-			{
-				return this._UserId;
-			}
-			set
-			{
-				if ((this._UserId != value))
-				{
-					this.OnUserIdChanging(value);
-					this.SendPropertyChanging();
-					this._UserId = value;
-					this.SendPropertyChanged("UserId");
-					this.OnUserIdChanged();
-				}
-			}
-		}
-		
-		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ExecutionTime", DbType="float NOT NULL")]
-		public double ExecutionTimeMs
-		{
-			get
-			{
-				return this._ExecutionTime;
-			}
-			set
-			{
-				if ((this._ExecutionTime != value))
-				{
-					this.OnExecutionTimeMsChanging(value);
-					this.SendPropertyChanging();
-					this._ExecutionTime = value;
-					this.SendPropertyChanged("ExecutionTimeMs");
-					this.OnExecutionTimeMsChanged();
-				}
-			}
-		}
-		
-		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_CoresUsed", DbType="Int NOT NULL")]
-		public int UsedCores
-		{
-			get
-			{
-				return this._CoresUsed;
-			}
-			set
-			{
-				if ((this._CoresUsed != value))
-				{
-					this.OnUsedCoresChanging(value);
-					this.SendPropertyChanging();
-					this._CoresUsed = value;
-					this.SendPropertyChanged("UsedCores");
-					this.OnUsedCoresChanged();
-				}
-			}
-		}
-		
-		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ExecutionTimeFinishedJobs", DbType="float NOT NULL")]
-		public double ExecutionTimeMsFinishedJobs
-		{
-			get
-			{
-				return this._ExecutionTimeFinishedJobs;
-			}
-			set
-			{
-				if ((this._ExecutionTimeFinishedJobs != value))
-				{
-					this.OnExecutionTimeMsFinishedJobsChanging(value);
-					this.SendPropertyChanging();
-					this._ExecutionTimeFinishedJobs = value;
-					this.SendPropertyChanged("ExecutionTimeMsFinishedJobs");
-					this.OnExecutionTimeMsFinishedJobsChanged();
-				}
-			}
-		}
-		
-		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_StartToEndTime", DbType="float NOT NULL")]
-		public double StartToEndTimeMs
-		{
-			get
-			{
-				return this._StartToEndTime;
-			}
-			set
-			{
-				if ((this._StartToEndTime != value))
-				{
-					this.OnStartToEndTimeMsChanging(value);
-					this.SendPropertyChanging();
-					this._StartToEndTime = value;
-					this.SendPropertyChanged("StartToEndTimeMs");
-					this.OnStartToEndTimeMsChanged();
-				}
-			}
-		}
-		
-		[global::System.Data.Linq.Mapping.AssociationAttribute(Name="Statistics_UserStatistics", Storage="_Statistics", ThisKey="StatisticsId", OtherKey="StatisticsId", IsForeignKey=true)]
-		public Statistics Statistics
-		{
-			get
-			{
-				return this._Statistics.Entity;
-			}
-			set
-			{
-				Statistics previousValue = this._Statistics.Entity;
-				if (((previousValue != value) 
-							|| (this._Statistics.HasLoadedOrAssignedValue == false)))
-				{
-					this.SendPropertyChanging();
-					if ((previousValue != null))
-					{
-						this._Statistics.Entity = null;
-						previousValue.UserStatistics.Remove(this);
-					}
-					this._Statistics.Entity = value;
-					if ((value != null))
-					{
-						value.UserStatistics.Add(this);
-						this._StatisticsId = value.StatisticsId;
-					}
-					else
-					{
-						this._StatisticsId = default(System.Guid);
-					}
-					this.SendPropertyChanged("Statistics");
-				}
-			}
-		}
-		
-		public event PropertyChangingEventHandler PropertyChanging;
-		
-		public event PropertyChangedEventHandler PropertyChanged;
-		
-		protected virtual void SendPropertyChanging()
-		{
-			if ((this.PropertyChanging != null))
-			{
-				this.PropertyChanging(this, emptyChangingEventArgs);
-			}
-		}
-		
-		protected virtual void SendPropertyChanged(String propertyName)
-		{
-			if ((this.PropertyChanged != null))
-			{
-				this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
-			}
-		}
-	}
-	
-	[global::System.Data.Linq.Mapping.TableAttribute(Name="")]
-	public partial class SlaveStatistics : INotifyPropertyChanging, INotifyPropertyChanged
-	{
-		
-		private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
-		
-		private System.Guid _StatisticsId;
-		
-		private System.Guid _SlaveId;
-		
-		private int _Cores;
-		
-		private int _FreeCores;
-		
-		private double _CpuUtilization;
-		
-		private int _Memory;
-		
-		private int _FreeMemory;
-		
-		private EntityRef<Statistics> _Statistics;
-		
-    #region Extensibility Method Definitions
-    partial void OnLoaded();
-    partial void OnValidate(System.Data.Linq.ChangeAction action);
-    partial void OnCreated();
-    partial void OnStatisticsIdChanging(System.Guid value);
-    partial void OnStatisticsIdChanged();
-    partial void OnSlaveIdChanging(System.Guid value);
-    partial void OnSlaveIdChanged();
-    partial void OnCoresChanging(int value);
-    partial void OnCoresChanged();
-    partial void OnFreeCoresChanging(int value);
-    partial void OnFreeCoresChanged();
-    partial void OnCpuUtilizationChanging(double value);
-    partial void OnCpuUtilizationChanged();
-    partial void OnMemoryChanging(int value);
-    partial void OnMemoryChanged();
-    partial void OnFreeMemoryChanging(int value);
-    partial void OnFreeMemoryChanged();
-    #endregion
-		
-		public SlaveStatistics()
-		{
-			this._Statistics = default(EntityRef<Statistics>);
-			OnCreated();
-		}
-		
-		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_StatisticsId", DbType="UniqueIdentifier NOT NULL", IsPrimaryKey=true)]
-		public System.Guid StatisticsId
-		{
-			get
-			{
-				return this._StatisticsId;
-			}
-			set
-			{
-				if ((this._StatisticsId != value))
-				{
-					if (this._Statistics.HasLoadedOrAssignedValue)
-					{
-						throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException();
-					}
-					this.OnStatisticsIdChanging(value);
-					this.SendPropertyChanging();
-					this._StatisticsId = value;
-					this.SendPropertyChanged("StatisticsId");
-					this.OnStatisticsIdChanged();
-				}
-			}
-		}
-		
-		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_SlaveId", DbType="UniqueIdentifier NOT NULL", IsPrimaryKey=true)]
-		public System.Guid SlaveId
-		{
-			get
-			{
-				return this._SlaveId;
-			}
-			set
-			{
-				if ((this._SlaveId != value))
-				{
-					this.OnSlaveIdChanging(value);
-					this.SendPropertyChanging();
-					this._SlaveId = value;
-					this.SendPropertyChanged("SlaveId");
-					this.OnSlaveIdChanged();
-				}
-			}
-		}
-		
-		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Cores", DbType="Int NOT NULL")]
-		public int Cores
-		{
-			get
-			{
-				return this._Cores;
-			}
-			set
-			{
-				if ((this._Cores != value))
-				{
-					this.OnCoresChanging(value);
-					this.SendPropertyChanging();
-					this._Cores = value;
-					this.SendPropertyChanged("Cores");
-					this.OnCoresChanged();
-				}
-			}
-		}
-		
-		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_FreeCores", DbType="Int NOT NULL")]
-		public int FreeCores
-		{
-			get
-			{
-				return this._FreeCores;
-			}
-			set
-			{
-				if ((this._FreeCores != value))
-				{
-					this.OnFreeCoresChanging(value);
-					this.SendPropertyChanging();
-					this._FreeCores = value;
-					this.SendPropertyChanged("FreeCores");
-					this.OnFreeCoresChanged();
-				}
-			}
-		}
-		
-		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_CpuUtilization", DbType="float NOT NULL")]
-		public double CpuUtilization
-		{
-			get
-			{
-				return this._CpuUtilization;
-			}
-			set
-			{
-				if ((this._CpuUtilization != value))
-				{
-					this.OnCpuUtilizationChanging(value);
-					this.SendPropertyChanging();
-					this._CpuUtilization = value;
-					this.SendPropertyChanged("CpuUtilization");
-					this.OnCpuUtilizationChanged();
-				}
-			}
-		}
-		
-		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Memory", DbType="Int NOT NULL")]
-		public int Memory
-		{
-			get
-			{
-				return this._Memory;
-			}
-			set
-			{
-				if ((this._Memory != value))
-				{
-					this.OnMemoryChanging(value);
-					this.SendPropertyChanging();
-					this._Memory = value;
-					this.SendPropertyChanged("Memory");
-					this.OnMemoryChanged();
-				}
-			}
-		}
-		
-		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_FreeMemory", DbType="Int NOT NULL")]
-		public int FreeMemory
-		{
-			get
-			{
-				return this._FreeMemory;
-			}
-			set
-			{
-				if ((this._FreeMemory != value))
-				{
-					this.OnFreeMemoryChanging(value);
-					this.SendPropertyChanging();
-					this._FreeMemory = value;
-					this.SendPropertyChanged("FreeMemory");
-					this.OnFreeMemoryChanged();
-				}
-			}
-		}
-		
-		[global::System.Data.Linq.Mapping.AssociationAttribute(Name="Statistics_SlaveStatistics", Storage="_Statistics", ThisKey="StatisticsId", OtherKey="StatisticsId", IsForeignKey=true)]
-		public Statistics Statistics
-		{
-			get
-			{
-				return this._Statistics.Entity;
-			}
-			set
-			{
-				Statistics previousValue = this._Statistics.Entity;
-				if (((previousValue != value) 
-							|| (this._Statistics.HasLoadedOrAssignedValue == false)))
-				{
-					this.SendPropertyChanging();
-					if ((previousValue != null))
-					{
-						this._Statistics.Entity = null;
-						previousValue.SlaveStatistics.Remove(this);
-					}
-					this._Statistics.Entity = value;
-					if ((value != null))
-					{
-						value.SlaveStatistics.Add(this);
-						this._StatisticsId = value.StatisticsId;
-					}
-					else
-					{
-						this._StatisticsId = default(System.Guid);
-					}
-					this.SendPropertyChanged("Statistics");
-				}
-			}
-		}
-		
-		public event PropertyChangingEventHandler PropertyChanging;
-		
-		public event PropertyChangedEventHandler PropertyChanged;
-		
-		protected virtual void SendPropertyChanging()
-		{
-			if ((this.PropertyChanging != null))
-			{
-				this.PropertyChanging(this, emptyChangingEventArgs);
-			}
-		}
-		
-		protected virtual void SendPropertyChanged(String propertyName)
-		{
-			if ((this.PropertyChanged != null))
-			{
-				this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
-			}
-		}
-	}
-	
-	[global::System.Data.Linq.Mapping.TableAttribute(Name="")]
-	public partial class Statistics : INotifyPropertyChanging, INotifyPropertyChanged
-	{
-		
-		private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
-		
-		private System.Guid _StatisticsId;
-		
-		private System.DateTime _Timestamp;
-		
-		private EntitySet<UserStatistics> _UserStatistics;
-		
-		private EntitySet<SlaveStatistics> _SlaveStatistics;
-		
-    #region Extensibility Method Definitions
-    partial void OnLoaded();
-    partial void OnValidate(System.Data.Linq.ChangeAction action);
-    partial void OnCreated();
-    partial void OnStatisticsIdChanging(System.Guid value);
-    partial void OnStatisticsIdChanged();
-    partial void OnTimestampChanging(System.DateTime value);
-    partial void OnTimestampChanged();
-    #endregion
-		
-		public Statistics()
-		{
-			this._UserStatistics = new EntitySet<UserStatistics>(new Action<UserStatistics>(this.attach_UserStatistics), new Action<UserStatistics>(this.detach_UserStatistics));
-			this._SlaveStatistics = new EntitySet<SlaveStatistics>(new Action<SlaveStatistics>(this.attach_SlaveStatistics), new Action<SlaveStatistics>(this.detach_SlaveStatistics));
-			OnCreated();
-		}
-		
-		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_StatisticsId", AutoSync=AutoSync.OnInsert, DbType="UniqueIdentifier NOT NULL", IsPrimaryKey=true, IsDbGenerated=true)]
-		public System.Guid StatisticsId
-		{
-			get
-			{
-				return this._StatisticsId;
-			}
-			set
-			{
-				if ((this._StatisticsId != value))
-				{
-					this.OnStatisticsIdChanging(value);
-					this.SendPropertyChanging();
-					this._StatisticsId = value;
-					this.SendPropertyChanged("StatisticsId");
-					this.OnStatisticsIdChanged();
-				}
-			}
-		}
-		
-		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Timestamp")]
-		public System.DateTime Timestamp
-		{
-			get
-			{
-				return this._Timestamp;
-			}
-			set
-			{
-				if ((this._Timestamp != value))
-				{
-					this.OnTimestampChanging(value);
-					this.SendPropertyChanging();
-					this._Timestamp = value;
-					this.SendPropertyChanged("Timestamp");
-					this.OnTimestampChanged();
-				}
-			}
-		}
-		
-		[global::System.Data.Linq.Mapping.AssociationAttribute(Name="Statistics_UserStatistics", Storage="_UserStatistics", ThisKey="StatisticsId", OtherKey="StatisticsId")]
-		public EntitySet<UserStatistics> UserStatistics
-		{
-			get
-			{
-				return this._UserStatistics;
-			}
-			set
-			{
-				this._UserStatistics.Assign(value);
-			}
-		}
-		
-		[global::System.Data.Linq.Mapping.AssociationAttribute(Name="Statistics_SlaveStatistics", Storage="_SlaveStatistics", ThisKey="StatisticsId", OtherKey="StatisticsId")]
-		public EntitySet<SlaveStatistics> SlaveStatistics
-		{
-			get
-			{
-				return this._SlaveStatistics;
-			}
-			set
-			{
-				this._SlaveStatistics.Assign(value);
-			}
-		}
-		
-		public event PropertyChangingEventHandler PropertyChanging;
-		
-		public event PropertyChangedEventHandler PropertyChanged;
-		
-		protected virtual void SendPropertyChanging()
-		{
-			if ((this.PropertyChanging != null))
-			{
-				this.PropertyChanging(this, emptyChangingEventArgs);
-			}
-		}
-		
-		protected virtual void SendPropertyChanged(String propertyName)
-		{
-			if ((this.PropertyChanged != null))
-			{
-				this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
-			}
-		}
-		
-		private void attach_UserStatistics(UserStatistics entity)
-		{
-			this.SendPropertyChanging();
-			entity.Statistics = this;
-		}
-		
-		private void detach_UserStatistics(UserStatistics entity)
-		{
-			this.SendPropertyChanging();
-			entity.Statistics = null;
-		}
-		
-		private void attach_SlaveStatistics(SlaveStatistics entity)
-		{
-			this.SendPropertyChanging();
-			entity.Statistics = this;
-		}
-		
-		private void detach_SlaveStatistics(SlaveStatistics entity)
-		{
-			this.SendPropertyChanging();
-			entity.Statistics = null;
-		}
-	}
-	
 	[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.ResourcePermission")]
 	public partial class ResourcePermission : INotifyPropertyChanging, INotifyPropertyChanged
@@ -4534,4 +3786,1849 @@
 		}
 	}
+	
+	[global::System.Data.Linq.Mapping.TableAttribute(Name="[statistics].DimClient")]
+	public partial class DimClient : INotifyPropertyChanging, INotifyPropertyChanged
+	{
+		
+		private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
+		
+		private System.Guid _Id;
+		
+		private string _Name;
+		
+		private System.Guid _ResourceId;
+		
+		private System.Nullable<System.DateTime> _ExpirationTime;
+		
+		private System.Nullable<System.Guid> _ResourceGroupId;
+		
+		private System.Nullable<System.Guid> _ResourceGroup2Id;
+		
+		private string _GroupName;
+		
+		private string _GroupName2;
+		
+		private EntitySet<FactTask> _FactTasks;
+		
+		private EntitySet<FactClientInfo> _FactClientInfos;
+		
+    #region Extensibility Method Definitions
+    partial void OnLoaded();
+    partial void OnValidate(System.Data.Linq.ChangeAction action);
+    partial void OnCreated();
+    partial void OnIdChanging(System.Guid value);
+    partial void OnIdChanged();
+    partial void OnNameChanging(string value);
+    partial void OnNameChanged();
+    partial void OnResourceIdChanging(System.Guid value);
+    partial void OnResourceIdChanged();
+    partial void OnExpirationTimeChanging(System.Nullable<System.DateTime> value);
+    partial void OnExpirationTimeChanged();
+    partial void OnResourceGroupIdChanging(System.Nullable<System.Guid> value);
+    partial void OnResourceGroupIdChanged();
+    partial void OnResourceGroup2IdChanging(System.Nullable<System.Guid> value);
+    partial void OnResourceGroup2IdChanged();
+    partial void OnGroupNameChanging(string value);
+    partial void OnGroupNameChanged();
+    partial void OnGroupName2Changing(string value);
+    partial void OnGroupName2Changed();
+    #endregion
+		
+		public DimClient()
+		{
+			this._FactTasks = new EntitySet<FactTask>(new Action<FactTask>(this.attach_FactTasks), new Action<FactTask>(this.detach_FactTasks));
+			this._FactClientInfos = new EntitySet<FactClientInfo>(new Action<FactClientInfo>(this.attach_FactClientInfos), new Action<FactClientInfo>(this.detach_FactClientInfos));
+			OnCreated();
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Id", AutoSync=AutoSync.OnInsert, DbType="UniqueIdentifier NOT NULL", IsPrimaryKey=true, IsDbGenerated=true)]
+		public System.Guid Id
+		{
+			get
+			{
+				return this._Id;
+			}
+			set
+			{
+				if ((this._Id != value))
+				{
+					this.OnIdChanging(value);
+					this.SendPropertyChanging();
+					this._Id = value;
+					this.SendPropertyChanged("Id");
+					this.OnIdChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Name", DbType="VarChar(MAX) NOT NULL", CanBeNull=false)]
+		public string Name
+		{
+			get
+			{
+				return this._Name;
+			}
+			set
+			{
+				if ((this._Name != value))
+				{
+					this.OnNameChanging(value);
+					this.SendPropertyChanging();
+					this._Name = value;
+					this.SendPropertyChanged("Name");
+					this.OnNameChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ResourceId", DbType="UniqueIdentifier NOT NULL")]
+		public System.Guid ResourceId
+		{
+			get
+			{
+				return this._ResourceId;
+			}
+			set
+			{
+				if ((this._ResourceId != value))
+				{
+					this.OnResourceIdChanging(value);
+					this.SendPropertyChanging();
+					this._ResourceId = value;
+					this.SendPropertyChanged("ResourceId");
+					this.OnResourceIdChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ExpirationTime", DbType="DateTime")]
+		public System.Nullable<System.DateTime> ExpirationTime
+		{
+			get
+			{
+				return this._ExpirationTime;
+			}
+			set
+			{
+				if ((this._ExpirationTime != value))
+				{
+					this.OnExpirationTimeChanging(value);
+					this.SendPropertyChanging();
+					this._ExpirationTime = value;
+					this.SendPropertyChanged("ExpirationTime");
+					this.OnExpirationTimeChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ResourceGroupId", DbType="UniqueIdentifier")]
+		public System.Nullable<System.Guid> ResourceGroupId
+		{
+			get
+			{
+				return this._ResourceGroupId;
+			}
+			set
+			{
+				if ((this._ResourceGroupId != value))
+				{
+					this.OnResourceGroupIdChanging(value);
+					this.SendPropertyChanging();
+					this._ResourceGroupId = value;
+					this.SendPropertyChanged("ResourceGroupId");
+					this.OnResourceGroupIdChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ResourceGroup2Id", DbType="UniqueIdentifier")]
+		public System.Nullable<System.Guid> ResourceGroup2Id
+		{
+			get
+			{
+				return this._ResourceGroup2Id;
+			}
+			set
+			{
+				if ((this._ResourceGroup2Id != value))
+				{
+					this.OnResourceGroup2IdChanging(value);
+					this.SendPropertyChanging();
+					this._ResourceGroup2Id = value;
+					this.SendPropertyChanged("ResourceGroup2Id");
+					this.OnResourceGroup2IdChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_GroupName")]
+		public string GroupName
+		{
+			get
+			{
+				return this._GroupName;
+			}
+			set
+			{
+				if ((this._GroupName != value))
+				{
+					this.OnGroupNameChanging(value);
+					this.SendPropertyChanging();
+					this._GroupName = value;
+					this.SendPropertyChanged("GroupName");
+					this.OnGroupNameChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_GroupName2")]
+		public string GroupName2
+		{
+			get
+			{
+				return this._GroupName2;
+			}
+			set
+			{
+				if ((this._GroupName2 != value))
+				{
+					this.OnGroupName2Changing(value);
+					this.SendPropertyChanging();
+					this._GroupName2 = value;
+					this.SendPropertyChanged("GroupName2");
+					this.OnGroupName2Changed();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.AssociationAttribute(Name="DimClient_FactTask", Storage="_FactTasks", ThisKey="Id", OtherKey="LastClientId")]
+		public EntitySet<FactTask> FactTasks
+		{
+			get
+			{
+				return this._FactTasks;
+			}
+			set
+			{
+				this._FactTasks.Assign(value);
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.AssociationAttribute(Name="DimClient_FactClientInfo", Storage="_FactClientInfos", ThisKey="Id", OtherKey="ClientId")]
+		public EntitySet<FactClientInfo> FactClientInfos
+		{
+			get
+			{
+				return this._FactClientInfos;
+			}
+			set
+			{
+				this._FactClientInfos.Assign(value);
+			}
+		}
+		
+		public event PropertyChangingEventHandler PropertyChanging;
+		
+		public event PropertyChangedEventHandler PropertyChanged;
+		
+		protected virtual void SendPropertyChanging()
+		{
+			if ((this.PropertyChanging != null))
+			{
+				this.PropertyChanging(this, emptyChangingEventArgs);
+			}
+		}
+		
+		protected virtual void SendPropertyChanged(String propertyName)
+		{
+			if ((this.PropertyChanged != null))
+			{
+				this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
+			}
+		}
+		
+		private void attach_FactTasks(FactTask entity)
+		{
+			this.SendPropertyChanging();
+			entity.DimClient = this;
+		}
+		
+		private void detach_FactTasks(FactTask entity)
+		{
+			this.SendPropertyChanging();
+			entity.DimClient = null;
+		}
+		
+		private void attach_FactClientInfos(FactClientInfo entity)
+		{
+			this.SendPropertyChanging();
+			entity.DimClient = this;
+		}
+		
+		private void detach_FactClientInfos(FactClientInfo entity)
+		{
+			this.SendPropertyChanging();
+			entity.DimClient = null;
+		}
+	}
+	
+	[global::System.Data.Linq.Mapping.TableAttribute(Name="[statistics].FactTask")]
+	public partial class FactTask : INotifyPropertyChanging, INotifyPropertyChanged
+	{
+		
+		private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
+		
+		private System.Guid _TaskId;
+		
+		private long _TotalRuntime;
+		
+		private long _TotalWaitingTime;
+		
+		private long _TotalTransferTime;
+		
+		private int _NumCalculationRuns;
+		
+		private int _NumFails;
+		
+		private int _CoresRequired;
+		
+		private int _MemoryRequired;
+		
+		private int _Priority;
+		
+		private System.Nullable<System.Guid> _LastClientId;
+		
+		private System.Guid _JobId;
+		
+		private System.Nullable<System.DateTime> _EndTime;
+		
+		private global::HeuristicLab.Services.Hive.DataAccess.TaskState _TaskState;
+		
+		private string _Exception;
+		
+		private long _InitialWaitingTimeMs;
+		
+		private System.Nullable<System.DateTime> _StartTime;
+		
+		private EntityRef<DimClient> _DimClient;
+		
+		private EntityRef<DimJob> _DimJob;
+		
+    #region Extensibility Method Definitions
+    partial void OnLoaded();
+    partial void OnValidate(System.Data.Linq.ChangeAction action);
+    partial void OnCreated();
+    partial void OnTaskIdChanging(System.Guid value);
+    partial void OnTaskIdChanged();
+    partial void OnCalculatingTimeChanging(long value);
+    partial void OnCalculatingTimeChanged();
+    partial void OnWaitingTimeChanging(long value);
+    partial void OnWaitingTimeChanged();
+    partial void OnTransferTimeChanging(long value);
+    partial void OnTransferTimeChanged();
+    partial void OnNumCalculationRunsChanging(int value);
+    partial void OnNumCalculationRunsChanged();
+    partial void OnNumRetriesChanging(int value);
+    partial void OnNumRetriesChanged();
+    partial void OnCoresRequiredChanging(int value);
+    partial void OnCoresRequiredChanged();
+    partial void OnMemoryRequiredChanging(int value);
+    partial void OnMemoryRequiredChanged();
+    partial void OnPriorityChanging(int value);
+    partial void OnPriorityChanged();
+    partial void OnLastClientIdChanging(System.Nullable<System.Guid> value);
+    partial void OnLastClientIdChanged();
+    partial void OnJobIdChanging(System.Guid value);
+    partial void OnJobIdChanged();
+    partial void OnEndTimeChanging(System.Nullable<System.DateTime> value);
+    partial void OnEndTimeChanged();
+    partial void OnTaskStateChanging(global::HeuristicLab.Services.Hive.DataAccess.TaskState value);
+    partial void OnTaskStateChanged();
+    partial void OnExceptionChanging(string value);
+    partial void OnExceptionChanged();
+    partial void OnInitialWaitingTimeChanging(long value);
+    partial void OnInitialWaitingTimeChanged();
+    partial void OnStartTimeChanging(System.Nullable<System.DateTime> value);
+    partial void OnStartTimeChanged();
+    #endregion
+		
+		public FactTask()
+		{
+			this._DimClient = default(EntityRef<DimClient>);
+			this._DimJob = default(EntityRef<DimJob>);
+			OnCreated();
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_TaskId", DbType="UniqueIdentifier NOT NULL", IsPrimaryKey=true)]
+		public System.Guid TaskId
+		{
+			get
+			{
+				return this._TaskId;
+			}
+			set
+			{
+				if ((this._TaskId != value))
+				{
+					this.OnTaskIdChanging(value);
+					this.SendPropertyChanging();
+					this._TaskId = value;
+					this.SendPropertyChanged("TaskId");
+					this.OnTaskIdChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_TotalRuntime", DbType="INT NOT NULL")]
+		public long CalculatingTime
+		{
+			get
+			{
+				return this._TotalRuntime;
+			}
+			set
+			{
+				if ((this._TotalRuntime != value))
+				{
+					this.OnCalculatingTimeChanging(value);
+					this.SendPropertyChanging();
+					this._TotalRuntime = value;
+					this.SendPropertyChanged("CalculatingTime");
+					this.OnCalculatingTimeChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_TotalWaitingTime", DbType="INT NOT NULL")]
+		public long WaitingTime
+		{
+			get
+			{
+				return this._TotalWaitingTime;
+			}
+			set
+			{
+				if ((this._TotalWaitingTime != value))
+				{
+					this.OnWaitingTimeChanging(value);
+					this.SendPropertyChanging();
+					this._TotalWaitingTime = value;
+					this.SendPropertyChanged("WaitingTime");
+					this.OnWaitingTimeChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_TotalTransferTime", DbType="INT NOT NULL")]
+		public long TransferTime
+		{
+			get
+			{
+				return this._TotalTransferTime;
+			}
+			set
+			{
+				if ((this._TotalTransferTime != value))
+				{
+					this.OnTransferTimeChanging(value);
+					this.SendPropertyChanging();
+					this._TotalTransferTime = value;
+					this.SendPropertyChanged("TransferTime");
+					this.OnTransferTimeChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_NumCalculationRuns", DbType="Int NOT NULL")]
+		public int NumCalculationRuns
+		{
+			get
+			{
+				return this._NumCalculationRuns;
+			}
+			set
+			{
+				if ((this._NumCalculationRuns != value))
+				{
+					this.OnNumCalculationRunsChanging(value);
+					this.SendPropertyChanging();
+					this._NumCalculationRuns = value;
+					this.SendPropertyChanged("NumCalculationRuns");
+					this.OnNumCalculationRunsChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_NumFails", DbType="Int NOT NULL")]
+		public int NumRetries
+		{
+			get
+			{
+				return this._NumFails;
+			}
+			set
+			{
+				if ((this._NumFails != value))
+				{
+					this.OnNumRetriesChanging(value);
+					this.SendPropertyChanging();
+					this._NumFails = value;
+					this.SendPropertyChanged("NumRetries");
+					this.OnNumRetriesChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_CoresRequired", DbType="Int NOT NULL")]
+		public int CoresRequired
+		{
+			get
+			{
+				return this._CoresRequired;
+			}
+			set
+			{
+				if ((this._CoresRequired != value))
+				{
+					this.OnCoresRequiredChanging(value);
+					this.SendPropertyChanging();
+					this._CoresRequired = value;
+					this.SendPropertyChanged("CoresRequired");
+					this.OnCoresRequiredChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_MemoryRequired", DbType="Int NOT NULL")]
+		public int MemoryRequired
+		{
+			get
+			{
+				return this._MemoryRequired;
+			}
+			set
+			{
+				if ((this._MemoryRequired != value))
+				{
+					this.OnMemoryRequiredChanging(value);
+					this.SendPropertyChanging();
+					this._MemoryRequired = value;
+					this.SendPropertyChanged("MemoryRequired");
+					this.OnMemoryRequiredChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Priority", DbType="Int NOT NULL")]
+		public int Priority
+		{
+			get
+			{
+				return this._Priority;
+			}
+			set
+			{
+				if ((this._Priority != value))
+				{
+					this.OnPriorityChanging(value);
+					this.SendPropertyChanging();
+					this._Priority = value;
+					this.SendPropertyChanged("Priority");
+					this.OnPriorityChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_LastClientId", DbType="UniqueIdentifier NOT NULL")]
+		public System.Nullable<System.Guid> LastClientId
+		{
+			get
+			{
+				return this._LastClientId;
+			}
+			set
+			{
+				if ((this._LastClientId != value))
+				{
+					if (this._DimClient.HasLoadedOrAssignedValue)
+					{
+						throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException();
+					}
+					this.OnLastClientIdChanging(value);
+					this.SendPropertyChanging();
+					this._LastClientId = value;
+					this.SendPropertyChanged("LastClientId");
+					this.OnLastClientIdChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_JobId", DbType="UniqueIdentifier NOT NULL")]
+		public System.Guid JobId
+		{
+			get
+			{
+				return this._JobId;
+			}
+			set
+			{
+				if ((this._JobId != value))
+				{
+					if (this._DimJob.HasLoadedOrAssignedValue)
+					{
+						throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException();
+					}
+					this.OnJobIdChanging(value);
+					this.SendPropertyChanging();
+					this._JobId = value;
+					this.SendPropertyChanged("JobId");
+					this.OnJobIdChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_EndTime", DbType="DateTime NOT NULL")]
+		public System.Nullable<System.DateTime> EndTime
+		{
+			get
+			{
+				return this._EndTime;
+			}
+			set
+			{
+				if ((this._EndTime != value))
+				{
+					this.OnEndTimeChanging(value);
+					this.SendPropertyChanging();
+					this._EndTime = value;
+					this.SendPropertyChanged("EndTime");
+					this.OnEndTimeChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_TaskState", DbType="varchar(30)", CanBeNull=false)]
+		public global::HeuristicLab.Services.Hive.DataAccess.TaskState TaskState
+		{
+			get
+			{
+				return this._TaskState;
+			}
+			set
+			{
+				if ((this._TaskState != value))
+				{
+					this.OnTaskStateChanging(value);
+					this.SendPropertyChanging();
+					this._TaskState = value;
+					this.SendPropertyChanged("TaskState");
+					this.OnTaskStateChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Exception", DbType="varchar(MAX)")]
+		public string Exception
+		{
+			get
+			{
+				return this._Exception;
+			}
+			set
+			{
+				if ((this._Exception != value))
+				{
+					this.OnExceptionChanging(value);
+					this.SendPropertyChanging();
+					this._Exception = value;
+					this.SendPropertyChanged("Exception");
+					this.OnExceptionChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_InitialWaitingTimeMs", DbType="INT")]
+		public long InitialWaitingTime
+		{
+			get
+			{
+				return this._InitialWaitingTimeMs;
+			}
+			set
+			{
+				if ((this._InitialWaitingTimeMs != value))
+				{
+					this.OnInitialWaitingTimeChanging(value);
+					this.SendPropertyChanging();
+					this._InitialWaitingTimeMs = value;
+					this.SendPropertyChanged("InitialWaitingTime");
+					this.OnInitialWaitingTimeChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_StartTime")]
+		public System.Nullable<System.DateTime> StartTime
+		{
+			get
+			{
+				return this._StartTime;
+			}
+			set
+			{
+				if ((this._StartTime != value))
+				{
+					this.OnStartTimeChanging(value);
+					this.SendPropertyChanging();
+					this._StartTime = value;
+					this.SendPropertyChanged("StartTime");
+					this.OnStartTimeChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.AssociationAttribute(Name="DimClient_FactTask", Storage="_DimClient", ThisKey="LastClientId", OtherKey="Id", IsForeignKey=true)]
+		public DimClient DimClient
+		{
+			get
+			{
+				return this._DimClient.Entity;
+			}
+			set
+			{
+				DimClient previousValue = this._DimClient.Entity;
+				if (((previousValue != value) 
+							|| (this._DimClient.HasLoadedOrAssignedValue == false)))
+				{
+					this.SendPropertyChanging();
+					if ((previousValue != null))
+					{
+						this._DimClient.Entity = null;
+						previousValue.FactTasks.Remove(this);
+					}
+					this._DimClient.Entity = value;
+					if ((value != null))
+					{
+						value.FactTasks.Add(this);
+						this._LastClientId = value.Id;
+					}
+					else
+					{
+						this._LastClientId = default(Nullable<System.Guid>);
+					}
+					this.SendPropertyChanged("DimClient");
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.AssociationAttribute(Name="DimJob_FactTask", Storage="_DimJob", ThisKey="JobId", OtherKey="JobId", IsForeignKey=true)]
+		public DimJob DimJob
+		{
+			get
+			{
+				return this._DimJob.Entity;
+			}
+			set
+			{
+				DimJob previousValue = this._DimJob.Entity;
+				if (((previousValue != value) 
+							|| (this._DimJob.HasLoadedOrAssignedValue == false)))
+				{
+					this.SendPropertyChanging();
+					if ((previousValue != null))
+					{
+						this._DimJob.Entity = null;
+						previousValue.FactTasks.Remove(this);
+					}
+					this._DimJob.Entity = value;
+					if ((value != null))
+					{
+						value.FactTasks.Add(this);
+						this._JobId = value.JobId;
+					}
+					else
+					{
+						this._JobId = default(System.Guid);
+					}
+					this.SendPropertyChanged("DimJob");
+				}
+			}
+		}
+		
+		public event PropertyChangingEventHandler PropertyChanging;
+		
+		public event PropertyChangedEventHandler PropertyChanged;
+		
+		protected virtual void SendPropertyChanging()
+		{
+			if ((this.PropertyChanging != null))
+			{
+				this.PropertyChanging(this, emptyChangingEventArgs);
+			}
+		}
+		
+		protected virtual void SendPropertyChanged(String propertyName)
+		{
+			if ((this.PropertyChanged != null))
+			{
+				this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
+			}
+		}
+	}
+	
+	[global::System.Data.Linq.Mapping.TableAttribute(Name="[statistics].DimJob")]
+	public partial class DimJob : INotifyPropertyChanging, INotifyPropertyChanged
+	{
+		
+		private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
+		
+		private System.Guid _JobId;
+		
+		private System.Guid _UserId;
+		
+		private string _JobName;
+		
+		private string _UserName;
+		
+		private System.DateTime _DateCreated;
+		
+		private int _TotalTasks;
+		
+		private int _CompletedTasks;
+		
+		private System.Nullable<System.DateTime> _DateCompleted;
+		
+		private EntitySet<FactTask> _FactTasks;
+		
+    #region Extensibility Method Definitions
+    partial void OnLoaded();
+    partial void OnValidate(System.Data.Linq.ChangeAction action);
+    partial void OnCreated();
+    partial void OnJobIdChanging(System.Guid value);
+    partial void OnJobIdChanged();
+    partial void OnUserIdChanging(System.Guid value);
+    partial void OnUserIdChanged();
+    partial void OnJobNameChanging(string value);
+    partial void OnJobNameChanged();
+    partial void OnUserNameChanging(string value);
+    partial void OnUserNameChanged();
+    partial void OnDateCreatedChanging(System.DateTime value);
+    partial void OnDateCreatedChanged();
+    partial void OnTotalTasksChanging(int value);
+    partial void OnTotalTasksChanged();
+    partial void OnCompletedTasksChanging(int value);
+    partial void OnCompletedTasksChanged();
+    partial void OnDateCompletedChanging(System.Nullable<System.DateTime> value);
+    partial void OnDateCompletedChanged();
+    #endregion
+		
+		public DimJob()
+		{
+			this._FactTasks = new EntitySet<FactTask>(new Action<FactTask>(this.attach_FactTasks), new Action<FactTask>(this.detach_FactTasks));
+			OnCreated();
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_JobId", DbType="UniqueIdentifier NOT NULL", IsPrimaryKey=true)]
+		public System.Guid JobId
+		{
+			get
+			{
+				return this._JobId;
+			}
+			set
+			{
+				if ((this._JobId != value))
+				{
+					this.OnJobIdChanging(value);
+					this.SendPropertyChanging();
+					this._JobId = value;
+					this.SendPropertyChanged("JobId");
+					this.OnJobIdChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_UserId", DbType="UniqueIdentifier NOT NULL")]
+		public System.Guid UserId
+		{
+			get
+			{
+				return this._UserId;
+			}
+			set
+			{
+				if ((this._UserId != value))
+				{
+					this.OnUserIdChanging(value);
+					this.SendPropertyChanging();
+					this._UserId = value;
+					this.SendPropertyChanged("UserId");
+					this.OnUserIdChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_JobName", DbType="VarChar(MAX) NOT NULL", CanBeNull=false)]
+		public string JobName
+		{
+			get
+			{
+				return this._JobName;
+			}
+			set
+			{
+				if ((this._JobName != value))
+				{
+					this.OnJobNameChanging(value);
+					this.SendPropertyChanging();
+					this._JobName = value;
+					this.SendPropertyChanged("JobName");
+					this.OnJobNameChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_UserName", DbType="VarChar(MAX) NOT NULL", CanBeNull=false)]
+		public string UserName
+		{
+			get
+			{
+				return this._UserName;
+			}
+			set
+			{
+				if ((this._UserName != value))
+				{
+					this.OnUserNameChanging(value);
+					this.SendPropertyChanging();
+					this._UserName = value;
+					this.SendPropertyChanged("UserName");
+					this.OnUserNameChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_DateCreated", DbType="DateTime NOT NULL")]
+		public System.DateTime DateCreated
+		{
+			get
+			{
+				return this._DateCreated;
+			}
+			set
+			{
+				if ((this._DateCreated != value))
+				{
+					this.OnDateCreatedChanging(value);
+					this.SendPropertyChanging();
+					this._DateCreated = value;
+					this.SendPropertyChanged("DateCreated");
+					this.OnDateCreatedChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_TotalTasks", DbType="INT NOT NULL")]
+		public int TotalTasks
+		{
+			get
+			{
+				return this._TotalTasks;
+			}
+			set
+			{
+				if ((this._TotalTasks != value))
+				{
+					this.OnTotalTasksChanging(value);
+					this.SendPropertyChanging();
+					this._TotalTasks = value;
+					this.SendPropertyChanged("TotalTasks");
+					this.OnTotalTasksChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_CompletedTasks", DbType="INT NOT NULL")]
+		public int CompletedTasks
+		{
+			get
+			{
+				return this._CompletedTasks;
+			}
+			set
+			{
+				if ((this._CompletedTasks != value))
+				{
+					this.OnCompletedTasksChanging(value);
+					this.SendPropertyChanging();
+					this._CompletedTasks = value;
+					this.SendPropertyChanged("CompletedTasks");
+					this.OnCompletedTasksChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_DateCompleted", DbType="DateTime NULL")]
+		public System.Nullable<System.DateTime> DateCompleted
+		{
+			get
+			{
+				return this._DateCompleted;
+			}
+			set
+			{
+				if ((this._DateCompleted != value))
+				{
+					this.OnDateCompletedChanging(value);
+					this.SendPropertyChanging();
+					this._DateCompleted = value;
+					this.SendPropertyChanged("DateCompleted");
+					this.OnDateCompletedChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.AssociationAttribute(Name="DimJob_FactTask", Storage="_FactTasks", ThisKey="JobId", OtherKey="JobId")]
+		public EntitySet<FactTask> FactTasks
+		{
+			get
+			{
+				return this._FactTasks;
+			}
+			set
+			{
+				this._FactTasks.Assign(value);
+			}
+		}
+		
+		public event PropertyChangingEventHandler PropertyChanging;
+		
+		public event PropertyChangedEventHandler PropertyChanged;
+		
+		protected virtual void SendPropertyChanging()
+		{
+			if ((this.PropertyChanging != null))
+			{
+				this.PropertyChanging(this, emptyChangingEventArgs);
+			}
+		}
+		
+		protected virtual void SendPropertyChanged(String propertyName)
+		{
+			if ((this.PropertyChanged != null))
+			{
+				this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
+			}
+		}
+		
+		private void attach_FactTasks(FactTask entity)
+		{
+			this.SendPropertyChanging();
+			entity.DimJob = this;
+		}
+		
+		private void detach_FactTasks(FactTask entity)
+		{
+			this.SendPropertyChanging();
+			entity.DimJob = null;
+		}
+	}
+	
+	[global::System.Data.Linq.Mapping.TableAttribute(Name="[statistics].DimTime")]
+	public partial class DimTime : INotifyPropertyChanging, INotifyPropertyChanged
+	{
+		
+		private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
+		
+		private System.DateTime _Time;
+		
+		private System.DateTime _Hour;
+		
+		private System.DateTime _Day;
+		
+		private System.DateTime _Month;
+		
+		private System.DateTime _Year;
+		
+		private System.DateTime _Minute;
+		
+		private EntitySet<FactClientInfo> _FactClientInfos;
+		
+    #region Extensibility Method Definitions
+    partial void OnLoaded();
+    partial void OnValidate(System.Data.Linq.ChangeAction action);
+    partial void OnCreated();
+    partial void OnTimeChanging(System.DateTime value);
+    partial void OnTimeChanged();
+    partial void OnHourChanging(System.DateTime value);
+    partial void OnHourChanged();
+    partial void OnDayChanging(System.DateTime value);
+    partial void OnDayChanged();
+    partial void OnMonthChanging(System.DateTime value);
+    partial void OnMonthChanged();
+    partial void OnYearChanging(System.DateTime value);
+    partial void OnYearChanged();
+    partial void OnMinuteChanging(System.DateTime value);
+    partial void OnMinuteChanged();
+    #endregion
+		
+		public DimTime()
+		{
+			this._FactClientInfos = new EntitySet<FactClientInfo>(new Action<FactClientInfo>(this.attach_FactClientInfos), new Action<FactClientInfo>(this.detach_FactClientInfos));
+			OnCreated();
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Time", DbType="DateTime NOT NULL", IsPrimaryKey=true)]
+		public System.DateTime Time
+		{
+			get
+			{
+				return this._Time;
+			}
+			set
+			{
+				if ((this._Time != value))
+				{
+					this.OnTimeChanging(value);
+					this.SendPropertyChanging();
+					this._Time = value;
+					this.SendPropertyChanged("Time");
+					this.OnTimeChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Hour", DbType="DateTime NOT NULL")]
+		public System.DateTime Hour
+		{
+			get
+			{
+				return this._Hour;
+			}
+			set
+			{
+				if ((this._Hour != value))
+				{
+					this.OnHourChanging(value);
+					this.SendPropertyChanging();
+					this._Hour = value;
+					this.SendPropertyChanged("Hour");
+					this.OnHourChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Day", DbType="Date NOT NULL")]
+		public System.DateTime Day
+		{
+			get
+			{
+				return this._Day;
+			}
+			set
+			{
+				if ((this._Day != value))
+				{
+					this.OnDayChanging(value);
+					this.SendPropertyChanging();
+					this._Day = value;
+					this.SendPropertyChanged("Day");
+					this.OnDayChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Month", DbType="Date NOT NULL")]
+		public System.DateTime Month
+		{
+			get
+			{
+				return this._Month;
+			}
+			set
+			{
+				if ((this._Month != value))
+				{
+					this.OnMonthChanging(value);
+					this.SendPropertyChanging();
+					this._Month = value;
+					this.SendPropertyChanged("Month");
+					this.OnMonthChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Year", DbType="Date NOT NULL")]
+		public System.DateTime Year
+		{
+			get
+			{
+				return this._Year;
+			}
+			set
+			{
+				if ((this._Year != value))
+				{
+					this.OnYearChanging(value);
+					this.SendPropertyChanging();
+					this._Year = value;
+					this.SendPropertyChanged("Year");
+					this.OnYearChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Minute")]
+		public System.DateTime Minute
+		{
+			get
+			{
+				return this._Minute;
+			}
+			set
+			{
+				if ((this._Minute != value))
+				{
+					this.OnMinuteChanging(value);
+					this.SendPropertyChanging();
+					this._Minute = value;
+					this.SendPropertyChanged("Minute");
+					this.OnMinuteChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.AssociationAttribute(Name="DimTime_FactClientInfo", Storage="_FactClientInfos", ThisKey="Time", OtherKey="Time")]
+		public EntitySet<FactClientInfo> FactClientInfos
+		{
+			get
+			{
+				return this._FactClientInfos;
+			}
+			set
+			{
+				this._FactClientInfos.Assign(value);
+			}
+		}
+		
+		public event PropertyChangingEventHandler PropertyChanging;
+		
+		public event PropertyChangedEventHandler PropertyChanged;
+		
+		protected virtual void SendPropertyChanging()
+		{
+			if ((this.PropertyChanging != null))
+			{
+				this.PropertyChanging(this, emptyChangingEventArgs);
+			}
+		}
+		
+		protected virtual void SendPropertyChanged(String propertyName)
+		{
+			if ((this.PropertyChanged != null))
+			{
+				this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
+			}
+		}
+		
+		private void attach_FactClientInfos(FactClientInfo entity)
+		{
+			this.SendPropertyChanging();
+			entity.DimTime = this;
+		}
+		
+		private void detach_FactClientInfos(FactClientInfo entity)
+		{
+			this.SendPropertyChanging();
+			entity.DimTime = null;
+		}
+	}
+	
+	[global::System.Data.Linq.Mapping.TableAttribute(Name="[statistics].DimUser")]
+	public partial class DimUser : INotifyPropertyChanging, INotifyPropertyChanged
+	{
+		
+		private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
+		
+		private System.Guid _UserId;
+		
+		private string _Name;
+		
+		private EntitySet<FactClientInfo> _FactClientInfos;
+		
+    #region Extensibility Method Definitions
+    partial void OnLoaded();
+    partial void OnValidate(System.Data.Linq.ChangeAction action);
+    partial void OnCreated();
+    partial void OnUserIdChanging(System.Guid value);
+    partial void OnUserIdChanged();
+    partial void OnNameChanging(string value);
+    partial void OnNameChanged();
+    #endregion
+		
+		public DimUser()
+		{
+			this._FactClientInfos = new EntitySet<FactClientInfo>(new Action<FactClientInfo>(this.attach_FactClientInfos), new Action<FactClientInfo>(this.detach_FactClientInfos));
+			OnCreated();
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_UserId", DbType="UniqueIdentifier NOT NULL", IsPrimaryKey=true)]
+		public System.Guid UserId
+		{
+			get
+			{
+				return this._UserId;
+			}
+			set
+			{
+				if ((this._UserId != value))
+				{
+					this.OnUserIdChanging(value);
+					this.SendPropertyChanging();
+					this._UserId = value;
+					this.SendPropertyChanged("UserId");
+					this.OnUserIdChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Name", DbType="VarChar(MAX) NOT NULL", CanBeNull=false)]
+		public string Name
+		{
+			get
+			{
+				return this._Name;
+			}
+			set
+			{
+				if ((this._Name != value))
+				{
+					this.OnNameChanging(value);
+					this.SendPropertyChanging();
+					this._Name = value;
+					this.SendPropertyChanged("Name");
+					this.OnNameChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.AssociationAttribute(Name="DimUser_FactClientInfo", Storage="_FactClientInfos", ThisKey="UserId", OtherKey="UserId")]
+		public EntitySet<FactClientInfo> FactClientInfos
+		{
+			get
+			{
+				return this._FactClientInfos;
+			}
+			set
+			{
+				this._FactClientInfos.Assign(value);
+			}
+		}
+		
+		public event PropertyChangingEventHandler PropertyChanging;
+		
+		public event PropertyChangedEventHandler PropertyChanged;
+		
+		protected virtual void SendPropertyChanging()
+		{
+			if ((this.PropertyChanging != null))
+			{
+				this.PropertyChanging(this, emptyChangingEventArgs);
+			}
+		}
+		
+		protected virtual void SendPropertyChanged(String propertyName)
+		{
+			if ((this.PropertyChanged != null))
+			{
+				this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
+			}
+		}
+		
+		private void attach_FactClientInfos(FactClientInfo entity)
+		{
+			this.SendPropertyChanging();
+			entity.DimUser = this;
+		}
+		
+		private void detach_FactClientInfos(FactClientInfo entity)
+		{
+			this.SendPropertyChanging();
+			entity.DimUser = null;
+		}
+	}
+	
+	[global::System.Data.Linq.Mapping.TableAttribute(Name="[statistics].FactClientInfo")]
+	public partial class FactClientInfo : INotifyPropertyChanging, INotifyPropertyChanged
+	{
+		
+		private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
+		
+		private System.Guid _ClientId;
+		
+		private System.DateTime _Time;
+		
+		private System.Guid _UserId;
+		
+		private int _NumUsedCores;
+		
+		private int _NumTotalCores;
+		
+		private int _UsedMemory;
+		
+		private int _TotalMemory;
+		
+		private double _CpuUtilization;
+		
+		private long _TotalTimeIdle;
+		
+		private long _TotalTimeOffline;
+		
+		private long _TotalTimeUnavailable;
+		
+		private global::HeuristicLab.Services.Hive.DataAccess.SlaveState _SlaveState;
+		
+		private bool _IsAllowedToCalculate;
+		
+		private EntityRef<DimClient> _DimClient;
+		
+		private EntityRef<DimTime> _DimTime;
+		
+		private EntityRef<DimUser> _DimUser;
+		
+    #region Extensibility Method Definitions
+    partial void OnLoaded();
+    partial void OnValidate(System.Data.Linq.ChangeAction action);
+    partial void OnCreated();
+    partial void OnClientIdChanging(System.Guid value);
+    partial void OnClientIdChanged();
+    partial void OnTimeChanging(System.DateTime value);
+    partial void OnTimeChanged();
+    partial void OnUserIdChanging(System.Guid value);
+    partial void OnUserIdChanged();
+    partial void OnNumUsedCoresChanging(int value);
+    partial void OnNumUsedCoresChanged();
+    partial void OnNumTotalCoresChanging(int value);
+    partial void OnNumTotalCoresChanged();
+    partial void OnUsedMemoryChanging(int value);
+    partial void OnUsedMemoryChanged();
+    partial void OnTotalMemoryChanging(int value);
+    partial void OnTotalMemoryChanged();
+    partial void OnCpuUtilizationChanging(double value);
+    partial void OnCpuUtilizationChanged();
+    partial void OnIdleTimeChanging(long value);
+    partial void OnIdleTimeChanged();
+    partial void OnOfflineTimeChanging(long value);
+    partial void OnOfflineTimeChanged();
+    partial void OnUnavailableTimeChanging(long value);
+    partial void OnUnavailableTimeChanged();
+    partial void OnSlaveStateChanging(global::HeuristicLab.Services.Hive.DataAccess.SlaveState value);
+    partial void OnSlaveStateChanged();
+    partial void OnIsAllowedToCalculateChanging(bool value);
+    partial void OnIsAllowedToCalculateChanged();
+    #endregion
+		
+		public FactClientInfo()
+		{
+			this._DimClient = default(EntityRef<DimClient>);
+			this._DimTime = default(EntityRef<DimTime>);
+			this._DimUser = default(EntityRef<DimUser>);
+			OnCreated();
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ClientId", DbType="UniqueIdentifier NOT NULL", IsPrimaryKey=true)]
+		public System.Guid ClientId
+		{
+			get
+			{
+				return this._ClientId;
+			}
+			set
+			{
+				if ((this._ClientId != value))
+				{
+					if (this._DimClient.HasLoadedOrAssignedValue)
+					{
+						throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException();
+					}
+					this.OnClientIdChanging(value);
+					this.SendPropertyChanging();
+					this._ClientId = value;
+					this.SendPropertyChanged("ClientId");
+					this.OnClientIdChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Time", DbType="DateTime NOT NULL", IsPrimaryKey=true)]
+		public System.DateTime Time
+		{
+			get
+			{
+				return this._Time;
+			}
+			set
+			{
+				if ((this._Time != value))
+				{
+					if (this._DimTime.HasLoadedOrAssignedValue)
+					{
+						throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException();
+					}
+					this.OnTimeChanging(value);
+					this.SendPropertyChanging();
+					this._Time = value;
+					this.SendPropertyChanged("Time");
+					this.OnTimeChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_UserId", DbType="UniqueIdentifier NULL", IsPrimaryKey=true)]
+		public System.Guid UserId
+		{
+			get
+			{
+				return this._UserId;
+			}
+			set
+			{
+				if ((this._UserId != value))
+				{
+					if (this._DimUser.HasLoadedOrAssignedValue)
+					{
+						throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException();
+					}
+					this.OnUserIdChanging(value);
+					this.SendPropertyChanging();
+					this._UserId = value;
+					this.SendPropertyChanged("UserId");
+					this.OnUserIdChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_NumUsedCores", DbType="Int NOT NULL")]
+		public int NumUsedCores
+		{
+			get
+			{
+				return this._NumUsedCores;
+			}
+			set
+			{
+				if ((this._NumUsedCores != value))
+				{
+					this.OnNumUsedCoresChanging(value);
+					this.SendPropertyChanging();
+					this._NumUsedCores = value;
+					this.SendPropertyChanged("NumUsedCores");
+					this.OnNumUsedCoresChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_NumTotalCores", DbType="Int NOT NULL")]
+		public int NumTotalCores
+		{
+			get
+			{
+				return this._NumTotalCores;
+			}
+			set
+			{
+				if ((this._NumTotalCores != value))
+				{
+					this.OnNumTotalCoresChanging(value);
+					this.SendPropertyChanging();
+					this._NumTotalCores = value;
+					this.SendPropertyChanged("NumTotalCores");
+					this.OnNumTotalCoresChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_UsedMemory", DbType="Int NOT NULL")]
+		public int UsedMemory
+		{
+			get
+			{
+				return this._UsedMemory;
+			}
+			set
+			{
+				if ((this._UsedMemory != value))
+				{
+					this.OnUsedMemoryChanging(value);
+					this.SendPropertyChanging();
+					this._UsedMemory = value;
+					this.SendPropertyChanged("UsedMemory");
+					this.OnUsedMemoryChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_TotalMemory", DbType="Int NOT NULL")]
+		public int TotalMemory
+		{
+			get
+			{
+				return this._TotalMemory;
+			}
+			set
+			{
+				if ((this._TotalMemory != value))
+				{
+					this.OnTotalMemoryChanging(value);
+					this.SendPropertyChanging();
+					this._TotalMemory = value;
+					this.SendPropertyChanged("TotalMemory");
+					this.OnTotalMemoryChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_CpuUtilization", DbType="Float NOT NULL")]
+		public double CpuUtilization
+		{
+			get
+			{
+				return this._CpuUtilization;
+			}
+			set
+			{
+				if ((this._CpuUtilization != value))
+				{
+					this.OnCpuUtilizationChanging(value);
+					this.SendPropertyChanging();
+					this._CpuUtilization = value;
+					this.SendPropertyChanged("CpuUtilization");
+					this.OnCpuUtilizationChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_TotalTimeIdle", DbType="INT NOT NULL")]
+		public long IdleTime
+		{
+			get
+			{
+				return this._TotalTimeIdle;
+			}
+			set
+			{
+				if ((this._TotalTimeIdle != value))
+				{
+					this.OnIdleTimeChanging(value);
+					this.SendPropertyChanging();
+					this._TotalTimeIdle = value;
+					this.SendPropertyChanged("IdleTime");
+					this.OnIdleTimeChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_TotalTimeOffline", DbType="INT NOT NULL")]
+		public long OfflineTime
+		{
+			get
+			{
+				return this._TotalTimeOffline;
+			}
+			set
+			{
+				if ((this._TotalTimeOffline != value))
+				{
+					this.OnOfflineTimeChanging(value);
+					this.SendPropertyChanging();
+					this._TotalTimeOffline = value;
+					this.SendPropertyChanged("OfflineTime");
+					this.OnOfflineTimeChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_TotalTimeUnavailable", DbType="INT NOT NULL")]
+		public long UnavailableTime
+		{
+			get
+			{
+				return this._TotalTimeUnavailable;
+			}
+			set
+			{
+				if ((this._TotalTimeUnavailable != value))
+				{
+					this.OnUnavailableTimeChanging(value);
+					this.SendPropertyChanging();
+					this._TotalTimeUnavailable = value;
+					this.SendPropertyChanged("UnavailableTime");
+					this.OnUnavailableTimeChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_SlaveState", DbType="VarChar(15)", CanBeNull=false)]
+		public global::HeuristicLab.Services.Hive.DataAccess.SlaveState SlaveState
+		{
+			get
+			{
+				return this._SlaveState;
+			}
+			set
+			{
+				if ((this._SlaveState != value))
+				{
+					this.OnSlaveStateChanging(value);
+					this.SendPropertyChanging();
+					this._SlaveState = value;
+					this.SendPropertyChanged("SlaveState");
+					this.OnSlaveStateChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_IsAllowedToCalculate", DbType="BIT")]
+		public bool IsAllowedToCalculate
+		{
+			get
+			{
+				return this._IsAllowedToCalculate;
+			}
+			set
+			{
+				if ((this._IsAllowedToCalculate != value))
+				{
+					this.OnIsAllowedToCalculateChanging(value);
+					this.SendPropertyChanging();
+					this._IsAllowedToCalculate = value;
+					this.SendPropertyChanged("IsAllowedToCalculate");
+					this.OnIsAllowedToCalculateChanged();
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.AssociationAttribute(Name="DimClient_FactClientInfo", Storage="_DimClient", ThisKey="ClientId", OtherKey="Id", IsForeignKey=true)]
+		public DimClient DimClient
+		{
+			get
+			{
+				return this._DimClient.Entity;
+			}
+			set
+			{
+				DimClient previousValue = this._DimClient.Entity;
+				if (((previousValue != value) 
+							|| (this._DimClient.HasLoadedOrAssignedValue == false)))
+				{
+					this.SendPropertyChanging();
+					if ((previousValue != null))
+					{
+						this._DimClient.Entity = null;
+						previousValue.FactClientInfos.Remove(this);
+					}
+					this._DimClient.Entity = value;
+					if ((value != null))
+					{
+						value.FactClientInfos.Add(this);
+						this._ClientId = value.Id;
+					}
+					else
+					{
+						this._ClientId = default(System.Guid);
+					}
+					this.SendPropertyChanged("DimClient");
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.AssociationAttribute(Name="DimTime_FactClientInfo", Storage="_DimTime", ThisKey="Time", OtherKey="Time", IsForeignKey=true)]
+		public DimTime DimTime
+		{
+			get
+			{
+				return this._DimTime.Entity;
+			}
+			set
+			{
+				DimTime previousValue = this._DimTime.Entity;
+				if (((previousValue != value) 
+							|| (this._DimTime.HasLoadedOrAssignedValue == false)))
+				{
+					this.SendPropertyChanging();
+					if ((previousValue != null))
+					{
+						this._DimTime.Entity = null;
+						previousValue.FactClientInfos.Remove(this);
+					}
+					this._DimTime.Entity = value;
+					if ((value != null))
+					{
+						value.FactClientInfos.Add(this);
+						this._Time = value.Time;
+					}
+					else
+					{
+						this._Time = default(System.DateTime);
+					}
+					this.SendPropertyChanged("DimTime");
+				}
+			}
+		}
+		
+		[global::System.Data.Linq.Mapping.AssociationAttribute(Name="DimUser_FactClientInfo", Storage="_DimUser", ThisKey="UserId", OtherKey="UserId", IsForeignKey=true)]
+		public DimUser DimUser
+		{
+			get
+			{
+				return this._DimUser.Entity;
+			}
+			set
+			{
+				DimUser previousValue = this._DimUser.Entity;
+				if (((previousValue != value) 
+							|| (this._DimUser.HasLoadedOrAssignedValue == false)))
+				{
+					this.SendPropertyChanging();
+					if ((previousValue != null))
+					{
+						this._DimUser.Entity = null;
+						previousValue.FactClientInfos.Remove(this);
+					}
+					this._DimUser.Entity = value;
+					if ((value != null))
+					{
+						value.FactClientInfos.Add(this);
+						this._UserId = value.UserId;
+					}
+					else
+					{
+						this._UserId = default(System.Guid);
+					}
+					this.SendPropertyChanged("DimUser");
+				}
+			}
+		}
+		
+		public event PropertyChangingEventHandler PropertyChanging;
+		
+		public event PropertyChangedEventHandler PropertyChanged;
+		
+		protected virtual void SendPropertyChanging()
+		{
+			if ((this.PropertyChanging != null))
+			{
+				this.PropertyChanging(this, emptyChangingEventArgs);
+			}
+		}
+		
+		protected virtual void SendPropertyChanged(String propertyName)
+		{
+			if ((this.PropertyChanged != null))
+			{
+				this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
+			}
+		}
+	}
 }
 #pragma warning restore 1591
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/ITransactionManager.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/ITransactionManager.cs	(revision 12753)
+++ 	(revision )
@@ -1,29 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System;
-
-namespace HeuristicLab.Services.Hive.DataAccess {
-  public interface ITransactionManager {
-    void UseTransaction(Action call, bool repeatableRead = false, bool longRunning = false);
-    T UseTransaction<T>(Func<T> call, bool repeatableRead = false, bool longRunning = false);
-  }
-}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Interfaces/IGenericDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Interfaces/IGenericDao.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Interfaces/IGenericDao.cs	(revision 12878)
@@ -0,0 +1,45 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Interfaces {
+  public interface IGenericDao<in PK, T> where T : class {
+    T GetById(PK id);
+    IQueryable<T> Get(Expression<Func<T, bool>> predicate);
+    IQueryable<T> GetAll();
+    T Save(T entity);
+    IEnumerable<T> Save(params T[] entities);
+    IEnumerable<T> Save(IEnumerable<T> entities);
+    T SaveOrAttach(T entity);
+    IEnumerable<T> SaveOrAttach(params T[] entities);
+    IEnumerable<T> SaveOrAttach(IEnumerable<T> entities);
+    void Delete(PK id);
+    void Delete(IEnumerable<PK> ids);
+    void Delete(T entity);
+    void Delete(IEnumerable<T> entities);
+    bool Exists(T entity);
+    bool Exists(PK id);
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Interfaces/IHiveDao.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Interfaces/IHiveDao.cs	(revision 12753)
+++ 	(revision )
@@ -1,149 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Linq.Expressions;
-using HeuristicLab.Services.Hive.Common.DataTransfer;
-using DT = HeuristicLab.Services.Hive.Common.DataTransfer;
-
-namespace HeuristicLab.Services.Hive.DataAccess {
-  public interface IHiveDao {
-    #region Job Methods
-    DT.Job GetJob(Guid id);
-    IEnumerable<DT.Job> GetJobs(Expression<Func<Job, bool>> predicate);
-    Guid AddJob(DT.Job dto);
-    void UpdateJob(DT.Job dto);
-    void DeleteJob(Guid id);
-    IEnumerable<DT.Job> GetWaitingJobs(DT.Slave slave, int count);
-    IEnumerable<DT.Job> GetParentJobs(IEnumerable<Guid> resourceIds, int count, bool finished);
-    DT.Job UpdateJobState(Guid jobId, JobState jobState, Guid? slaveId, Guid? userId, string exception);
-    #endregion
-
-    #region JobData Methods
-    DT.JobData GetJobData(Guid id);
-    IEnumerable<DT.JobData> GetJobDatas(Expression<Func<JobData, bool>> predicate);
-    Guid AddJobData(DT.JobData dto);
-    void UpdateJobData(DT.JobData dto);
-    void DeleteJobData(Guid id);
-    #endregion
-
-    #region StateLog Methods
-    DT.StateLog GetStateLog(Guid id);
-    IEnumerable<DT.StateLog> GetStateLogs(Expression<Func<StateLog, bool>> predicate);
-    Guid AddStateLog(DT.StateLog dto);
-    void UpdateStateLog(DT.StateLog dto);
-    void DeleteStateLog(Guid id);
-    #endregion
-
-    #region HiveExperiment Methods
-    DT.HiveExperiment GetHiveExperiment(Guid id);
-    IEnumerable<DT.HiveExperiment> GetHiveExperiments(Expression<Func<HiveExperiment, bool>> predicate);
-    Guid AddHiveExperiment(DT.HiveExperiment dto);
-    void UpdateHiveExperiment(DT.HiveExperiment dto);
-    void DeleteHiveExperiment(Guid id);
-    #endregion
-
-    #region HiveExperimentPermission Methods
-    DT.HiveExperimentPermission GetHiveExperimentPermission(Guid hiveExperimentId, Guid grantedUserId);
-    IEnumerable<DT.HiveExperimentPermission> GetHiveExperimentPermissions(Expression<Func<HiveExperimentPermission, bool>> predicate);
-    void AddHiveExperimentPermission(DT.HiveExperimentPermission dto);
-    void UpdateHiveExperimentPermission(DT.HiveExperimentPermission dto);
-    void DeleteHiveExperimentPermission(Guid hiveExperimentId, Guid grantedUserId);
-    void SetHiveExperimentPermission(Guid hiveExperimentId, Guid grantedByUserId, Guid grantedUserId, Permission permission);
-    #endregion
-
-    #region Plugin Methods
-    DT.Plugin GetPlugin(Guid id);
-    IEnumerable<DT.Plugin> GetPlugins(Expression<Func<Plugin, bool>> predicate);
-    Guid AddPlugin(DT.Plugin dto);
-    void UpdatePlugin(DT.Plugin dto);
-    void DeletePlugin(Guid id);
-    #endregion
-
-    #region PluginData Methods
-    DT.PluginData GetPluginData(Guid id);
-    IEnumerable<DT.PluginData> GetPluginDatas(Expression<Func<PluginData, bool>> predicate);
-    Guid AddPluginData(DT.PluginData dto);
-    void UpdatePluginData(DT.PluginData dto);
-    void DeletePluginData(Guid id);
-    #endregion
-
-    #region Calendar Methods
-    #endregion
-
-    #region Slave Methods
-    DT.Slave GetSlave(Guid id);
-    IEnumerable<DT.Slave> GetSlaves(Expression<Func<Slave, bool>> predicate);
-    Guid AddSlave(DT.Slave dto);
-    void UpdateSlave(DT.Slave dto);
-    void DeleteSlave(Guid id);
-    #endregion
-
-    #region SlaveGroup Methods
-    DT.SlaveGroup GetSlaveGroup(Guid id);
-    IEnumerable<DT.SlaveGroup> GetSlaveGroups(Expression<Func<SlaveGroup, bool>> predicate);
-    Guid AddSlaveGroup(DT.SlaveGroup dto);
-    void UpdateSlaveGroup(DT.SlaveGroup dto);
-    void DeleteSlaveGroup(Guid id);
-    #endregion
-
-    #region Resource Methods
-    DT.Resource GetResource(Guid id);
-    IEnumerable<DT.Resource> GetResources(Expression<Func<Resource, bool>> predicate);
-    Guid AddResource(DT.Resource dto);
-    void UpdateResource(DT.Resource dto);
-    void DeleteResource(Guid id);
-    void AssignJobToResource(Guid jobId, Guid resourceId);
-    IEnumerable<DT.Resource> GetAssignedResources(Guid jobId);
-    IEnumerable<DT.Resource> GetParentResources(Guid resourceId);
-    IEnumerable<DT.Resource> GetChildResources(Guid resourceId);
-    IEnumerable<DT.Job> GetJobsByResourceId(Guid resourceId);
-    #endregion
-
-    #region Authorization Methods
-    Permission GetPermissionForJob(Guid jobId, Guid userId);
-    Permission GetPermissionForExperiment(Guid experimentId, Guid userId);
-    Guid GetExperimentForJob(Guid jobId);
-    #endregion
-
-    #region Lifecycle Methods
-    DateTime GetLastCleanup();
-    void SetLastCleanup(DateTime datetime);
-    #endregion
-
-    #region Downtime Methods
-    DT.Downtime GetDowntime(Guid id);
-    IEnumerable<DT.Downtime> GetDowntimes(Expression<Func<Downtime, bool>> predicate);
-    Guid AddDowntime(DT.Downtime dto);
-    void UpdateDowntime(DT.Downtime dto);
-    void DeleteDowntime(Guid id);
-    #endregion
-
-    #region Statistics Methods
-    DT.Statistics GetStatistic(Guid id);
-    IEnumerable<DT.Statistics> GetStatistics(Expression<Func<Statistics, bool>> predicate);
-    Guid AddStatistics(DT.Statistics dto);
-    void DeleteStatistics(Guid id);
-    List<DT.UserStatistics> GetUserStatistics();
-    #endregion
-  }
-}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Interfaces/IPersistenceManager.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Interfaces/IPersistenceManager.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Interfaces/IPersistenceManager.cs	(revision 12878)
@@ -0,0 +1,68 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Data.Linq;
+using HeuristicLab.Services.Hive.DataAccess.Daos;
+using HeuristicLab.Services.Hive.DataAccess.Daos.HiveStatistics;
+using HeuristicLab.Services.Hive.DataAccess.Data;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Interfaces {
+  public interface IPersistenceManager : IDisposable {
+    DataContext DataContext { get; }
+
+    #region Hive daos
+    AssignedResourceDao AssignedResourceDao { get; }
+    DowntimeDao DowntimeDao { get; }
+    JobDao JobDao { get; }
+    JobPermissionDao JobPermissionDao { get; }
+    LifecycleDao LifecycleDao { get; }
+    PluginDao PluginDao { get; }
+    PluginDataDao PluginDataDao { get; }
+    RequiredPluginDao RequiredPluginDao { get; }
+    ResourceDao ResourceDao { get; }
+    ResourcePermissionDao ResourcePermissionDao { get; }
+    SlaveDao SlaveDao { get; }
+    SlaveGroupDao SlaveGroupDao { get; }
+    StateLogDao StateLogDao { get; }
+    TaskDao TaskDao { get; }
+    TaskDataDao TaskDataDao { get; }
+    UserPriorityDao UserPriorityDao { get; }
+    #endregion
+
+    #region HiveStatistics daos
+    DimClientDao DimClientDao { get; }
+    DimJobDao DimJobDao { get; }
+    DimTimeDao DimTimeDao { get; }
+    DimUserDao DimUserDao { get; }
+    FactClientInfoDao FactClientInfoDao { get; }
+    FactTaskDao FactTaskDao { get; }
+    #endregion
+
+    #region Transaction management
+    void UseTransaction(Action call, bool repeatableRead = false, bool longRunning = false);
+    T UseTransaction<T>(Func<T> call, bool repeatableRead = false, bool longRunning = false);
+    #endregion
+
+    TableInformation GetTableInformation(string table);
+    void SubmitChanges();
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Manager/PersistenceManager.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Manager/PersistenceManager.cs	(revision 12878)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Manager/PersistenceManager.cs	(revision 12878)
@@ -0,0 +1,239 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Data.Linq;
+using System.Linq;
+using System.Transactions;
+using HeuristicLab.Services.Hive.DataAccess.Daos;
+using HeuristicLab.Services.Hive.DataAccess.Daos.HiveStatistics;
+using HeuristicLab.Services.Hive.DataAccess.Data;
+using HeuristicLab.Services.Hive.DataAccess.Interfaces;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Manager {
+  public class PersistenceManager : IPersistenceManager {
+    private readonly DataContext dataContext;
+    public DataContext DataContext {
+      get { return dataContext; }
+    }
+
+    #region Hive daos
+
+    private AssignedResourceDao assignedResourceDao;
+    public AssignedResourceDao AssignedResourceDao {
+      get { return assignedResourceDao ?? (assignedResourceDao = new AssignedResourceDao(dataContext)); }
+    }
+
+    private DowntimeDao downtimeDao;
+    public DowntimeDao DowntimeDao {
+      get { return downtimeDao ?? (downtimeDao = new DowntimeDao(dataContext)); }
+    }
+
+    private JobDao jobDao;
+    public JobDao JobDao {
+      get { return jobDao ?? (jobDao = new JobDao(dataContext)); }
+    }
+
+    private JobPermissionDao jobPermissionDao;
+    public JobPermissionDao JobPermissionDao {
+      get { return jobPermissionDao ?? (jobPermissionDao = new JobPermissionDao(dataContext)); }
+    }
+
+    private LifecycleDao lifecycleDao;
+    public LifecycleDao LifecycleDao {
+      get { return lifecycleDao ?? (lifecycleDao = new LifecycleDao(dataContext)); }
+    }
+
+    private PluginDao pluginDao;
+    public PluginDao PluginDao {
+      get { return pluginDao ?? (pluginDao = new PluginDao(dataContext)); }
+    }
+
+    private PluginDataDao pluginDataDao;
+    public PluginDataDao PluginDataDao {
+      get { return pluginDataDao ?? (pluginDataDao = new PluginDataDao(dataContext)); }
+    }
+
+    private RequiredPluginDao requiredPluginDao;
+    public RequiredPluginDao RequiredPluginDao {
+      get { return requiredPluginDao ?? (requiredPluginDao = new RequiredPluginDao(dataContext)); }
+    }
+
+    private ResourceDao resourceDao;
+    public ResourceDao ResourceDao {
+      get { return resourceDao ?? (resourceDao = new ResourceDao(dataContext)); }
+    }
+
+    private ResourcePermissionDao resourcePermissionDao;
+    public ResourcePermissionDao ResourcePermissionDao {
+      get { return resourcePermissionDao ?? (resourcePermissionDao = new ResourcePermissionDao(dataContext)); }
+    }
+
+    private SlaveDao slaveDao;
+    public SlaveDao SlaveDao {
+      get { return slaveDao ?? (slaveDao = new SlaveDao(dataContext)); }
+    }
+
+    private SlaveGroupDao slaveGroupDao;
+    public SlaveGroupDao SlaveGroupDao {
+      get { return slaveGroupDao ?? (slaveGroupDao = new SlaveGroupDao(dataContext)); }
+    }
+
+    private StateLogDao stateLogDao;
+    public StateLogDao StateLogDao {
+      get { return stateLogDao ?? (stateLogDao = new StateLogDao(dataContext)); }
+    }
+
+    private TaskDao taskDao;
+    public TaskDao TaskDao {
+      get { return taskDao ?? (taskDao = new TaskDao(dataContext)); }
+    }
+
+    private TaskDataDao taskDataDao;
+    public TaskDataDao TaskDataDao {
+      get { return taskDataDao ?? (taskDataDao = new TaskDataDao(dataContext)); }
+    }
+
+    private UserPriorityDao userPriorityDao;
+    public UserPriorityDao UserPriorityDao {
+      get { return userPriorityDao ?? (userPriorityDao = new UserPriorityDao(dataContext)); }
+    }
+    #endregion
+
+    #region HiveStatistics daos
+
+    private DimClientDao dimClientDao;
+    public DimClientDao DimClientDao {
+      get { return dimClientDao ?? (dimClientDao = new DimClientDao(dataContext)); }
+    }
+
+    private DimJobDao dimJobDao;
+    public DimJobDao DimJobDao {
+      get { return dimJobDao ?? (dimJobDao = new DimJobDao(dataContext)); }
+    }
+
+    private DimTimeDao dimTimeDao;
+    public DimTimeDao DimTimeDao {
+      get { return dimTimeDao ?? (dimTimeDao = new DimTimeDao(dataContext)); }
+    }
+
+    private DimUserDao dimUserDao;
+    public DimUserDao DimUserDao {
+      get { return dimUserDao ?? (dimUserDao = new DimUserDao(dataContext)); }
+    }
+
+    private FactClientInfoDao factClientInfoDao;
+    public FactClientInfoDao FactClientInfoDao {
+      get { return factClientInfoDao ?? (factClientInfoDao = new FactClientInfoDao(dataContext)); }
+    }
+
+    private FactTaskDao factTaskDao;
+    public FactTaskDao FactTaskDao {
+      get { return factTaskDao ?? (factTaskDao = new FactTaskDao(dataContext)); }
+    }
+    #endregion
+
+    public PersistenceManager(bool longRunning = false) {
+      var context = new HiveDataContext(Settings.Default.HeuristicLab_Hive_LinqConnectionString);
+      if (longRunning) context.CommandTimeout = (int)Settings.Default.LongRunningDatabaseCommandTimeout.TotalSeconds;
+      dataContext = context;
+    }
+
+    public PersistenceManager(DataContext dataContext) {
+      this.dataContext = dataContext;
+    }
+
+    #region Transaction management
+    public void UseTransaction(Action call, bool repeatableRead = false, bool longRunning = false) {
+      UseTransaction<object>(() => {
+        call();
+        return null;
+      });
+    }
+
+    public T UseTransaction<T>(Func<T> call, bool repeatableRead = false, bool longRunning = false) {
+      int n = 10;
+      while (n > 0) {
+        TransactionScope transaction = CreateTransaction(repeatableRead, longRunning);
+        try {
+          T result = call();
+          transaction.Complete();
+          return result;
+        }
+        catch (System.Data.SqlClient.SqlException e) {
+          n--; // probably deadlock situation, let it roll back and repeat the transaction n times
+          LogFactory.GetLogger(typeof(TransactionManager).Namespace).Log(string.Format("Exception occured, repeating transaction {0} more times. Details: {1}", n, e.ToString()));
+          if (n <= 0) throw;
+        }
+        finally {
+          transaction.Dispose();
+        }
+      }
+      throw new Exception("Transaction couldn't be completed.");
+    }
+
+    private static TransactionScope CreateTransaction(bool repeatableRead, bool longRunning) {
+      var options = new TransactionOptions {
+        IsolationLevel = repeatableRead ? IsolationLevel.RepeatableRead : IsolationLevel.ReadUncommitted
+      };
+      if (longRunning) {
+        options.Timeout = Settings.Default.LongRunningDatabaseCommandTimeout;
+      }
+      return new TransactionScope(TransactionScopeOption.Required, options);
+    }
+    #endregion
+
+    public TableInformation GetTableInformation(string table) {
+      string query = string.Format("sp_spaceused '{0}', @updateusage='true'", table);
+      var result = dataContext.ExecuteQuery<SqlServerTableInformation>(query).FirstOrDefault();
+      if (result == null) return null;
+      return new TableInformation {
+        Name = result.Name,
+        Rows = int.Parse(result.Rows.Remove(result.Rows.IndexOf(' '))),
+        Reserved = int.Parse(result.Reserved.Remove(result.Reserved.IndexOf(' '))),
+        Data = int.Parse(result.Data.Remove(result.Data.IndexOf(' '))),
+        IndexSize = int.Parse(result.Index_Size.Remove(result.Index_Size.IndexOf(' '))),
+        Unused = int.Parse(result.Unused.Remove(result.Unused.IndexOf(' ')))
+      };
+    }
+
+    public void SubmitChanges() {
+      if (dataContext != null) {
+        dataContext.SubmitChanges();
+      }
+    }
+
+    public void Dispose() {
+      if (dataContext != null) {
+        dataContext.Dispose();
+      }
+    }
+
+    private class SqlServerTableInformation {
+      public string Name { get; set; }
+      public string Rows { get; set; }
+      public string Reserved { get; set; }
+      public string Data { get; set; }
+      public string Index_Size { get; set; } // naming of sp_spaceused...
+      public string Unused { get; set; }
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/SQL Scripts/Initialize Hive Database.sql
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/SQL Scripts/Initialize Hive Database.sql	(revision 12753)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/SQL Scripts/Initialize Hive Database.sql	(revision 12878)
@@ -1,4 +1,21 @@
-﻿USE [HeuristicLab.Hive-3.3]
-/* create and initialize hive database tables */
+﻿/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+USE [HeuristicLab.Hive-3.3]
 
 EXEC sp_configure filestream_access_level, 2
@@ -131,36 +148,4 @@
   [DateEnqueued] DateTime NOT NULL,
   CONSTRAINT [PK_UserPriority] PRIMARY KEY ([UserId])
-  )
-CREATE TABLE [DeletedJobStatistics](
-  [UserId] UniqueIdentifier NOT NULL,
-  [ExecutionTimeS] float NOT NULL,
-  [ExecutionTimeSFinishedJobs] float NOT NULL,
-  [StartToEndTimeS] float NOT NULL,
-  [DeletedJobStatisticsId] UniqueIdentifier NOT NULL,
-  CONSTRAINT [PK_DeletedJobStatistics] PRIMARY KEY ([DeletedJobStatisticsId])
-  )
-CREATE TABLE [UserStatistics](
-  [StatisticsId] UniqueIdentifier NOT NULL,
-  [UserId] UniqueIdentifier NOT NULL,
-  [ExecutionTimeMs] float NOT NULL,
-  [UsedCores] Int NOT NULL,
-  [ExecutionTimeMsFinishedJobs] float NOT NULL,
-  [StartToEndTimeMs] float NOT NULL,
-  CONSTRAINT [PK_UserStatistics] PRIMARY KEY ([StatisticsId], [UserId])
-  )
-CREATE TABLE [SlaveStatistics](
-  [StatisticsId] UniqueIdentifier NOT NULL,
-  [SlaveId] UniqueIdentifier NOT NULL,
-  [Cores] Int NOT NULL,
-  [FreeCores] Int NOT NULL,
-  [CpuUtilization] float NOT NULL,
-  [Memory] Int NOT NULL,
-  [FreeMemory] Int NOT NULL,
-  CONSTRAINT [PK_SlaveStatistics] PRIMARY KEY ([StatisticsId], [SlaveId])
-  )
-CREATE TABLE [Statistics](
-  [StatisticsId] UniqueIdentifier NOT NULL,
-  [Timestamp] DateTime NOT NULL,
-  CONSTRAINT [PK_Statistics] PRIMARY KEY ([StatisticsId])
   )
 ALTER TABLE [dbo].[AssignedResources]
@@ -192,6 +177,87 @@
 ALTER TABLE [dbo].[JobPermission]
   ADD CONSTRAINT [Job_JobPermission] FOREIGN KEY ([JobId]) REFERENCES [dbo].[Job]([JobId])
-ALTER TABLE [UserStatistics]
-  ADD CONSTRAINT [Statistics_UserStatistics] FOREIGN KEY ([StatisticsId]) REFERENCES [Statistics]([StatisticsId])
-ALTER TABLE [SlaveStatistics]
-  ADD CONSTRAINT [Statistics_SlaveStatistics] FOREIGN KEY ([StatisticsId]) REFERENCES [Statistics]([StatisticsId])
+
+GO
+CREATE SCHEMA [statistics]
+GO
+
+CREATE TABLE [statistics].[DimTime] (
+    [Time]   DATETIME NOT NULL,
+    [Minute] DATETIME NOT NULL,
+    [Hour]   DATETIME NOT NULL,
+    [Day]    DATE     NOT NULL,
+    [Month]  DATE     NOT NULL,
+    [Year]   DATE     NOT NULL,
+    CONSTRAINT [PK_DimTime] PRIMARY KEY CLUSTERED ([Time] ASC)
+);
+CREATE TABLE [statistics].[DimClient] (
+    [Id]               UNIQUEIDENTIFIER CONSTRAINT [DF_DimClient_Id] DEFAULT (newsequentialid()) NOT NULL,
+    [Name]             VARCHAR (MAX)    NOT NULL,
+    [ResourceId]       UNIQUEIDENTIFIER NOT NULL,
+    [ExpirationTime]   DATETIME         NULL,
+    [ResourceGroupId]  UNIQUEIDENTIFIER NULL,
+    [ResourceGroup2Id] UNIQUEIDENTIFIER NULL,
+    [GroupName]        VARCHAR (MAX)    NULL,
+    [GroupName2]       VARCHAR (MAX)    NULL,
+    CONSTRAINT [PK_DimClient] PRIMARY KEY CLUSTERED ([Id] ASC)
+);
+CREATE TABLE [statistics].[DimJob] (
+    [JobId]          UNIQUEIDENTIFIER NOT NULL,
+    [UserId]         UNIQUEIDENTIFIER NOT NULL,
+    [JobName]        VARCHAR (MAX)    NOT NULL,
+    [UserName]       VARCHAR (MAX)    NOT NULL,
+    [DateCreated]    DATETIME		  NOT NULL,
+    [TotalTasks]     INT              NOT NULL,
+    [CompletedTasks] INT              NOT NULL,
+    [DateCompleted]  DATETIME		  NULL,
+    CONSTRAINT [PK_DimJob] PRIMARY KEY CLUSTERED ([JobId] ASC)
+);
+CREATE TABLE [statistics].[DimUser] (
+    [UserId] UNIQUEIDENTIFIER NOT NULL,
+    [Name]   VARCHAR (MAX)    NOT NULL,
+    CONSTRAINT [PK_DimUser] PRIMARY KEY CLUSTERED ([UserId] ASC)
+);
+CREATE TABLE [statistics].[FactClientInfo] (
+    [ClientId]             UNIQUEIDENTIFIER NOT NULL,
+    [Time]                 DATETIME         NOT NULL,
+    [UserId]               UNIQUEIDENTIFIER NOT NULL,
+    [NumUsedCores]         INT              NOT NULL,
+    [NumTotalCores]        INT              NOT NULL,
+    [UsedMemory]           INT              NOT NULL,
+    [TotalMemory]          INT              NOT NULL,
+    [CpuUtilization]       FLOAT (53)       NOT NULL,
+    [SlaveState]           VarChar(15)      NOT NULL,
+    [IdleTime]             INT              NOT NULL,
+    [OfflineTime]          INT              NOT NULL,
+    [UnavailableTime]      INT              NOT NULL,
+    [IsAllowedToCalculate] BIT              NOT NULL,
+    CONSTRAINT [PK_FactClientInfo] PRIMARY KEY CLUSTERED ([ClientId] ASC, [Time] ASC, [UserId] ASC),
+    CONSTRAINT [FK_FactClientInfo_DimTime] FOREIGN KEY ([Time]) REFERENCES [statistics].[DimTime] ([Time]),
+    CONSTRAINT [FK_FactClientInfo_DimClient] FOREIGN KEY ([ClientId]) REFERENCES [statistics].[DimClient] ([Id]),
+    CONSTRAINT [FK_FactClientInfo_DimUser] FOREIGN KEY ([UserId]) REFERENCES [statistics].[DimUser] ([UserId])
+);
+CREATE TABLE [statistics].[FactTask] (
+  [TaskId]             UNIQUEIDENTIFIER NOT NULL,
+  [CalculatingTime]    INT              NOT NULL,
+  [WaitingTime]        INT              NOT NULL,
+  [TransferTime]       INT              NOT NULL,
+  [NumCalculationRuns] INT              NOT NULL,
+  [NumRetries]         INT              NOT NULL,
+  [CoresRequired]      INT              NOT NULL,
+  [MemoryRequired]     INT              NOT NULL,
+  [Priority]           INT              NOT NULL,
+  [LastClientId]       UNIQUEIDENTIFIER NULL,
+  [JobId]		       UNIQUEIDENTIFIER NOT NULL,
+  [StartTime]          DATETIME         NULL,
+  [EndTime]            DATETIME         NULL,
+  [TaskState]          VARCHAR (30)     NOT NULL,
+  [Exception]          VARCHAR (MAX)    NULL,
+  [InitialWaitingTime] INT              NULL,
+  CONSTRAINT [PK_FactTask] PRIMARY KEY CLUSTERED ([TaskId] ASC),
+  CONSTRAINT [FK_FactTask_DimClient] FOREIGN KEY ([LastClientId]) REFERENCES [statistics].[DimClient] ([Id]),
+  CONSTRAINT [FK_FactTask_DimJob] FOREIGN KEY ([JobId]) REFERENCES [statistics].[DimJob] ([JobId])
+);
+
+/* dummy for nullable userIds in FactClientInfo */
+INSERT INTO [statistics].[DimUser] ([UserId], [Name])
+VALUES ('00000000-0000-0000-0000-000000000000', 'NULL');
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/SQL Scripts/Migrate to Filestream.sql
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/SQL Scripts/Migrate to Filestream.sql	(revision 12753)
+++ 	(revision )
@@ -1,79 +1,0 @@
-/* Upgrade script from HeuristicLab Hive 3.3.8 to 3.3.9 */
-
-USE [HeuristicLab.Hive-3.3]
-
-EXEC sp_configure filestream_access_level, 2
-GO
-RECONFIGURE
-GO 
-
-/**********************************************************/
-
-/* Move old Task Data */
-
-CREATE TABLE [dbo].[TaskDataTemp](
-  [TaskId] UniqueIdentifier RowGuidCol NOT NULL,
-  [Data] VarBinary(MAX) Filestream NOT NULL,
-  [LastUpdate] DateTime NOT NULL,
-  CONSTRAINT [PK_dbo.TaskDataTemp] PRIMARY KEY ([TaskId])
-)
-
-INSERT INTO dbo.TaskDataTemp (TaskId, Data, LastUpdate)
-SELECT TaskId, Data, LastUpdate
-FROM dbo.TaskData
-
-DELETE FROM dbo.TaskData
-
-/* Alter TaskId and Data Column */
-
-ALTER TABLE dbo.TaskData
-ALTER COLUMN [TaskId] ADD RowGuidCol
-
-ALTER TABLE dbo.TaskData
-DROP COLUMN Data
-
-ALTER TABLE dbo.TaskData
-ADD [Data] VarBinary(MAX) Filestream NOT NULL
-
-/* Insert data */
-
-INSERT INTO dbo.TaskData (TaskId, Data, LastUpdate)
-SELECT TaskId, Data, LastUpdate
-FROM dbo.TaskDataTemp
-
-DROP TABLE dbo.TaskDataTemp
-
-
-/**********************************************************/
-
-/* Move old Plugin Data */
-
-CREATE TABLE [dbo].[PluginDataTemp](
-  [PluginDataId] UniqueIdentifier RowGuidCol NOT NULL,
-  [PluginId] UniqueIdentifier NOT NULL,
-  [Data] VarBinary(MAX) FileStream NOT NULL,
-  [FileName] VarChar(MAX) NOT NULL,
-  CONSTRAINT [PK_dbo.PluginDataTemp] PRIMARY KEY ([PluginDataId])
-)
-
-INSERT INTO dbo.PluginDataTemp (PluginDataId, PluginId, Data, [FileName])
-SELECT PluginDataId, PluginId, Data, [FileName]
-FROM dbo.PluginData
-
-DELETE FROM dbo.PluginData
-
-/* Alter Data Column */
-
-ALTER TABLE dbo.PluginData
-DROP COLUMN Data
-
-ALTER TABLE dbo.PluginData
-ADD [Data] VarBinary(MAX) Filestream NOT NULL
-
-/* Insert data */
-
-INSERT INTO dbo.PluginData (PluginDataId, PluginId, Data, [FileName])
-SELECT PluginDataId, PluginId, Data, [FileName]
-FROM dbo.PluginDataTemp
-
-DROP TABLE dbo.PluginDataTemp
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/SQL Scripts/Prepare Hive Database.sql
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/SQL Scripts/Prepare Hive Database.sql	(revision 12753)
+++ trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/SQL Scripts/Prepare Hive Database.sql	(revision 12878)
@@ -1,10 +1,23 @@
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* this script is supposed to be executed after the plain DB is generated by the linq-to-sql schema */
 USE [HeuristicLab.Hive-3.3]
-/* this script is supposed to be executed after the plain DB is generated by the linq-to-sql schema */
-/* adds default values */
-/* creates delete and update cascades */
-/* creates indices */
-/* creates views */
-/* creates triggers */
-
 
 ALTER TABLE [dbo].[AssignedResources]  DROP  CONSTRAINT [Task_AssignedResource]
@@ -93,78 +106,21 @@
 GO
 
-ALTER TABLE [dbo].[Statistics] ALTER COLUMN StatisticsId ADD ROWGUIDCOL;
-ALTER TABLE [dbo].[Statistics] WITH NOCHECK ADD CONSTRAINT [DF_Statistics_StatisticsId] DEFAULT (NEWSEQUENTIALID()) FOR StatisticsId;
-GO
-
-ALTER TABLE [dbo].[DeletedJobStatistics] ALTER COLUMN DeletedJobStatisticsId ADD ROWGUIDCOL;
-ALTER TABLE [dbo].[DeletedJobStatistics] WITH NOCHECK ADD CONSTRAINT [DF_DeletedJobStatistics_DeletedJobStatisticsId] DEFAULT (NEWSEQUENTIALID()) FOR DeletedJobStatisticsId;
-GO
-
-ALTER TABLE [dbo].[SlaveStatistics]  DROP  CONSTRAINT [Statistics_SlaveStatistics]
-ALTER TABLE [dbo].[SlaveStatistics]  WITH CHECK ADD  CONSTRAINT [Statistics_SlaveStatistics] FOREIGN KEY([StatisticsId])
-REFERENCES [dbo].[Statistics] ([StatisticsId])
-ON UPDATE CASCADE
-ON DELETE CASCADE
-GO
-
-ALTER TABLE [dbo].[UserStatistics]  DROP  CONSTRAINT [Statistics_UserStatistics]
-ALTER TABLE [dbo].[UserStatistics]  WITH CHECK ADD  CONSTRAINT [Statistics_UserStatistics] FOREIGN KEY([StatisticsId])
-REFERENCES [dbo].[Statistics] ([StatisticsId])
-ON UPDATE CASCADE
-ON DELETE CASCADE
-GO
-
 /* create indices */
 CREATE INDEX Index_RequiredPlugins_TaskId ON RequiredPlugins(TaskId);
 GO
 
-/* views */
--- =============================================
--- Author:		cneumuel
--- Description:	Returns the first StateLog entry for each job
--- =============================================
-CREATE VIEW [dbo].[view_FirstState]
-AS
-SELECT     sl.TaskId, sl.DateTime, sl.State
-FROM         dbo.StateLog AS sl INNER JOIN
-                          (SELECT     TaskId, MIN(DateTime) AS DateTime
-                            FROM          dbo.StateLog
-                            GROUP BY TaskId) AS minDate ON sl.DateTime = minDate.DateTime AND sl.TaskId = minDate.TaskId
-
+-- speed up joins between Job and Task
+CREATE NONCLUSTERED INDEX [TaskJobIdIndex]
+ON [dbo].[Task] ([JobId])
+INCLUDE ([TaskId],[TaskState],[ExecutionTimeMs],[LastHeartbeat],[ParentTaskId],[Priority],[CoresNeeded],[MemoryNeeded],[IsParentTask],[FinishWhenChildJobsFinished],[Command],[IsPrivileged])
 GO
 
--- =============================================
--- Author:		cneumuel
--- Description:	Returns the last StateLog entry for each job
--- =============================================
-CREATE VIEW [dbo].[view_LastState]
-AS
-SELECT     sl.TaskId, sl.DateTime, sl.State
-FROM         dbo.StateLog AS sl INNER JOIN
-                          (SELECT     TaskId, MAX(DateTime) AS DateTime
-                            FROM          dbo.StateLog
-                            GROUP BY TaskId) AS minDate ON sl.DateTime = minDate.DateTime AND sl.TaskId = minDate.TaskId
+-- this is an index to speed up the GetWaitingTasks() method 
+CREATE NONCLUSTERED INDEX [TaskGetWaitingTasksIndex]
+ON [dbo].[Task] ([TaskState],[IsParentTask],[FinishWhenChildJobsFinished],[CoresNeeded],[MemoryNeeded])
+INCLUDE ([TaskId],[ExecutionTimeMs],[LastHeartbeat],[ParentTaskId],[Priority],[Command],[JobId],[IsPrivileged])
 GO
 
--- =============================================
--- Author:		cneumuel
--- Description:	returns aggregates statistic information for every minute
--- =============================================
-CREATE VIEW [dbo].[view_Statistics]
-AS
-SELECT  CONVERT(VARCHAR(19), MIN(s.Timestamp), 120) AS DateTime, SUM(ss.Cores) AS Cores, SUM(ss.FreeCores) AS FreeCores, 
-        AVG(ss.CpuUtilization) AS CpuUtilization, SUM(ss.Memory) AS Memory, SUM(ss.FreeMemory) AS FreeMemory, x.exSum AS ExecutionTimeHours, 
-        x.exFinishedSum AS ExecutionTimeFinished, x.exStartToEndSum AS StartToEndTimeFinished
-FROM         dbo.SlaveStatistics AS ss INNER JOIN
-                      dbo.[Statistics] AS s ON ss.StatisticsId = s.StatisticsId INNER JOIN
-                      dbo.Resource AS r ON ss.SlaveId = r.ResourceId INNER JOIN
-                          (SELECT     StatisticsId, SUM(ExecutionTimeMs) / 1000 / 60 / 60 AS exSum, SUM(ExecutionTimeMsFinishedJobs) / 1000 / 60 / 60 AS exFinishedSum, 
-                                                   SUM(StartToEndTimeMs) / 1000 / 60 / 60 AS exStartToEndSum
-                            FROM          dbo.UserStatistics AS us
-                            GROUP BY StatisticsId) AS x ON s.StatisticsId = x.StatisticsId
-GROUP BY s.StatisticsId, x.exSum, x.exFinishedSum, x.exStartToEndSum
 
-/* triggers */
-GO
 /****** Object:  Trigger [dbo].[tr_JobDeleteCascade]    Script Date: 04/19/2011 16:31:53 ******/
 SET ANSI_NULLS ON
@@ -182,6 +138,6 @@
 CREATE TRIGGER [dbo].[tr_JobDeleteCascade] ON [dbo].[Job] INSTEAD OF DELETE AS 
 BEGIN
-	DELETE Task FROM deleted, Task WHERE deleted.JobId = Task.JobId
-	DELETE Job FROM deleted, Job WHERE deleted.JobId = Job.JobId
+    DELETE Task FROM deleted, Task WHERE deleted.JobId = Task.JobId
+    DELETE Job FROM deleted, Job WHERE deleted.JobId = Job.JobId
 END
 GO
@@ -191,74 +147,32 @@
 -- Create date: 11.11.2010
 -- Description:	Recursively deletes all child-jobs of a job when it is deleted. (Source: http://devio.wordpress.com/2008/05/23/recursive-delete-in-sql-server/)
--- =============================================
+-- =============================================DeletedJobStatistics
 CREATE TRIGGER [dbo].[tr_TaskDeleteCascade] ON [dbo].[Task] INSTEAD OF DELETE AS 
 BEGIN
-	-- add statistics
-	INSERT INTO dbo.DeletedJobStatistics (UserId, ExecutionTimeS, ExecutionTimeSFinishedJobs, StartToEndTimeS)
-	SELECT 
-		he.OwnerUserId AS UserId, 
-		ROUND(SUM(j.ExecutionTimeMs) / 1000, 0) AS ExecutionTimeS,  
-		ROUND(ISNULL(SUM(CASE ls.State WHEN 'Finished' THEN j.ExecutionTimeMs END), 0) / 1000, 0) AS ExecutionTimeSFinishedJobs,
-		ISNULL(SUM(CASE ls.State WHEN 'Finished' THEN DATEDIFF(s, fs.DateTime, ls.DateTime) ELSE 0 END), 0) AS StartToEndTimeS
-	FROM 
-		deleted j, 
-		Job he, 
-		view_FirstState fs, 
-		view_LastState ls
-	WHERE 
-		he.JobId = j.JobId AND 
-		fs.TaskId = j.TaskId AND 
-		ls.TaskId = j.TaskId
-	GROUP BY he.OwnerUserId
-
-	-- recursively delete jobs
-	CREATE TABLE #Table( 
-		TaskId uniqueidentifier 
-	)
-	INSERT INTO #Table (TaskId)
-	SELECT TaskId FROM deleted
-	
-	DECLARE @c INT
-	SET @c = 0
-	
-	WHILE @c <> (SELECT COUNT(TaskId) FROM #Table) BEGIN
-		SELECT @c = COUNT(TaskId) FROM #Table
-		
-		INSERT INTO #Table (TaskId)
-			SELECT Task.TaskId
-			FROM Task
-			LEFT OUTER JOIN #Table ON Task.TaskId = #Table.TaskId
-			WHERE Task.ParentTaskId IN (SELECT TaskId FROM #Table)
-				AND #Table.TaskId IS NULL
-	END
-	
-	DELETE TaskData FROM TaskData INNER JOIN #Table ON TaskData.TaskId = #Table.TaskId
-	DELETE Task FROM Task INNER JOIN #Table ON Task.TaskId = #Table.TaskId
+    -- recursively delete jobs
+    CREATE TABLE #Table( 
+        TaskId uniqueidentifier 
+    )
+    INSERT INTO #Table (TaskId)
+    SELECT TaskId FROM deleted
+    
+    DECLARE @c INT
+    SET @c = 0
+    
+    WHILE @c <> (SELECT COUNT(TaskId) FROM #Table) BEGIN
+        SELECT @c = COUNT(TaskId) FROM #Table
+        
+        INSERT INTO #Table (TaskId)
+            SELECT Task.TaskId
+            FROM Task
+            LEFT OUTER JOIN #Table ON Task.TaskId = #Table.TaskId
+            WHERE Task.ParentTaskId IN (SELECT TaskId FROM #Table)
+                AND #Table.TaskId IS NULL
+    END
+    
+    DELETE TaskData FROM TaskData INNER JOIN #Table ON TaskData.TaskId = #Table.TaskId
+    DELETE Task FROM Task INNER JOIN #Table ON Task.TaskId = #Table.TaskId
 END
 GO
 
 
-CREATE TRIGGER [dbo].[tr_StatisticsDeleteCascade] ON [dbo].[Statistics] INSTEAD OF DELETE AS 
-BEGIN
-	DELETE SlaveStatistics FROM deleted, SlaveStatistics WHERE deleted.StatisticsId = SlaveStatistics.StatisticsId
-	-- should also remove UserStatistics here 
-	DELETE [Statistics] FROM deleted, [Statistics] WHERE deleted.StatisticsId = [Statistics].StatisticsId
-END
-GO
-
-
--- ============================================================
--- Description:	Create indices to speed up execution of queries
--- ============================================================
-
--- speed up joins between Job and Task
-CREATE NONCLUSTERED INDEX [TaskJobIdIndex]
-ON [dbo].[Task] ([JobId])
-INCLUDE ([TaskId],[TaskState],[ExecutionTimeMs],[LastHeartbeat],[ParentTaskId],[Priority],[CoresNeeded],[MemoryNeeded],[IsParentTask],[FinishWhenChildJobsFinished],[Command],[IsPrivileged])
-GO
-
--- this is an index to speed up the GetWaitingTasks() method 
-CREATE NONCLUSTERED INDEX [TaskGetWaitingTasksIndex]
-ON [dbo].[Task] ([TaskState],[IsParentTask],[FinishWhenChildJobsFinished],[CoresNeeded],[MemoryNeeded])
-INCLUDE ([TaskId],[ExecutionTimeMs],[LastHeartbeat],[ParentTaskId],[Priority],[Command],[JobId],[IsPrivileged])
-GO
Index: trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/TransactionManager.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.Hive.DataAccess/3.3/TransactionManager.cs	(revision 12753)
+++ 	(revision )
@@ -1,82 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System;
-using System.Transactions;
-
-namespace HeuristicLab.Services.Hive.DataAccess {
-  public class TransactionManager : ITransactionManager {
-    public void UseTransaction(Action call, bool repeatableRead = false, bool longRunning = false) {
-      int n = 10;
-      while (n > 0) {
-        TransactionScope transaction = CreateTransaction(repeatableRead, longRunning);
-        try {
-          call();
-          transaction.Complete();
-          n = 0;
-        }
-        catch (System.Data.SqlClient.SqlException e) {
-          n--; // probably deadlock situation, let it roll back and repeat the transaction n times
-          LogFactory.GetLogger(typeof(TransactionManager).Namespace).Log(string.Format("Exception occured, repeating transaction {0} more times. Details: {1}", n, e.ToString()));
-          if (n <= 0) throw;
-        }
-        finally {
-          transaction.Dispose();
-        }
-      }
-    }
-
-    public T UseTransaction<T>(Func<T> call, bool repeatableRead = false, bool longRunning = false) {
-      int n = 10;
-      while (n > 0) {
-        TransactionScope transaction = CreateTransaction(repeatableRead, longRunning);
-        try {
-          T result = call();
-          transaction.Complete();
-          n = 0;
-          return result;
-        }
-        catch (System.Data.SqlClient.SqlException e) {
-          n--; // probably deadlock situation, let it roll back and repeat the transaction n times
-          LogFactory.GetLogger(typeof(TransactionManager).Namespace).Log(string.Format("Exception occured, repeating transaction {0} more times. Details: {1}", n, e.ToString()));
-          if (n <= 0) throw;
-        }
-        finally {
-          transaction.Dispose();
-        }
-      }
-      throw new Exception("This code should not be reached");
-    }
-
-    private TransactionScope CreateTransaction(bool repeatableRead, bool longRunning) {
-      var options = new TransactionOptions();
-      if (repeatableRead)
-        options.IsolationLevel = IsolationLevel.RepeatableRead;
-      else
-        options.IsolationLevel = IsolationLevel.ReadUncommitted;
-
-      if (longRunning)
-        options.Timeout = Settings.Default.LongRunningDatabaseCommandTimeout;
-
-      return new TransactionScope(TransactionScopeOption.Required, options);
-    }
-  }
-}
