Index: trunk/sources/HeuristicLab 3.3 Services.sln
===================================================================
--- trunk/sources/HeuristicLab 3.3 Services.sln	(revision 4277)
+++ trunk/sources/HeuristicLab 3.3 Services.sln	(revision 4278)
@@ -16,4 +16,6 @@
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Services.OKB.DataAccess-3.3", "HeuristicLab.Services.OKB.DataAccess\3.3\HeuristicLab.Services.OKB.DataAccess-3.3.csproj", "{E36BE58F-F3CE-40BB-9AB3-9F9E30AD5CCF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Services.OKB.AttributeSelector-3.3", "HeuristicLab.Services.OKB.AttributeSelector\3.3\HeuristicLab.Services.OKB.AttributeSelector-3.3.csproj", "{E80A68DB-D6E1-4395-ABF0-AFE09E4DEF8B}"
 EndProject
 Global
@@ -75,4 +77,16 @@
 		{E36BE58F-F3CE-40BB-9AB3-9F9E30AD5CCF}.Release|x86.ActiveCfg = Release|x86
 		{E36BE58F-F3CE-40BB-9AB3-9F9E30AD5CCF}.Release|x86.Build.0 = Release|x86
+		{E80A68DB-D6E1-4395-ABF0-AFE09E4DEF8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E80A68DB-D6E1-4395-ABF0-AFE09E4DEF8B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E80A68DB-D6E1-4395-ABF0-AFE09E4DEF8B}.Debug|x64.ActiveCfg = Debug|x64
+		{E80A68DB-D6E1-4395-ABF0-AFE09E4DEF8B}.Debug|x64.Build.0 = Debug|x64
+		{E80A68DB-D6E1-4395-ABF0-AFE09E4DEF8B}.Debug|x86.ActiveCfg = Debug|x86
+		{E80A68DB-D6E1-4395-ABF0-AFE09E4DEF8B}.Debug|x86.Build.0 = Debug|x86
+		{E80A68DB-D6E1-4395-ABF0-AFE09E4DEF8B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E80A68DB-D6E1-4395-ABF0-AFE09E4DEF8B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{E80A68DB-D6E1-4395-ABF0-AFE09E4DEF8B}.Release|x64.ActiveCfg = Release|x64
+		{E80A68DB-D6E1-4395-ABF0-AFE09E4DEF8B}.Release|x64.Build.0 = Release|x64
+		{E80A68DB-D6E1-4395-ABF0-AFE09E4DEF8B}.Release|x86.ActiveCfg = Release|x86
+		{E80A68DB-D6E1-4395-ABF0-AFE09E4DEF8B}.Release|x86.Build.0 = Release|x86
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
Index: trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/AttributeSelector.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/AttributeSelector.cs	(revision 4278)
+++ trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/AttributeSelector.cs	(revision 4278)
@@ -0,0 +1,188 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 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 System.Text;
+using HeuristicLab.Services.OKB.DataAccess;
+
+namespace HeuristicLab.Services.OKB.AttributeSelector {
+
+  public class AttributeSelector : IAttributeSelector {
+
+    public string TableName { get; private set; }
+    public string FieldName { get; private set; }
+    public bool IsHidden { get; set; }
+    public object MinValue { get; set; }
+    public object MaxValue { get; set; }
+    public ICollection<object> AllowedValues { get; set; }
+
+    public Type TableType { get; private set; }
+    public bool IsDynamic { get; private set; }
+    public Type DataType { get; private set; }
+    public int ParentId { get; private set; }
+
+    protected static readonly List<string> staticTables = new List<string>() {
+      typeof(AlgorithmClass).Name,
+      typeof(Algorithm).Name,
+      typeof(ProblemClass).Name,
+      typeof(Problem).Name,
+      typeof(Experiment).Name,
+      typeof(Platform).Name,
+      typeof(SolutionRepresentation).Name,
+      typeof(Project).Name,
+      typeof(Run).Name,
+      typeof(Client).Name,
+      typeof(User).Name,
+      typeof(ExperimentCreator).Name,
+    };
+
+    protected static readonly List<string> dynamicTables = new List<string>() {
+      typeof(ProblemCharacteristic).Name,
+      typeof(Parameter).Name,
+      typeof(Result).Name,
+    };
+
+    protected AttributeSelector(Type tableType, string fieldName, bool isDynamic, Type dataType, int parentId) {
+      TableName = tableType.Name;
+      FieldName = fieldName;
+      TableType = tableType;
+      IsDynamic = isDynamic;
+      DataType = dataType;
+      ParentId = parentId;
+    }
+
+    public AttributeSelector(OKBDataContext okb, string tableName, string fieldName) {
+      TableName = tableName;
+      FieldName = fieldName;
+      if (tableName == typeof(ExperimentCreator).Name)
+        tableName = typeof(User).Name;
+      TableType = GetTableType(tableName);
+      ITable Table = GetTable(okb, tableName);
+      if (staticTables.Contains(tableName)) {
+        IsDynamic = false;
+        try {
+          DataType = TableType.GetProperty(fieldName).PropertyType;
+        }
+        catch (Exception x) {
+          throw new ArgumentException(String.Format(
+            "Invalid field name {0} in table {1}", fieldName, tableName),
+            x);
+        }
+      } else if (dynamicTables.Contains(tableName)) {
+        IsDynamic = true;
+        try {
+          IDynamicParent parent =
+            Table
+            .Cast<IDynamicParent>()
+            .Single(t => t.Name == fieldName);
+          ParentId = parent.Id;
+          DataType = parent.DataType.Type;
+        }
+        catch (Exception x) {
+          throw new ArgumentException(String.Format(
+            "Invalid field name {0} in table {1}", fieldName, tableName),
+            x);
+        }
+      } else {
+        throw new ArgumentException(String.Format("Invalid table name {0}", tableName));
+      }
+    }
+
+    protected static Type GetTableType(string name) {
+      try {
+        return typeof(Run).Assembly.GetType(typeof(Run).Namespace + "." + name, true);
+      }
+      catch {
+        return null;
+      }
+    }
+
+    protected static ITable GetTable(OKBDataContext okb, string name) {
+      return okb.GetTable(GetTableType(name));
+    }
+
+    public string FullName {
+      get {
+        return new StringBuilder().Append(TableName).Append('_').Append(FieldName).ToString();
+      }
+    }
+
+    protected static void LoadWith(DataLoadOptions dlo, Type parentType, Type type) {
+      ParameterExpression parent = Expression.Parameter(parentType, parentType.Name.ToLower());
+      LambdaExpression expr = Expression.Lambda(Expression.PropertyOrField(parent, type.Name), parent);
+      try {
+        dlo.LoadWith(expr);
+      }
+      catch (ArgumentException) {
+        Console.WriteLine(String.Format("Info: dlo.LoadWith<{0}>({1}) has already been added", parent.Type.Name, expr));
+      }
+    }
+
+    protected LambdaExpression GetDynamicSelector<T>(
+      Type masterType,
+      Expression<Func<Run, T>> parentSelector,
+      Expression<Func<T, int>> intSelector,
+      Expression<Func<T, double>> doubleSelector,
+      Expression<Func<T, string>> stringSelector,
+      Expression<Func<T, object>> operatorNameSelector) {
+      if (TableType != masterType)
+        return null;
+      ParameterExpression run = Expression.Parameter(typeof(Run), "run");
+      switch (Type.GetTypeCode(DataType)) {
+        case TypeCode.Int32:
+          return ExpressionTools.CallAfter<Run>(intSelector, parentSelector);
+        case TypeCode.Double:
+          return ExpressionTools.CallAfter<Run>(doubleSelector, parentSelector);
+        case TypeCode.String:
+          return ExpressionTools.CallAfter<Run>(stringSelector, parentSelector);
+        case TypeCode.Object:
+          return ExpressionTools.CallAfter<Run>(operatorNameSelector, parentSelector);
+      };
+      return null;
+    }
+
+    public override string ToString() {
+      StringBuilder sb = new StringBuilder()
+        .Append(TableName)
+        .Append('.')
+        .Append(FieldName);
+      if (MinValue != null)
+        sb.Append(" >").Append(MinValue);
+      if (MaxValue != null)
+        sb.Append(" <").Append(MaxValue);
+      if (AllowedValues != null)
+        sb.Append(" in [")
+          .Append(string.Join(", ",
+                    AllowedValues
+                    .Select(v => v.ToString())
+                    .ToArray()))
+          .Append(']');
+      if (IsHidden)
+        return String.Format("({0})", sb.ToString());
+      else
+        return sb.ToString();
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/DataSetBuilder.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/DataSetBuilder.cs	(revision 4278)
+++ trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/DataSetBuilder.cs	(revision 4278)
@@ -0,0 +1,152 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 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;
+using System.Collections.Generic;
+using System.Data;
+using System.Data.Linq;
+using System.Linq;
+using System.Linq.Expressions;
+using HeuristicLab.Services.OKB.DataAccess;
+
+
+namespace HeuristicLab.Services.OKB.AttributeSelector {
+  public class DataSetBuilder : IEnumerable<DataRow> {
+
+    public static DataSet GetDataSet(OKBDataContext okb, IEnumerable<RunAttributeSelector> selectors) {
+      DataSetBuilder builder = new DataSetBuilder(okb, selectors);
+      DataTable runs = new DataTable("Runs");
+      foreach (DataRow row in builder) {
+        runs.Rows.Add(row);
+      }
+      DataSet dataSet = new DataSet();
+      dataSet.Tables.Add(runs);
+      return dataSet;
+    }
+
+    private IQueryable<Run> query;
+    public DataTable Runs { get; private set; }
+    private IEnumerable<RunAttributeSelector> selectors;
+
+    public DataSetBuilder(OKBDataContext okb, IEnumerable<RunAttributeSelector> selectors) {
+      DataLoadOptions dlo = new DataLoadOptions();
+      query = okb.Runs.AsQueryable();
+      Runs = new DataTable("Runs");
+      this.selectors = selectors;
+
+      foreach (var selector in selectors) {
+        query = query.Where(selector.GetWhereExpression());
+        selector.ConfigureDataLoadOptions(dlo);
+        if (!selector.IsHidden) {
+          AddColumn(selector);
+        }
+      }
+
+      okb.LoadOptions = dlo;
+      Console.WriteLine(query);
+    }
+
+    private void AddColumn(RunAttributeSelector selector) {
+      Type type = selector.DataType;
+      if (type == typeof(object))
+        type = typeof(string);
+      if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
+        type = type.GetGenericArguments()[0];
+      int i = 0;
+      string columnName = selector.FullName;
+      while (Runs.Columns.Contains(columnName)) {
+        i++;
+        columnName = string.Format("{0}({1})", selector.FullName, i);
+      }
+      Runs.Columns.Add(columnName, type);
+    }
+
+    public IEnumerator<DataRow> GetEnumerator() {
+      foreach (var run in query) {
+        DataRow row = Runs.NewRow();
+        int columnNr = 0;
+        foreach (var selector in selectors.Where(s => !s.IsHidden)) {
+          object value = selector.CompiledSelector(run);
+          row[columnNr] = selector.CompiledSelector(run) ?? DBNull.Value;
+          columnNr++;
+        }
+        yield return row;
+      }
+    }
+
+    IEnumerator IEnumerable.GetEnumerator() {
+      return GetEnumerator();
+    }
+
+
+    public int GetCount() {
+      return query.Count();
+    }
+
+    public static IEnumerable<object> GetEntities(OKBDataContext okb, Type tableType, IEnumerable<int> ids) {
+      ITable table = okb.GetTable(tableType);
+
+      // idFilter = element => ids.Contains(element.Id)
+      ParameterExpression param = Expression.Parameter(table.ElementType, "element");
+      LambdaExpression idFilter = Expression.Lambda(
+        Expression.Call(
+          null,
+          ExpressionTools.Enumerable_Contains.MakeGenericMethod(typeof(int)),
+          Expression.Constant(ids),
+          Expression.Property(param, "Id")), param);
+
+      // idSelector = element => element.Id
+      ParameterExpression param2 = Expression.Parameter(table.ElementType, "element");
+      LambdaExpression idSelector = Expression.Lambda(
+        Expression.Property(param2, "Id"), param2);
+
+      // selector = () => okb.<tableType>.Where(idFilter).OrderBy(idSelector).Cast<object>()
+      LambdaExpression selector =
+        Expression.Lambda(
+          Expression.Call(
+            null,
+            ExpressionTools.Enumerable_Cast.MakeGenericMethod(typeof(object)),
+            Expression.Call(
+              null,
+              ExpressionTools.Enumerable_OrderBy.MakeGenericMethod(table.ElementType, typeof(int)),
+              Expression.Call(
+                null,
+                ExpressionTools.Enumerable_Where.MakeGenericMethod(table.ElementType),
+                table.Expression,
+                idFilter),
+             idSelector)));
+      return (IEnumerable<object>)selector.Compile().DynamicInvoke();
+    }
+
+    public static int CountEntities(OKBDataContext okb, Type tableType) {
+      ITable table = okb.GetTable(tableType);
+      // okb.<tableType>.Count();
+      LambdaExpression counter =
+        Expression.Lambda(
+          Expression.Call(
+            null,
+            ExpressionTools.Enumerable_Count.MakeGenericMethod(table.ElementType),
+            table.Expression));
+      return (int)counter.Compile().DynamicInvoke();
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/ExpressionTools.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/ExpressionTools.cs	(revision 4278)
+++ trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/ExpressionTools.cs	(revision 4278)
@@ -0,0 +1,107 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 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 System.Reflection;
+using HeuristicLab.Services.OKB.DataAccess;
+
+namespace HeuristicLab.Services.OKB.AttributeSelector {
+
+  public static class ExpressionTools {
+
+    /// <summary>
+    /// p => f(g(p)) where p : T
+    /// </summary>
+    public static LambdaExpression CallAfter<T>(Expression f, Expression g) {
+      ParameterExpression p = Expression.Parameter(typeof(T), "p");
+      return Expression.Lambda(Expression.Invoke(f, Expression.Invoke(g, p)), p);
+    }
+
+    public static Selector GetSelector<T, D>(Expression<Func<Run, T>> tableSelector, Expression<Func<T, D>> fieldSelector) {
+      Expression member = fieldSelector.Body;
+      while (member is UnaryExpression)
+        member = ((UnaryExpression)member).Operand;
+      if (!(member is MemberExpression))
+        throw new ArgumentException("cannot determine field name");
+      string fieldName = ((MemberExpression)member).Member.Name;
+      return new Selector() {
+        Table = tableSelector.Body.Type,
+        Field = fieldName,
+        Expression = ExpressionTools.CallAfter<Run>(fieldSelector, tableSelector),
+      };
+    }
+
+    public static readonly List<Type> SupportedTypes = new List<Type>() {
+      typeof(int), typeof(double), typeof(DateTime), typeof(Guid) };
+
+    public static BinaryExpression GetLessThanOrEqualExpression<T>(Expression left, Expression right) {
+      if (SupportedTypes.Contains(typeof(T)))
+        return Expression.LessThanOrEqual(left, right);
+      else if (typeof(T) == typeof(string))
+        return Expression.LessThanOrEqual(
+          GetStringComparisonExpression(left, right), Expression.Constant(0));
+      else throw new ArgumentException("Unsupported comparison for types of " + typeof(T));
+    }
+
+    public static BinaryExpression GetGreaterOrEqualExpression<T>(Expression left, Expression right) {
+      if (SupportedTypes.Contains(typeof(T)))
+        return Expression.GreaterThanOrEqual(left, right);
+      else if (typeof(T) == typeof(string))
+        return Expression.GreaterThanOrEqual(
+          GetStringComparisonExpression(left, right), Expression.Constant(0));
+      else throw new ArgumentException("Unsupported comparison for types of " + typeof(T));
+    }
+
+    public static MethodCallExpression GetStringComparisonExpression(Expression left, Expression right) {
+      return Expression.Call(null, String_Compare, left, right);
+    }
+
+    public static readonly MethodInfo String_Compare =
+      typeof(string).GetMethod("Compare", new[] { typeof(string), typeof(string) });
+
+    public static readonly MethodInfo Enumerable_Contains =
+      typeof(Enumerable).GetMethods().Single(mi => mi.Name == "Contains" && mi.GetParameters().Count() == 2);
+
+    public static readonly MethodInfo Enumerable_Single =
+      typeof(Enumerable).GetMethods().Single(mi => mi.Name == "Single" && mi.GetParameters().Count() == 2);
+
+    public static readonly MethodInfo Enumerable_Where =
+      (from mi in typeof(Enumerable).GetMethods()
+       where mi.Name == "Where"
+       let p = mi.GetParameters()
+       where p.Count() == 2
+       let pt = p[1].ParameterType
+       where pt.IsGenericType
+       where pt.GetGenericArguments().Count() == 2
+       select mi).Single();
+
+    public static readonly MethodInfo Enumerable_Cast = typeof(Enumerable).GetMethod("Cast");
+
+    public static readonly MethodInfo Enumerable_OrderBy =
+      typeof(Enumerable).GetMethods().Single(mi => mi.Name == "OrderBy" && mi.GetParameters().Count() == 2);
+
+    public static readonly MethodInfo Enumerable_Count =
+      typeof(Enumerable).GetMethods().Single(mi => mi.Name == "Count" && mi.GetParameters().Count() == 1);
+  }
+}
Index: trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/HeuristicLab.Services.OKB.AttributeSelector-3.3.csproj
===================================================================
--- trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/HeuristicLab.Services.OKB.AttributeSelector-3.3.csproj	(revision 4278)
+++ trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/HeuristicLab.Services.OKB.AttributeSelector-3.3.csproj	(revision 4278)
@@ -0,0 +1,167 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{E80A68DB-D6E1-4395-ABF0-AFE09E4DEF8B}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HeuristicLab.Services.OKB.AttributeSelector</RootNamespace>
+    <AssemblyName>HeuristicLab.Services.OKB.AttributeSelector-3.3</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <OldToolsVersion>3.5</OldToolsVersion>
+    <UpgradeBackupLocation />
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+    <TargetFrameworkProfile />
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>bin\Release\HeuristicLab.Services.OKB.AttributeSelector-3.3.xml</DocumentationFile>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x64\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
+    <OutputPath>bin\x64\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <DocumentationFile>bin\x64\Release\HeuristicLab.Services.OKB.AttributeSelector-3.3.xml</DocumentationFile>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x86\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <OutputPath>bin\x86\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <DocumentationFile>bin\x86\Release\HeuristicLab.Services.OKB.AttributeSelector-3.3.xml</DocumentationFile>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SignAssembly>true</SignAssembly>
+  </PropertyGroup>
+  <PropertyGroup>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="AttributeSelector.cs" />
+    <Compile Include="DataSetBuilder.cs" />
+    <Compile Include="ExpressionTools.cs" />
+    <Compile Include="IAttributeSelector.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <None Include="HeuristicLab.snk" />
+    <None Include="Properties\AssemblyInfo.frame" />
+    <Compile Include="RunAttributeSelector.cs" />
+    <Compile Include="Selector.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+      <Visible>False</Visible>
+      <ProductName>Windows Installer 3.1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\HeuristicLab.Services.OKB.DataAccess\3.3\HeuristicLab.Services.OKB.DataAccess-3.3.csproj">
+      <Project>{E36BE58F-F3CE-40BB-9AB3-9F9E30AD5CCF}</Project>
+      <Name>HeuristicLab.Services.OKB.DataAccess-3.3</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <PropertyGroup>
+    <PreBuildEvent>set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+set ProjectDir=$(ProjectDir)
+set SolutionDir=$(SolutionDir)
+set Outdir=$(Outdir)
+
+call PreBuildEvent.cmd</PreBuildEvent>
+  </PropertyGroup>
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
Index: trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/IAttributeSelector.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/IAttributeSelector.cs	(revision 4278)
+++ trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/IAttributeSelector.cs	(revision 4278)
@@ -0,0 +1,35 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 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.Collections.Generic;
+
+namespace HeuristicLab.Services.OKB.AttributeSelector {
+
+  public interface IAttributeSelector {
+    string TableName { get; }
+    string FieldName { get; }
+    bool IsHidden { get; }
+    object MinValue { get; }
+    object MaxValue { get; }
+    ICollection<object> AllowedValues { get; }
+  }
+
+}
Index: trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/Properties/AssemblyInfo.frame
===================================================================
--- trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/Properties/AssemblyInfo.frame	(revision 4278)
+++ trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/Properties/AssemblyInfo.frame	(revision 4278)
@@ -0,0 +1,57 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 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.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("HeuristicLab.Services.OKB.AttributeSelector")]
+[assembly: AssemblyDescription("Attribute selector for HeuristicLab OKB service")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("HeuristicLab")]
+[assembly: AssemblyCopyright("(c) 2002-2010 HEAL")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("3cbb2cba-f4e7-4e4a-9cb2-1eed8b7e2a24")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("3.3.0.0")]
+[assembly: AssemblyFileVersion("3.3.0.$WCREV$")]
Index: trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/RunAttributeSelector.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/RunAttributeSelector.cs	(revision 4278)
+++ trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/RunAttributeSelector.cs	(revision 4278)
@@ -0,0 +1,327 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 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;
+using System.Collections.Generic;
+using System.Data.Linq;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
+using HeuristicLab.Services.OKB.DataAccess;
+
+namespace HeuristicLab.Services.OKB.AttributeSelector {
+
+  public class AttributeSpecifier {
+    public string TableName { get; set; }
+    public string FieldName { get; set; }
+    public Type DataType { get; set; }
+  }
+
+  public class RunAttributeSelector : AttributeSelector {
+
+    public RunAttributeSelector(OKBDataContext okb, string table, string field)
+      : base(okb, table, field) { }
+
+    public RunAttributeSelector(OKBDataContext okb, IAttributeSelector selector)
+      : base(okb, selector.TableName, selector.FieldName) {
+      IsHidden = selector.IsHidden;
+      MinValue = selector.MinValue;
+      MaxValue = selector.MaxValue;
+      AllowedValues = selector.AllowedValues;
+    }
+
+    protected RunAttributeSelector(Type tableType, string fieldName, bool isDynamic, Type dataType, int parentId)
+      : base(tableType, fieldName, isDynamic, dataType, parentId) { }
+
+    public static IEnumerable<RunAttributeSelector> GetAllAttributeSelectors(OKBDataContext okb) {
+      OKBDataContext o = new OKBDataContext(okb.Connection.ConnectionString);
+      DataLoadOptions dlo = new DataLoadOptions();
+      dlo.LoadWith<Result>(r => r.DataType);
+      dlo.LoadWith<Parameter>(p => p.DataType);
+      dlo.LoadWith<ProblemCharacteristic>(pc => pc.DataType);
+      o.LoadOptions = dlo;
+      foreach (Selector selector in Selectors) {
+        yield return new RunAttributeSelector(o, selector.Table.Name, selector.Field);
+      }
+      foreach (Result result in okb.Results) {
+        yield return new RunAttributeSelector(typeof(Result), result.Name, true, result.DataType.Type, result.Id);
+      }
+      foreach (Parameter p in okb.Parameters) {
+        yield return new RunAttributeSelector(typeof(Parameter), p.Name, true, p.DataType.Type, p.Id);
+      }
+      foreach (ProblemCharacteristic pc in okb.ProblemCharacteristics) {
+        yield return new RunAttributeSelector(typeof(ProblemCharacteristic), pc.Name, true, pc.DataType.Type, pc.Id);
+      }
+    }
+
+    public void ConfigureDataLoadOptions(DataLoadOptions dlo) {
+      if (IsHidden)
+        return;
+      Include(TableType, dlo);
+    }
+
+    private static readonly Dictionary<Type, Type> parents = new Dictionary<Type, Type>() {
+      { typeof(Run), null },
+      { typeof(Client), typeof(Run) },
+      { typeof(User), typeof(Run) },
+      { typeof(Experiment), typeof(Run) },
+      { typeof(ExperimentCreator), typeof(Experiment) },
+      { typeof(Project), typeof(Experiment) },
+      { typeof(Algorithm), typeof(Experiment) },
+      { typeof(AlgorithmClass), typeof(Algorithm) },
+      { typeof(Platform), typeof(Algorithm) },
+      { typeof(Problem), typeof(Experiment) },
+      { typeof(ProblemClass), typeof(Problem) },
+      { typeof(SolutionRepresentation), typeof(Problem) },
+    };
+
+    public static MethodInfo Enumerable_Where =
+      typeof(Enumerable).GetMethods().Single(mi =>
+        mi.Name == "Where" &&
+        mi.GetParameters().Count() == 2 &&
+        mi.GetParameters()[1].ParameterType.GetGenericArguments().Count() == 2);
+
+    public static MethodInfo Enumerable_Cast = typeof(Enumerable).GetMethod("Cast");
+
+    private void AssociateWith<T, V>(DataLoadOptions dlo,
+      Expression<Func<T, IEnumerable>> intSelector,
+      Expression<Func<T, IEnumerable>> doubleSelector,
+      Expression<Func<T, IEnumerable>> charSelector,
+      Expression<Func<T, IEnumerable>> blobSelector,
+      Expression<Func<V, bool>> filterPredicate) {
+      Expression<Func<T, IEnumerable>> selector;
+      switch (Type.GetTypeCode(DataType)) {
+        case TypeCode.Int32: selector = intSelector; break;
+        case TypeCode.Double: selector = doubleSelector; break;
+        case TypeCode.String: selector = charSelector; break;
+        default:
+          if (blobSelector != null)
+            selector = blobSelector;
+          else
+            throw new ArgumentException("DataType");
+          break;
+      }
+      ParameterExpression param = Expression.Parameter(typeof(T), "param");
+      dlo.AssociateWith<T>((Expression<Func<T, object>>)
+        Expression.Lambda(
+          Expression.Convert(
+            Expression.Call(
+              null,
+              Enumerable_Where.MakeGenericMethod(typeof(V)),
+              Expression.Convert(Expression.Invoke(selector, param), typeof(IEnumerable<V>)),
+              filterPredicate),
+          typeof(object)), param));
+      try {
+        dlo.LoadWith(selector);
+      }
+      catch (ArgumentException) {
+        Console.WriteLine("INFO: not adding (duplicate) load option: dlo.LoadWith<{0}>({1})", typeof(T).Name, selector.ToString());
+        Console.WriteLine("INFO: clearing association filters to allow multiple associations");
+        dlo.AssociateWith<T>((Expression<Func<T, object>>)
+          Expression.Lambda(
+            Expression.Convert(
+            Expression.Invoke(selector, param),
+            typeof(object)),
+          param));
+      }
+    }
+
+    private void Include(Type type, DataLoadOptions dlo) {
+      if (parents.ContainsKey(type)) {
+        Type parentType = parents[type];
+        if (parentType == null)
+          return;
+        LoadWith(dlo, parentType, type);
+        Include(parentType, dlo);
+      } else if (type == typeof(ProblemCharacteristic)) {
+        AssociateWith<Problem, IProblemCharacteristicValue>(dlo,
+          p => p.IntProblemCharacteristicValues,
+          p => p.FloatProblemCharacteristicValues,
+          p => p.CharProblemCharacteristicValues,
+          null,
+          pc => pc.ProblemId == ParentId);
+        Include(typeof(Problem), dlo);
+      } else if (type == typeof(Parameter)) {
+        AssociateWith<Experiment, IParameterValue>(dlo,
+          x => x.IntParameterValues,
+          x => x.FloatParameterValues,
+          x => x.CharParameterValues,
+          x => x.OperatorParameterValues,
+          ipv => ipv.ParameterId == ParentId);
+        try {
+          dlo.LoadWith<OperatorParameterValue>(opv => opv.DataType);
+        }
+        catch (ArgumentException) {
+          Console.WriteLine("INFO: not adding (duplicate) load option for OperatorParameterValue.DataType");
+        }
+        Include(typeof(Experiment), dlo);
+      } else if (type == typeof(Result)) {
+        AssociateWith<Run, IResultValue>(dlo,
+          r => r.IntResultValues,
+          r => r.FloatResultValues,
+          r => r.CharResultValues,
+          r => r.BlobResultValues,
+          irv => irv.ResultId == ParentId);
+      } else
+        throw new ArgumentException("type");
+    }
+
+    protected static List<Selector> Selectors = new List<Selector>() {
+        ExpressionTools.GetSelector(run => run, r => r.Id),
+        ExpressionTools.GetSelector(run => run, r => r.FinishedDate),
+
+        ExpressionTools.GetSelector(run => run.Client, c => c.Id),
+        ExpressionTools.GetSelector(run => run.Client, c => c.Name),
+
+        ExpressionTools.GetSelector(run => run.User, u => u.Id),
+        ExpressionTools.GetSelector(run => run.User, u => u.Name),
+
+        ExpressionTools.GetSelector(run => run.Experiment, x => x.Id),
+
+        ExpressionTools.GetSelector(run => run.Experiment.ExperimentCreators.Single(), xc => xc.User.Id),
+        ExpressionTools.GetSelector(run => run.Experiment.ExperimentCreators.Single(), xc => xc.User.Name),
+
+        ExpressionTools.GetSelector(run => run.Experiment.Project, p => p.Id),
+        ExpressionTools.GetSelector(run => run.Experiment.Project, p => p.Name),
+        ExpressionTools.GetSelector(run => run.Experiment.Project, p => p.Description),
+
+        ExpressionTools.GetSelector(run => run.Experiment.Algorithm, a => a.Id),
+        ExpressionTools.GetSelector(run => run.Experiment.Algorithm, a => a.Name),
+        ExpressionTools.GetSelector(run => run.Experiment.Algorithm, a => a.Description),
+
+        ExpressionTools.GetSelector(run => run.Experiment.Algorithm.AlgorithmClass, ac => ac.Id),
+        ExpressionTools.GetSelector(run => run.Experiment.Algorithm.AlgorithmClass, ac => ac.Name),
+        ExpressionTools.GetSelector(run => run.Experiment.Algorithm.AlgorithmClass, ac => ac.Description),
+
+        ExpressionTools.GetSelector(run => run.Experiment.Algorithm.Platform, p => p.Id),
+        ExpressionTools.GetSelector(run => run.Experiment.Algorithm.Platform, p => p.Name),
+        ExpressionTools.GetSelector(run => run.Experiment.Algorithm.Platform, p => p.Description),
+
+        ExpressionTools.GetSelector(run => run.Experiment.Problem, p => p.Id),
+        ExpressionTools.GetSelector(run => run.Experiment.Problem, p => p.Name),
+        ExpressionTools.GetSelector(run => run.Experiment.Problem, p => p.Description),
+
+        ExpressionTools.GetSelector(run => run.Experiment.Problem.ProblemClass, pc => pc.Id),
+        ExpressionTools.GetSelector(run => run.Experiment.Problem.ProblemClass, pc => pc.Name),
+        ExpressionTools.GetSelector(run => run.Experiment.Problem.ProblemClass, pc => pc.Description),
+
+        ExpressionTools.GetSelector(run => run.Experiment.Problem.SolutionRepresentation, sr => sr.Id),
+        ExpressionTools.GetSelector(run => run.Experiment.Problem.SolutionRepresentation, sr => sr.Name),
+        ExpressionTools.GetSelector(run => run.Experiment.Problem.SolutionRepresentation, sr => sr.Description)
+    };
+
+    private Func<Run, object> compiledSelector;
+
+    protected void CreateCompiledSelector<T>() {
+      var genericCompiledSelector = ((Expression<Func<Run, T>>)GetSelectorExpression()).Compile();
+      compiledSelector = run => {
+        try {
+          return (object)genericCompiledSelector(run);
+        }
+        catch (InvalidOperationException x) {
+          if (x.TargetSite == ExpressionTools.Enumerable_Single)
+            return null;
+          else
+            throw;
+        }
+      };
+    }
+
+    public Func<Run, object> CompiledSelector {
+      get {
+        if (compiledSelector == null) {
+          typeof(RunAttributeSelector)
+            .GetMethod("CreateCompiledSelector", BindingFlags.Instance | BindingFlags.NonPublic)
+            .MakeGenericMethod(DataType).Invoke(this, new object[0]);
+        }
+        return compiledSelector;
+      }
+    }
+
+    public LambdaExpression GetSelectorExpression() {
+      if (TableType == typeof(Parameter))
+        return
+          GetDynamicSelector(typeof(Parameter), run => run.Experiment,
+            x => x.IntParameterValues.Single(ipv => ipv.ParameterId == ParentId).Value,
+            x => x.FloatParameterValues.Single(fpv => fpv.ParameterId == ParentId).Value,
+            x => x.CharParameterValues.Single(cpv => cpv.ParameterId == ParentId).Value,
+            x => x.OperatorParameterValues.Single(opv => opv.ParameterId == ParentId).DataType.ClrName);
+      else if (TableType == typeof(Result))
+        return
+          GetDynamicSelector(typeof(Result), run => run,
+            r => r.IntResultValues.Single(irv => irv.ResultId == ParentId).Value,
+            r => r.FloatResultValues.Single(frv => frv.ResultId == ParentId).Value,
+            r => r.CharResultValues.Single(crv => crv.ResultId == ParentId).Value,
+            null);
+      else if (TableType == typeof(ProblemCharacteristic))
+        return
+          GetDynamicSelector(typeof(ProblemCharacteristic), run => run.Experiment.Problem,
+            p => p.IntProblemCharacteristicValues.Single(ipcv => ipcv.ProblemCharacteristicId == ParentId).Value,
+            p => p.FloatProblemCharacteristicValues.Single(fpcv => fpcv.ProblemCharacteristicId == ParentId).Value,
+            p => p.CharProblemCharacteristicValues.Single(cpcv => cpcv.ProblemCharacteristicId == ParentId).Value,
+            null);
+      else
+        return Selectors.Single(s => s.Table == TableType && s.Field == FieldName).Expression;
+    }
+
+    public Expression<Func<Run, bool>> GetWhereExpression() {
+      return GetWhereExpression(GetSelectorExpression());
+    }
+
+    protected Expression<Func<Run, bool>> GetWhereExpression(Expression selector) {
+      try {
+        return (Expression<Func<Run, bool>>)typeof(RunAttributeSelector)
+          .GetMethod("GenericGetWhereExpression", BindingFlags.Instance | BindingFlags.NonPublic)
+          .MakeGenericMethod(selector.Type.GetGenericArguments()[1])
+          .Invoke(this, new[] { selector });
+      }
+      catch (TargetInvocationException x) {
+        throw x.InnerException;
+      }
+    }
+
+    protected Expression<Func<Run, bool>> GenericGetWhereExpression<T>(Expression<Func<Run, T>> selector) {
+      ParameterExpression parameter = Expression.Parameter(typeof(Run), "run");
+      Expression testExpression = Expression.Constant(true);
+      if (AllowedValues != null) {
+        testExpression = Expression.AndAlso(testExpression,
+          Expression.Call(
+            null,
+            ExpressionTools.Enumerable_Contains.MakeGenericMethod(typeof(T)),
+            Expression.Constant(AllowedValues.Cast<T>().ToArray()),
+            Expression.Invoke(selector, parameter)));
+      }
+      if (MinValue != null) {
+        testExpression = Expression.AndAlso(testExpression,
+          ExpressionTools.GetLessThanOrEqualExpression<T>(Expression.Constant(MinValue),
+          Expression.Invoke(selector, parameter)));
+      }
+      if (MaxValue != null) {
+        testExpression = Expression.AndAlso(testExpression,
+          ExpressionTools.GetGreaterOrEqualExpression<T>(Expression.Constant(MaxValue),
+          Expression.Invoke(selector, parameter)));
+      }
+      return (Expression<Func<Run, bool>>)
+        Expression.Lambda(testExpression, parameter);
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/Selector.cs
===================================================================
--- trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/Selector.cs	(revision 4278)
+++ trunk/sources/HeuristicLab.Services.OKB.AttributeSelector/3.3/Selector.cs	(revision 4278)
@@ -0,0 +1,32 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 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.Linq.Expressions;
+
+namespace HeuristicLab.Services.OKB.AttributeSelector {
+
+  public class Selector {
+    public Type Table { get; set; }
+    public string Field { get; set; }
+    public LambdaExpression Expression { get; set; }
+  }
+}
