Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Convert.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Convert.cs	(revision 12467)
+++ 	(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: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/AssignedResourceDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/AssignedResourceDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/AssignedResourceDao.cs	(revision 12468)
@@ -0,0 +1,33 @@
+﻿#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;
+
+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();
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/DowntimeDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/DowntimeDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/DowntimeDao.cs	(revision 12468)
@@ -0,0 +1,34 @@
+﻿#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 Table.SingleOrDefault(x => x.DowntimeId == id);
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/GenericDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/GenericDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/GenericDao.cs	(revision 12468)
@@ -0,0 +1,115 @@
+﻿#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(PK id) {
+      return GetById(id) != null;
+    }
+    #endregion
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimClientDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimClientDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimClientDao.cs	(revision 12468)
@@ -0,0 +1,52 @@
+﻿#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> {
+    private const string UpdateExpirationTimeQuery =
+      @"UPDATE [statistics].[DimClient] 
+           SET ExpirationTime = {0} 
+         WHERE Id IN ({1});";
+
+    public DimClientDao(DataContext dataContext) : base(dataContext) { }
+
+    public override DimClient GetById(Guid id) {
+      return Table.SingleOrDefault(x => x.Id == id);
+    }
+    public IQueryable<DimClient> GetRecentlyAddedClients() {
+      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;
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimJobDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimJobDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimJobDao.cs	(revision 12468)
@@ -0,0 +1,34 @@
+﻿#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 Table.SingleOrDefault(x => x.JobId == id);
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimTimeDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimTimeDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimTimeDao.cs	(revision 12468)
@@ -0,0 +1,37 @@
+﻿#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 Table.SingleOrDefault(x => x.Time == id);
+    }
+    public DimTime GetLastEntry() {
+      return Table.OrderByDescending(x => x.Time).FirstOrDefault();
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimUserDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimUserDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimUserDao.cs	(revision 12468)
@@ -0,0 +1,34 @@
+﻿#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 Table.SingleOrDefault(x => x.UserId == id);
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/FactClientInfoDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/FactClientInfoDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/FactClientInfoDao.cs	(revision 12468)
@@ -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.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),
+             };
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/FactTaskDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/FactTaskDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/FactTaskDao.cs	(revision 12468)
@@ -0,0 +1,51 @@
+﻿#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 const string BatchDeleteQuery =
+      @"DELETE FROM [statistics].[FactTask]
+         WHERE TaskId IN ({0});";
+    public FactTaskDao(DataContext dataContext) : base(dataContext) { }
+
+    public override FactTask GetById(Guid id) {
+      return Table.SingleOrDefault(x => x.TaskId == id);
+    }
+
+    public IQueryable<FactTask> GetNotFinishedTasks() {
+      return Table.Where(x => x.EndTime == null);
+    }
+
+    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);
+      }
+    }
+
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/JobDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/JobDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/JobDao.cs	(revision 12468)
@@ -0,0 +1,34 @@
+﻿#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 Table.SingleOrDefault(x => x.JobId == id);
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/JobPermissionDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/JobPermissionDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/JobPermissionDao.cs	(revision 12468)
@@ -0,0 +1,33 @@
+﻿#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;
+
+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();
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/LifecycleDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/LifecycleDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/LifecycleDao.cs	(revision 12468)
@@ -0,0 +1,33 @@
+﻿#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.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 Table.SingleOrDefault(x => x.LifecycleId == id);
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/PluginDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/PluginDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/PluginDao.cs	(revision 12468)
@@ -0,0 +1,34 @@
+﻿#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 PluginDao : GenericDao<Guid, Plugin> {
+    public PluginDao(DataContext dataContext) : base(dataContext) { }
+
+    public override Plugin GetById(Guid id) {
+      return Table.SingleOrDefault(x => x.PluginId == id);
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/PluginDataDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/PluginDataDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/PluginDataDao.cs	(revision 12468)
@@ -0,0 +1,34 @@
+﻿#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 Table.SingleOrDefault(x => x.PluginDataId == id);
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/RequiredPluginDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/RequiredPluginDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/RequiredPluginDao.cs	(revision 12468)
@@ -0,0 +1,34 @@
+﻿#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 Table.SingleOrDefault(x => x.RequiredPluginId == id);
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ResourceDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ResourceDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ResourceDao.cs	(revision 12468)
@@ -0,0 +1,38 @@
+﻿#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 Table.SingleOrDefault(x => x.ResourceId == id);
+    }
+
+    public IQueryable<Resource> GetResourcesWithValidOwner() {
+      return Table.Where(x => x.OwnerUserId != null);
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ResourcePermissionDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ResourcePermissionDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ResourcePermissionDao.cs	(revision 12468)
@@ -0,0 +1,33 @@
+﻿#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;
+
+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();
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/SlaveDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/SlaveDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/SlaveDao.cs	(revision 12468)
@@ -0,0 +1,119 @@
+﻿#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 Entities.SingleOrDefault(x => x.ResourceId == id);
+    }
+
+    public IQueryable<Slave> Get(Expression<Func<Slave, bool>> predicate) {
+      return Entities.Where(predicate);
+    }
+
+    public IQueryable<Slave> GetAll() {
+      return Entities;
+    }
+
+    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(Guid id) {
+      return GetById(id) != null;
+    }
+    #endregion
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/SlaveGroupDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/SlaveGroupDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/SlaveGroupDao.cs	(revision 12468)
@@ -0,0 +1,118 @@
+﻿#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 Entities.SingleOrDefault(x => x.ResourceId == 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(Guid id) {
+      return GetById(id) != null;
+    }
+    #endregion
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/StateLogDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/StateLogDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/StateLogDao.cs	(revision 12468)
@@ -0,0 +1,41 @@
+﻿#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> {
+    public StateLogDao(DataContext dataContext) : base(dataContext) { }
+
+    public override StateLog GetById(Guid id) {
+      return Table.SingleOrDefault(x => x.StateLogId == id);
+    }
+
+    public StateLog GetLastStateLogFromTask(Task task) {
+      return Table
+        .Where(x => x.TaskId == task.TaskId)
+        .OrderByDescending(x => x.DateTime)
+        .First(x => x.SlaveId != null);
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/TaskDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/TaskDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/TaskDao.cs	(revision 12468)
@@ -0,0 +1,38 @@
+﻿#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 TaskDao : GenericDao<Guid, Task> {
+    public TaskDao(DataContext dataContext) : base(dataContext) { }
+
+    public override Task GetById(Guid id) {
+      return Table.SingleOrDefault(x => x.TaskId == id);
+    }
+
+    public IQueryable<Task> GetAllChildTasks() {
+      return Table.Where(x => !x.IsParentTask);
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/TaskDataDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/TaskDataDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/TaskDataDao.cs	(revision 12468)
@@ -0,0 +1,34 @@
+﻿#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 Table.SingleOrDefault(x => x.TaskId == id);
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/UserPriorityDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/UserPriorityDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/UserPriorityDao.cs	(revision 12468)
@@ -0,0 +1,34 @@
+﻿#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 Table.SingleOrDefault(x => x.UserId == id);
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HeuristicLab.Services.Hive.DataAccess-3.3.csproj
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HeuristicLab.Services.Hive.DataAccess-3.3.csproj	(revision 12467)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HeuristicLab.Services.Hive.DataAccess-3.3.csproj	(revision 12468)
@@ -104,7 +104,33 @@
   <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="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 +142,5 @@
       <DependentUpon>HiveDataContext.dbml</DependentUpon>
     </Compile>
-    <Compile Include="ITransactionManager.cs" />
+    <Compile Include="Interfaces\ITransactionManager.cs" />
     <Compile Include="Enums\TaskState.cs" />
     <Compile Include="Logger.cs" />
@@ -128,5 +154,5 @@
     </Compile>
     <Compile Include="Enums\SlaveState.cs" />
-    <Compile Include="TransactionManager.cs" />
+    <Compile Include="Manager\TransactionManager.cs" />
   </ItemGroup>
   <ItemGroup>
@@ -158,4 +184,5 @@
     <Content Include="SQL Scripts\Prepare Hive Database.sql" />
   </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <PropertyGroup>
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDao.cs	(revision 12467)
+++ 	(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: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDataContext.dbml
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDataContext.dbml	(revision 12467)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDataContext.dbml	(revision 12468)
@@ -1,4 +1,4 @@
 ﻿<?xml version="1.0" encoding="utf-8"?><Database Name="HeuristicLab.Hive-3.3" Class="HiveDataContext" xmlns="http://schemas.microsoft.com/linqtosql/dbml/2007">
-  <Connection Mode="AppSettings" ConnectionString="Data Source=.\SQLEXPRESS;Initial Catalog=HeuristicLab.Hive-3.3;Integrated Security=True" SettingsObjectName="HeuristicLab.Services.Hive.DataAccess.Settings" SettingsPropertyName="HeuristicLab_Hive_LinqConnectionString" Provider="System.Data.SqlClient" />
+  <Connection Mode="AppSettings" ConnectionString="Data Source=localhost;Initial Catalog=HeuristicLab.Hive-3.3;Integrated Security=True" SettingsObjectName="HeuristicLab.Services.Hive.DataAccess.Settings" SettingsPropertyName="HeuristicLab_Hive_LinqConnectionString" Provider="System.Data.SqlClient" />
   <Table Name="dbo.AssignedResources" Member="AssignedResources">
     <Type Name="AssignedResource">
@@ -233,5 +233,5 @@
       <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="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="StartTime" Type="System.DateTime" DbType="DateTime NOT NULL" CanBeNull="false" />
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDataContext.dbml.layout
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDataContext.dbml.layout	(revision 12467)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDataContext.dbml.layout	(revision 12468)
@@ -297,5 +297,5 @@
       </nodes>
     </associationConnector>
-    <associationConnector edgePoints="[(5.02343625 : 10.2708968098958); (5.02343625 : 14.7227579166667); (6.875 : 14.7227579166667)]" fixedFrom="NotFixed" fixedTo="NotFixed">
+    <associationConnector edgePoints="[(5.02343625 : 10.2708968098958); (5.02343625 : 14.7227579166667); (5.90885291666667 : 14.7227579166667 : JumpStart); (6.07551958333333 : 14.7227579166667 : JumpEnd); (6.875 : 14.7227579166667)]" fixedFrom="NotFixed" fixedTo="NotFixed">
       <AssociationMoniker Name="/HiveDataContext/DimTime/DimTime_FactTask" />
       <nodes>
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDataContext.designer.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDataContext.designer.cs	(revision 12467)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/HiveDataContext.designer.cs	(revision 12468)
@@ -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
@@ -4863,5 +4863,5 @@
 		private int _Priority;
 		
-		private System.Guid _LastClientId;
+		private System.Nullable<System.Guid> _LastClientId;
 		
 		private System.Guid _JobId;
@@ -4905,5 +4905,5 @@
     partial void OnPriorityChanging(int value);
     partial void OnPriorityChanged();
-    partial void OnLastClientIdChanging(System.Guid value);
+    partial void OnLastClientIdChanging(System.Nullable<System.Guid> value);
     partial void OnLastClientIdChanged();
     partial void OnJobIdChanging(System.Guid value);
@@ -5109,5 +5109,5 @@
 		
 		[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_LastClientId", DbType="UniqueIdentifier NOT NULL")]
-		public System.Guid LastClientId
+		public System.Nullable<System.Guid> LastClientId
 		{
 			get
@@ -5271,5 +5271,5 @@
 					else
 					{
-						this._LastClientId = default(System.Guid);
+						this._LastClientId = default(Nullable<System.Guid>);
 					}
 					this.SendPropertyChanged("DimClient");
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/ITransactionManager.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/ITransactionManager.cs	(revision 12467)
+++ 	(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: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Interfaces/IGenericDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Interfaces/IGenericDao.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Interfaces/IGenericDao.cs	(revision 12468)
@@ -0,0 +1,44 @@
+﻿#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(PK id);
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Interfaces/IHiveDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Interfaces/IHiveDao.cs	(revision 12467)
+++ 	(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: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Interfaces/IPersistenceManager.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Interfaces/IPersistenceManager.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Interfaces/IPersistenceManager.cs	(revision 12468)
@@ -0,0 +1,66 @@
+﻿#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;
+
+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
+
+    void SubmitChanges();
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Interfaces/ITransactionManager.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Interfaces/ITransactionManager.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Interfaces/ITransactionManager.cs	(revision 12468)
@@ -0,0 +1,29 @@
+﻿#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.Interfaces {
+  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: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Manager/PersistenceManager.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Manager/PersistenceManager.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Manager/PersistenceManager.cs	(revision 12468)
@@ -0,0 +1,186 @@
+﻿#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.Transactions;
+using HeuristicLab.Services.Hive.DataAccess.Daos;
+using HeuristicLab.Services.Hive.DataAccess.Daos.HiveStatistics;
+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
+    public AssignedResourceDao AssignedResourceDao {
+      get { return new AssignedResourceDao(dataContext); }
+    }
+
+    public DowntimeDao DowntimeDao {
+      get { return new DowntimeDao(dataContext); }
+    }
+
+    public JobDao JobDao {
+      get { return new JobDao(dataContext); }
+    }
+
+    public JobPermissionDao JobPermissionDao {
+      get { return new JobPermissionDao(dataContext); }
+    }
+
+    public LifecycleDao LifecycleDao {
+      get { return new LifecycleDao(dataContext); }
+    }
+
+    public PluginDao PluginDao {
+      get { return new PluginDao(dataContext); }
+    }
+
+    public PluginDataDao PluginDataDao {
+      get { return new PluginDataDao(dataContext); }
+    }
+
+    public RequiredPluginDao RequiredPluginDao {
+      get { return new RequiredPluginDao(dataContext); }
+    }
+
+    public ResourceDao ResourceDao {
+      get { return new ResourceDao(dataContext); }
+    }
+
+    public ResourcePermissionDao ResourcePermissionDao {
+      get { return new ResourcePermissionDao(dataContext); }
+    }
+
+    public SlaveDao SlaveDao {
+      get { return new SlaveDao(dataContext); }
+    }
+
+    public SlaveGroupDao SlaveGroupDao {
+      get { return new SlaveGroupDao(dataContext); }
+    }
+
+    public StateLogDao StateLogDao {
+      get { return new StateLogDao(dataContext); }
+    }
+
+    public TaskDao TaskDao {
+      get { return new TaskDao(dataContext); }
+    }
+
+    public TaskDataDao TaskDataDao {
+      get { return new TaskDataDao(dataContext); }
+    }
+
+    public UserPriorityDao UserPriorityDao {
+      get { return new UserPriorityDao(dataContext); }
+    }
+    #endregion
+
+    #region HiveStatistics daos
+    public DimClientDao DimClientDao {
+      get { return new DimClientDao(dataContext); }
+    }
+
+    public DimJobDao DimJobDao {
+      get { return new DimJobDao(dataContext); }
+    }
+
+    public DimTimeDao DimTimeDao {
+      get { return new DimTimeDao(dataContext); }
+    }
+
+    public DimUserDao DimUserDao {
+      get { return new DimUserDao(dataContext); }
+    }
+
+    public FactClientInfoDao FactClientInfoDao {
+      get { return new FactClientInfoDao(dataContext); }
+    }
+
+    public FactTaskDao FactTaskDao {
+      get { return 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;
+    }
+
+    #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 void SubmitChanges() {
+      if (dataContext != null) {
+        dataContext.SubmitChanges();
+      }
+    }
+
+    public void Dispose() {
+      if (dataContext != null) {
+        dataContext.Dispose();
+      }
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Manager/TransactionManager.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Manager/TransactionManager.cs	(revision 12468)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Manager/TransactionManager.cs	(revision 12468)
@@ -0,0 +1,83 @@
+﻿#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;
+using HeuristicLab.Services.Hive.DataAccess.Interfaces;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Manager {
+  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);
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/SQL Scripts/Initialize Hive Database.sql
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/SQL Scripts/Initialize Hive Database.sql	(revision 12467)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/SQL Scripts/Initialize Hive Database.sql	(revision 12468)
@@ -239,5 +239,5 @@
     [TotalMemory]           INT              NOT NULL,
     [CpuUtilization]        FLOAT (53)       NOT NULL,
-	[SlaveState]			VarChar(15) 	 NOT NULL,
+    [SlaveState]			VarChar(15) 	 NOT NULL,
     [TotalTimeIdle]         FLOAT (53)       NOT NULL,
     [TotalTimeCalculating]  FLOAT (53)       NOT NULL,
@@ -260,10 +260,10 @@
     [MemoryRequired]     INT              NOT NULL,
     [Priority]           INT              NOT NULL,
-    [LastClientId]       UNIQUEIDENTIFIER NOT NULL,
+    [LastClientId]       UNIQUEIDENTIFIER NULL,
     [JobId]              UNIQUEIDENTIFIER NOT NULL,
     [StartTime]          DATETIME         NOT NULL,
     [EndTime]            DATETIME         NULL,
-	[TaskState]          VARCHAR (30)     NOT NULL,
-	[Exception]			 VARCHAR (MAX)	  NULL,
+    [TaskState]          VARCHAR (30)     NOT NULL,
+    [Exception]			 VARCHAR (MAX)	  NULL,
     CONSTRAINT [PK_FactTask] PRIMARY KEY CLUSTERED ([TaskId] ASC),
     CONSTRAINT [FK_FactTask_DimClient] FOREIGN KEY ([LastClientId]) REFERENCES [statistics].[DimClient] ([Id]),
@@ -273,4 +273,5 @@
 );
 
-INSERT INTO [HeuristicLab.Hive-3.3].[statistics].[DimClient] ([Id] ,[Name] ,[ResourceId])
-VALUES ('00000000-0000-0000-0000-000000000000' ,'NULL' ,'00000000-0000-0000-0000-000000000000')
+/* dummy for nullable userIds in FactClientInfo */
+INSERT INTO [statistics].[DimUser] ([UserId], [Name])
+VALUES ('00000000-0000-0000-0000-000000000000', 'NULL');
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/TransactionManager.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/TransactionManager.cs	(revision 12467)
+++ 	(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);
-    }
-  }
-}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Web/Hive-3.3/Status.aspx.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Web/Hive-3.3/Status.aspx.cs	(revision 12467)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Web/Hive-3.3/Status.aspx.cs	(revision 12468)
@@ -84,5 +84,5 @@
 
     overallCpuUtilizationLabel.Text = (onlineSlaves.Any() ? Math.Round(onlineSlaves.Average(s => s.CpuUtilization), 2).ToString() : "0.0") + " %";
-    cpuUtilizationLabel.Text = (onlineSlaves.Any() && onlineSlaves.Any(x => x.IsAllowedToCalculate) ? Math.Round(onlineSlaves.Where(x => x.IsAllowedToCalculate).Average(s => s.CpuUtilization), 2).ToString() : "0.0") + " %";
+    cpuUtilizationLabel.Text = (onlineSlaves.Any(x => x.IsAllowedToCalculate) ? Math.Round(onlineSlaves.Where(x => x.IsAllowedToCalculate).Average(s => s.CpuUtilization), 2).ToString() : "0.0") + " %";
 
     DT.Statistics[] stats = new DT.Statistics[0];
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/HiveDao.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/HiveDao.cs	(revision 12467)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/HiveDao.cs	(revision 12468)
@@ -891,4 +891,5 @@
     public List<DT.UserStatistics> GetUserStatistics() {
       using (var db = CreateContext()) {
+        db.Log = Console.Out;
         var userStats = new Dictionary<Guid, DT.UserStatistics>();
 
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/HiveJanitor.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/HiveJanitor.cs	(revision 12467)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/HiveJanitor.cs	(revision 12468)
@@ -23,4 +23,5 @@
 using System.Threading;
 using HeuristicLab.Services.Hive.DataAccess;
+using HeuristicLab.Services.Hive.DataAccess.Interfaces;
 
 namespace HeuristicLab.Services.Hive {
@@ -30,5 +31,5 @@
     private AutoResetEvent generateStatisticsWaitHandle;
 
-    private DataAccess.ITransactionManager trans {
+    private ITransactionManager trans {
       get { return ServiceLocator.Instance.TransactionManager; }
     }
@@ -55,4 +56,5 @@
       stop = true;
       cleanupWaitHandle.Set();
+      generateStatisticsWaitHandle.Set();
     }
 
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/HiveService.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/HiveService.cs	(revision 12467)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/HiveService.cs	(revision 12468)
@@ -24,4 +24,5 @@
 using System.Linq;
 using System.ServiceModel;
+using HeuristicLab.Services.Hive.DataAccess.Interfaces;
 using HeuristicLab.Services.Hive.DataTransfer;
 using HeuristicLab.Services.Hive.ServiceContracts;
@@ -51,5 +52,5 @@
       get { return ServiceLocator.Instance.AuthorizationManager; }
     }
-    private DataAccess.ITransactionManager trans {
+    private ITransactionManager trans {
       get { return ServiceLocator.Instance.TransactionManager; }
     }
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/HiveStatisticsGenerator.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/HiveStatisticsGenerator.cs	(revision 12467)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/HiveStatisticsGenerator.cs	(revision 12468)
@@ -1,266 +1,280 @@
-﻿using System;
+﻿#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.Transactions;
-using HeuristicLab.Services.Access;
 using HeuristicLab.Services.Hive.DataAccess;
+using HeuristicLab.Services.Hive.DataAccess.Manager;
 
 namespace HeuristicLab.Services.Hive {
   public class HiveStatisticsGenerator : IStatisticsGenerator {
-    private IUserManager userManager { get { return ServiceLocator.Instance.UserManager; } }
-
+
+    private const string UnknownUserName = "Unknown";
     private static readonly TimeSpan SmallestTimeSpan = new TimeSpan(0, 5, 0);
-    private static readonly string UnknownUserName = "Unknown";
 
     public void GenerateStatistics() {
-      using (var db = new HiveDataContext(Settings.Default.HeuristicLab_Hive_LinqConnectionString))
-      using (var transaction = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted })) {
-
-        var newTime = UpdateDimensionTables(db);
-        db.SubmitChanges();
-
-        if (newTime != null) {
-          UpdateFactTables(newTime, db);
-          try {
-            db.SubmitChanges();
+      using (var pm = new PersistenceManager()) {
+        pm.UseTransaction(() => {
+          UpdateDimUserTable(pm);
+          UpdateDimJobTable(pm);
+          UpdateDimClients(pm);
+          pm.SubmitChanges();
+        });
+
+        pm.UseTransaction(() => {
+          var newTime = UpdateDimTimeTable(pm);
+          if (newTime != null) {
+            pm.SubmitChanges();
+            UpdateFactClientInfoTable(newTime, pm);
+            UpdateTaskFacts(newTime, pm);
+            try {
+              pm.SubmitChanges();
+            }
+            catch (DuplicateKeyException e) {
+              var logger = LogFactory.GetLogger(typeof(HiveStatisticsGenerator).Namespace);
+              logger.Log(string.Format(
+                @"Propable change from summertime to wintertime, resulting in overlapping times.
+                          On wintertime to summertime change, slave timeouts and a fact gap will occur. 
+                          Exception Details: {0}", e));
+            }
           }
-          catch (DuplicateKeyException) {
-            // Propable change from summertime to wintertime, resulting in overlapping times
-            // On wintertime to summertime change, slave timeouts and a fact gap will occur
-          }
+        });
+      }
+    }
+
+    private DimTime UpdateDimTimeTable(PersistenceManager pm) {
+      var dimTimeDao = pm.DimTimeDao;
+      var now = DateTime.Now;
+      var timeEntry = new DimTime {
+        Time = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0),
+        Hour = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0),
+        Day = new DateTime(now.Year, now.Month, now.Day, 0, 0, 0),
+        Month = new DateTime(now.Year, now.Month, 1, 0, 0, 0),
+        Year = new DateTime(now.Year, 1, 1, 0, 0, 0)
+      };
+      // using SaveOrAttach instead of save because the table can only be updated once every minute
+      // (pk restriction) save would cause a duplicate key exception if the method is accidentally 
+      // called more than once every minute (e.g. restarting the service within a minute)
+      return dimTimeDao.SaveOrAttach(timeEntry);
+    }
+
+    private void UpdateDimUserTable(PersistenceManager pm) {
+      var dimUserDao = pm.DimUserDao;
+      var resourceDao = pm.ResourceDao;
+      var jobDao = pm.JobDao;
+      var existingUserIds = dimUserDao.GetAll().Select(x => x.UserId);
+      var vaildResourceOwnerIds = resourceDao.GetResourcesWithValidOwner().Select(x => x.OwnerUserId.Value);
+      var jobOwnerIds = jobDao.GetAll().Select(x => x.OwnerUserId);
+      var newUserIds = vaildResourceOwnerIds
+        .Union(jobOwnerIds)
+        .Where(id => !existingUserIds.Contains(id))
+        .ToList();
+      dimUserDao.Save(newUserIds.Select(x => new DimUser {
+        UserId = x,
+        Name = GetUserName(x)
+      }));
+    }
+
+    private void UpdateDimJobTable(PersistenceManager pm) {
+      var dimJobDao = pm.DimJobDao;
+      var jobDao = pm.JobDao;
+      var dimJobIds = dimJobDao.GetAll().Select(x => x.JobId);
+      var newJobs = jobDao.GetAll()
+        .Where(x => !dimJobIds.Contains(x.JobId))
+        .Select(x => new {
+          JobId = x.JobId,
+          UserId = x.OwnerUserId,
+          JobName = x.Name ?? string.Empty,
+        })
+        .ToList();
+      dimJobDao.Save(newJobs.Select(x => new DimJob {
+        JobId = x.JobId,
+        JobName = x.JobName,
+        UserId = x.UserId,
+        UserName = GetUserName(x.UserId)
+      }));
+    }
+
+    private void UpdateDimClients(PersistenceManager pm) {
+      var dimClientDao = pm.DimClientDao;
+      var slaveDao = pm.SlaveDao;
+      var slaves = slaveDao.GetAll();
+      var recentlyAddedClients = dimClientDao.GetRecentlyAddedClients();
+      var slaveIds = slaves.Select(x => x.ResourceId);
+
+      var removedClientIds = recentlyAddedClients
+        .Where(x => !slaveIds.Contains(x.ResourceId))
+        .Select(x => x.Id);
+      var modifiedClients =
+        from slave in slaves
+        join client in recentlyAddedClients on slave.ResourceId equals client.ResourceId
+        where (slave.Name != client.Name
+               || slave.ParentResourceId != client.ResourceGroupId
+               || slave.ParentResource.ParentResourceId != client.ResourceGroup2Id)
+        select new {
+          SlaveId = slave.ResourceId,
+          ClientId = client.Id
+        };
+      var clientIds = dimClientDao.GetAll().Select(x => x.ResourceId);
+      var modifiedClientIds = modifiedClients.Select(x => x.SlaveId);
+      var newClients = slaves
+        .Where(x => !clientIds.Contains(x.ResourceId)
+                    || modifiedClientIds.Contains(x.ResourceId))
+        .Select(x => new {
+          x.ResourceId,
+          x.Name,
+          ResourceGroupId = x.ParentResourceId,
+          ResourceGroup2Id = x.ParentResource.ParentResourceId
+        })
+        .ToList();
+
+      var clientsToUpdate = removedClientIds.Union(modifiedClients.Select(x => x.ClientId));
+      dimClientDao.UpdateExpirationTime(clientsToUpdate, DateTime.Now);
+      dimClientDao.Save(newClients.Select(x => new DimClient {
+        ResourceId = x.ResourceId,
+        Name = x.Name,
+        ExpirationTime = null,
+        ResourceGroupId = x.ResourceGroupId,
+        ResourceGroup2Id = x.ResourceGroup2Id
+      }));
+    }
+
+    private void UpdateFactClientInfoTable(DimTime newTime, PersistenceManager pm) {
+      var factClientInfoDao = pm.FactClientInfoDao;
+      var slaveDao = pm.SlaveDao;
+      var dimClientDao = pm.DimClientDao;
+
+      var newRawFactInfos =
+        from s in slaveDao.GetAll()
+        join c in dimClientDao.GetRecentlyAddedClients() on s.ResourceId equals c.ResourceId
+        join lcf in factClientInfoDao.GetLastUpdateTimestamps() on c.ResourceId equals lcf.ResourceId into joinCf
+        from cf in joinCf.DefaultIfEmpty()
+        select new {
+          ClientId = c.Id,
+          UserId = s.OwnerUserId ?? Guid.Empty,
+          TotalCores = s.Cores ?? 0,
+          FreeCores = s.FreeCores ?? 0,
+          TotalMemory = s.Memory ?? 0,
+          FreeMemory = s.FreeMemory ?? 0,
+          CpuUtilization = s.CpuUtilization,
+          SlaveState = s.SlaveState,
+          IsAllowedToCalculate = s.IsAllowedToCalculate,
+          LastFactTimestamp = cf.Timestamp
+        };
+
+      factClientInfoDao.Save(
+        from x in newRawFactInfos.ToList()
+        let duration = x.LastFactTimestamp != null
+                       ? (newTime.Time - (DateTime)x.LastFactTimestamp).TotalMinutes
+                       : SmallestTimeSpan.TotalMinutes
+        select new FactClientInfo {
+          ClientId = x.ClientId,
+          DimTime = newTime,
+          UserId = x.UserId,
+          NumUsedCores = x.TotalCores - x.FreeCores,
+          NumTotalCores = x.TotalMemory,
+          UsedMemory = x.TotalMemory - x.FreeMemory,
+          TotalMemory = x.TotalMemory,
+          CpuUtilization = x.CpuUtilization,
+          SlaveState = x.SlaveState,
+          TotalTimeIdle = x.SlaveState == SlaveState.Idle && x.IsAllowedToCalculate ? duration : 0.0,
+          TotalTimeCalculating = x.SlaveState == SlaveState.Calculating ? duration : 0.0,
+          TotalTimeUnavailable = x.SlaveState == SlaveState.Idle && !x.IsAllowedToCalculate ? duration : 0.0,
+          TotalTimeOffline = x.SlaveState == SlaveState.Offline ? duration : 0.0
         }
-
-        transaction.Complete();
-      }
-    }
-
-    private DimTime UpdateDimensionTables(HiveDataContext db) {
-      var newTime = UpdateTime(db);
-
-      UpdateUsers(db);
-      UpdateJobs(db);
-      UpdateClients(db);
-
-      return newTime;
-    }
-
-    private DimTime UpdateTime(HiveDataContext db) {
-      var lastUpdateTime =
-        (from t in db.DimTimes
-         orderby t.Time descending
-         select t.Time)
-        .FirstOrDefault();
-
-      var now = DateTime.Now;
-      DimTime newTime = null;
-
-      if (lastUpdateTime == default(DateTime) || lastUpdateTime + SmallestTimeSpan < now) {
-        newTime = new DimTime {
-          Time = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute - now.Minute % SmallestTimeSpan.Minutes, 0),
-          Hour = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0),
-          Day = new DateTime(now.Year, now.Month, now.Day, 0, 0, 0),
-          Month = new DateTime(now.Year, now.Month, 1, 0, 0, 0),
-          Year = new DateTime(now.Year, 1, 1, 0, 0, 0)
-        };
-        db.DimTimes.InsertOnSubmit(newTime);
-      }
-
-      return newTime;
-    }
-
-    private void UpdateUsers(HiveDataContext db) {
-      var newUsers =
-        from u in db.Resources.Where(x => x.OwnerUserId != null).Select(x => x.OwnerUserId.Value).Union(db.Jobs.Select(x => x.OwnerUserId))
-        where !db.DimUsers.Select(x => x.UserId).Contains(u)
-        select u;
-
-
-      var newDimUsers =
-     from u in newUsers.ToList()
-     select new DimUser {
-       UserId = u,
-       Name = userManager.GetUserById(u) != null ? userManager.GetUserById(u).UserName : UnknownUserName
-     };
-
-      db.DimUsers.InsertAllOnSubmit(newDimUsers);
-
-      // insert NULL-User
-      if (!db.DimUsers.Any(x => x.UserId == Guid.Empty)) {
-        db.DimUsers.InsertOnSubmit(new DimUser { UserId = Guid.Empty, Name = "NULL" });
-      }
-    }
-
-    private void UpdateJobs(HiveDataContext db) {
-      var newJobs =
-        from j in db.Jobs
-        where !db.DimJobs.Select(x => x.JobId).Contains(j.JobId)
-        select j;
-
-      var newDimJobs =
-        from j in newJobs.ToList()
-        select new DimJob {
-          JobId = j.JobId,
-          JobName = j.Name == null ? string.Empty : j.Name,
-          UserId = j.OwnerUserId,
-          UserName = userManager.GetUserById(j.OwnerUserId) != null ? userManager.GetUserById(j.OwnerUserId).UserName : UnknownUserName
-        };
-
-      db.DimJobs.InsertAllOnSubmit(newDimJobs);
-
-      // insert NULL-Job
-      if (!db.DimJobs.Any(x => x.JobId == Guid.Empty)) {
-        db.DimJobs.InsertOnSubmit(new DimJob { JobId = Guid.Empty, JobName = "NULL", UserId = Guid.Empty, UserName = "NULL" });
-      }
-    }
-
-    private void UpdateClients(HiveDataContext db) {
-      var removedClients =
-        from c in db.DimClients
-        where c.ExpirationTime == null &&
-              !db.Resources.OfType<Slave>().Select(x => x.ResourceId).Contains(c.ResourceId)
-        select c;
-
-      var modifiedClients =
-        from s in db.Resources.OfType<Slave>()
-        join c in db.DimClients on s.ResourceId equals c.ResourceId
-        where c.ExpirationTime == null
-              && (s.Name != c.Name || s.ParentResourceId != c.ResourceGroupId ||
-                  s.ParentResource.ParentResourceId != c.ResourceGroup2Id)
-        select new { Slave = s, Client = c };
-
-      foreach (var client in removedClients.Union(modifiedClients.Select(x => x.Client))) {
-        client.ExpirationTime = DateTime.Now;
-      }
-
-      var newClients =
-        from s in db.Resources.OfType<Slave>()
-        where !db.DimClients.Select(x => x.ResourceId).Contains(s.ResourceId)
-              || modifiedClients.Select(x => x.Slave.ResourceId).Contains(s.ResourceId)
-        select new {
-          Slave = s,
-          Group = s.ParentResourceId,
-          Group2 = s.ParentResource.ParentResourceId
-        };
-
-      var newDimClients =
-        from s in newClients.ToList()
-        select new DimClient {
-          ResourceId = s.Slave.ResourceId,
-          Name = s.Slave.Name,
-          ExpirationTime = null,
-          ResourceGroupId = s.Group,
-          ResourceGroup2Id = s.Group2
-        };
-
-      db.DimClients.InsertAllOnSubmit(newDimClients);
-    }
-
-    private void UpdateFactTables(DimTime newTime, HiveDataContext db) {
-      UpdateClientInfoFacts(newTime, db);
-      UpdateTaskFacts(newTime, db);
-    }
-
-    private void UpdateClientInfoFacts(DimTime newTime, HiveDataContext db) {
-      var time = newTime.Time;
-
-      var lastFacts =
-        from cf in db.FactClientInfos
-        join r in db.DimClients on cf.ClientId equals r.Id
-        group cf by r.ResourceId into grpFacts
-        select new {
-          ResourceId = grpFacts.Key,
-          Fact = grpFacts.OrderByDescending(x => x.Time).First(),
-        };
-
-      var slaves =
-        from s in db.Resources.OfType<Slave>()
-        join c in db.DimClients on s.ResourceId equals c.ResourceId
-        join lcf in lastFacts on c.ResourceId equals lcf.ResourceId into joinCf
-        from cf in joinCf.DefaultIfEmpty()
-        where c.ExpirationTime == null
-        select new {
-          Slave = s,
-          Client = c,
-          LastFact = cf != null ? cf.Fact : null
-        };
-
-      var clientFacts =
-        from s in slaves.ToList()
-        let duration = s.LastFact != null ? (time - s.LastFact.Time).TotalMinutes : SmallestTimeSpan.TotalMinutes
-        select new FactClientInfo {
-          DimClient = s.Client,
-          DimTime = newTime,
-          UserId = s.Slave.OwnerUserId ?? Guid.Empty,
-          NumUsedCores = s.Slave.Cores != null && s.Slave.FreeCores != null
-                         ? s.Slave.Cores.Value - s.Slave.FreeCores.Value : 0,
-          NumTotalCores = s.Slave.Cores ?? 0,
-          UsedMemory = s.Slave.Memory != null && s.Slave.FreeMemory != null
-                       ? s.Slave.Memory.Value - s.Slave.FreeMemory.Value : 0,
-          TotalMemory = s.Slave.Memory ?? 0,
-          CpuUtilization = s.Slave.CpuUtilization,
-          SlaveState = s.Slave.SlaveState,
-          TotalTimeIdle = s.Slave.SlaveState == SlaveState.Idle && s.Slave.IsAllowedToCalculate
-                                  ? duration : 0.0,
-          TotalTimeCalculating = s.Slave.SlaveState == SlaveState.Calculating
-                                  ? duration : 0.0,
-          TotalTimeTransferring = 0.0,
-          TotalTimeUnavailable = s.Slave.SlaveState == SlaveState.Idle && !s.Slave.IsAllowedToCalculate
-                                  ? duration : 0.0,
-          TotalTimeOffline = s.Slave.SlaveState == SlaveState.Offline
-                                  ? duration : 0.0
-        };
-
-      db.FactClientInfos.InsertAllOnSubmit(clientFacts);
-    }
-
-    private void UpdateTaskFacts(DimTime newTime, HiveDataContext db) {
-      // old Task facts
-      var oldFacts =
-        from fact in db.FactTasks
-        where fact.EndTime == null
-        select fact;
-
-      // query Task facts data
-      var newFacts =
-        from task in db.Tasks
-        where !task.IsParentTask
-          && (!db.FactTasks.Select(fact => fact.TaskId).Contains(task.TaskId) || oldFacts.Select(fact => fact.TaskId).Contains(task.TaskId))
-        join lastFact in oldFacts on task.TaskId equals lastFact.TaskId into lastFactPerTask
+      );
+    }
+
+    private void UpdateTaskFacts(DimTime newTime, PersistenceManager pm) {
+      var factTaskDao = pm.FactTaskDao;
+      var taskDao = pm.TaskDao;
+      var dimClientDao = pm.DimClientDao;
+      var stateLogDao = pm.StateLogDao;
+
+      var factTaskIds = factTaskDao.GetAll().Select(x => x.TaskId);
+      var notFinishedFactTasks = factTaskDao.GetNotFinishedTasks().Select(x => new {
+        x.TaskId,
+        x.DimTimeStart,
+        x.LastClientId
+      });
+
+      var newTasks =
+        from task in taskDao.GetAllChildTasks()
+        let stateLogs = task.StateLogs.OrderByDescending(x => x.DateTime)
+        let lastSlaveId = stateLogs.First(x => x.SlaveId != null).SlaveId
+        where (!factTaskIds.Contains(task.TaskId)
+               || notFinishedFactTasks.Select(x => x.TaskId).Contains(task.TaskId))
+        join lastFactTask in notFinishedFactTasks on task.TaskId equals lastFactTask.TaskId into lastFactPerTask
         from lastFact in lastFactPerTask.DefaultIfEmpty()
-        let lastSlaveId = task.StateLogs.OrderByDescending(sl => sl.DateTime).First(sl => sl.SlaveId != null).SlaveId
-        join client in db.DimClients.Where(client => client.ExpirationTime == null) on lastSlaveId equals client.ResourceId into clientsPerSlaveId
+        join client in dimClientDao.GetRecentlyAddedClients() on lastSlaveId equals client.ResourceId into clientsPerSlaveId
         from client in clientsPerSlaveId.DefaultIfEmpty()
         select new {
-          Task = task,
-          StateLogs = task.StateLogs.OrderBy(sl => sl.DateTime),
-          LastClientId = client != null ? client.Id : default(Guid?),
-          LastFact = lastFact
+          TaskId = task.TaskId,
+          JobId = task.JobId,
+          Priority = task.Priority,
+          CoresRequired = task.CoresNeeded,
+          MemoryRequired = task.MemoryNeeded,
+          State = task.State,
+          StateLogs = stateLogs,
+          DimTimeStart = lastFact != null ? lastFact.DimTimeStart : newTime,
+          LastClientId = client != null
+                         ? client.Id : lastFact != null
+                         ? lastFact.LastClientId : (Guid?)null
         };
 
-      // new Task facts
-      var newTaskFacts =
-        from t in newFacts.ToList()
-        let stateLogsLinkedList = new LinkedList<StateLog>(t.StateLogs)
+      var endStates = new[] { TaskState.Finished, TaskState.Failed, TaskState.Aborted };
+      factTaskDao.Save(
+        from x in newTasks.ToList()
+        let stateLogsLinkedList = new LinkedList<StateLog>(x.StateLogs.OrderBy(y => y.DateTime))
+        let lastStateLog = stateLogsLinkedList.OrderByDescending(y => y.DateTime).FirstOrDefault(sl => sl.Exception != null)
         select new FactTask {
-          TaskId = t.Task.TaskId,
-          JobId = t.Task.JobId,
-          DimTimeStart = t.LastFact != null ? t.LastFact.DimTimeStart : newTime,
-          DimTimeEnd = new[] { TaskState.Finished, TaskState.Failed, TaskState.Aborted }.Contains(t.Task.State) ? newTime : null,
-          LastClientId = t.LastClientId ?? (t.LastFact != null ? t.LastFact.LastClientId : Guid.Empty),
-          Priority = t.Task.Priority,
-          CoresRequired = t.Task.CoresNeeded,
-          MemoryRequired = t.Task.MemoryNeeded,
+          TaskId = x.TaskId,
+          JobId = x.JobId,
+          DimTimeStart = x.DimTimeStart,
+          DimTimeEnd = endStates.Contains(x.State) ? newTime : null,
+          LastClientId = x.LastClientId,
+          Priority = x.Priority,
+          CoresRequired = x.CoresRequired,
+          MemoryRequired = x.MemoryRequired,
           NumCalculationRuns = stateLogsLinkedList.CountCalculationRuns(),
           NumRetries = stateLogsLinkedList.CountRetries(),
           TotalWaitingTime = stateLogsLinkedList.SumTotalTimeWhere(stateLog => stateLog.Value.State == TaskState.Waiting),
-          TotalRuntime = stateLogsLinkedList.SumTotalTimeWhere(stateLog => stateLog.Value.State == TaskState.Calculating && stateLog.NextIs(x => x.State == TaskState.Transferring)),
+          TotalRuntime = stateLogsLinkedList.SumTotalTimeWhere(stateLog => stateLog.Value.State == TaskState.Calculating && stateLog.NextIs(y => y.State == TaskState.Transferring)),
           TotalTransferTime = stateLogsLinkedList.SumTotalTimeWhere(stateLog => stateLog.Value.State == TaskState.Transferring),
-          TaskState = t.Task.State,
-          Exception = stateLogsLinkedList.FirstOrDefault(sl => sl.Exception != null) == null ? string.Empty : stateLogsLinkedList.FirstOrDefault(sl => sl.Exception != null).Exception
-        };
-
-      db.FactTasks.DeleteAllOnSubmit(oldFacts.ToList());
-      db.FactTasks.InsertAllOnSubmit(newTaskFacts);
+          TaskState = x.State,
+          Exception = lastStateLog == null ? string.Empty : lastStateLog.Exception
+        });
+      factTaskDao.Delete(notFinishedFactTasks.Select(x => x.TaskId));
+    }
+
+    private string GetUserName(Guid userId) {
+      try {
+        var userManager = ServiceLocator.Instance.UserManager;
+        var user = userManager.GetUserById(userId);
+        return user != null ? user.UserName : UnknownUserName;
+      }
+      catch (Exception) {
+        return UnknownUserName;
+      }
     }
   }
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/Interfaces/IServiceLocator.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/Interfaces/IServiceLocator.cs	(revision 12467)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/Interfaces/IServiceLocator.cs	(revision 12468)
@@ -21,4 +21,5 @@
 
 using HeuristicLab.Services.Hive.DataAccess;
+using HeuristicLab.Services.Hive.DataAccess.Interfaces;
 
 namespace HeuristicLab.Services.Hive {
@@ -26,4 +27,5 @@
     Access.IRoleVerifier RoleVerifier { get; }
     IAuthorizationManager AuthorizationManager { get; }
+    IPersistenceManager PersistenceManager { get; }
     IHiveDao HiveDao { get; }
     IOptimizedHiveDao OptimizedHiveDao { get; }
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/Manager/EventManager.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/Manager/EventManager.cs	(revision 12467)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/Manager/EventManager.cs	(revision 12468)
@@ -24,4 +24,5 @@
 using System.Linq;
 using HeuristicLab.Services.Hive.DataAccess;
+using HeuristicLab.Services.Hive.DataAccess.Interfaces;
 using DT = HeuristicLab.Services.Hive.DataTransfer;
 
@@ -41,5 +42,5 @@
       get { return LogFactory.GetLogger(this.GetType().Namespace); }
     }
-    private DataAccess.ITransactionManager trans {
+    private ITransactionManager trans {
       get { return ServiceLocator.Instance.TransactionManager; }
     }
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/Manager/HeartbeatManager.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/Manager/HeartbeatManager.cs	(revision 12467)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/Manager/HeartbeatManager.cs	(revision 12468)
@@ -25,4 +25,5 @@
 using System.Threading;
 using HeuristicLab.Services.Hive.DataAccess;
+using HeuristicLab.Services.Hive.DataAccess.Interfaces;
 using Heartbeat = HeuristicLab.Services.Hive.DataTransfer.Heartbeat;
 
@@ -37,5 +38,5 @@
       get { return ServiceLocator.Instance.TaskScheduler; }
     }
-    private DataAccess.ITransactionManager trans {
+    private ITransactionManager trans {
       get { return ServiceLocator.Instance.TransactionManager; }
     }
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/ServiceLocator.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/ServiceLocator.cs	(revision 12467)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/ServiceLocator.cs	(revision 12468)
@@ -21,4 +21,6 @@
 
 using HeuristicLab.Services.Hive.DataAccess;
+using HeuristicLab.Services.Hive.DataAccess.Interfaces;
+using HeuristicLab.Services.Hive.DataAccess.Manager;
 
 namespace HeuristicLab.Services.Hive {
@@ -32,4 +34,8 @@
       }
       set { instance = value; }
+    }
+
+    public IPersistenceManager PersistenceManager {
+      get { return new PersistenceManager(); }
     }
 
