#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 . */ #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.AttributeSelection { 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 GetAllAttributeSelectors(OKBDataContext okb) { OKBDataContext o = new OKBDataContext(okb.Connection.ConnectionString); DataLoadOptions dlo = new DataLoadOptions(); dlo.LoadWith(r => r.DataType); dlo.LoadWith(p => p.DataType); dlo.LoadWith(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 parents = new Dictionary() { { typeof(Run), null }, { typeof(Client), typeof(Run) }, { typeof(User), typeof(Run) }, { typeof(Experiment), typeof(Run) }, { 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(DataLoadOptions dlo, Expression> intSelector, Expression> doubleSelector, Expression> charSelector, Expression> blobSelector, Expression> filterPredicate) { Expression> 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((Expression>) Expression.Lambda( Expression.Convert( Expression.Call( null, Enumerable_Where.MakeGenericMethod(typeof(V)), Expression.Convert(Expression.Invoke(selector, param), typeof(IEnumerable)), 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((Expression>) 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(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(dlo, x => x.IntParameterValues, x => x.FloatParameterValues, x => x.CharParameterValues, x => x.OperatorParameterValues, ipv => ipv.ParameterId == ParentId); try { dlo.LoadWith(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(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 Selectors = new List() { 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.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 compiledSelector; protected void CreateCompiledSelector() { var genericCompiledSelector = ((Expression>)GetSelectorExpression()).Compile(); compiledSelector = run => { try { return (object)genericCompiledSelector(run); } catch (InvalidOperationException x) { if (x.TargetSite == ExpressionTools.Enumerable_Single) return null; else throw; } }; } public Func 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> GetWhereExpression() { return GetWhereExpression(GetSelectorExpression()); } protected Expression> GetWhereExpression(Expression selector) { try { return (Expression>)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> GenericGetWhereExpression(Expression> 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().ToArray()), Expression.Invoke(selector, parameter))); } if (MinValue != null) { testExpression = Expression.AndAlso(testExpression, ExpressionTools.GetLessThanOrEqualExpression(Expression.Constant(MinValue), Expression.Invoke(selector, parameter))); } if (MaxValue != null) { testExpression = Expression.AndAlso(testExpression, ExpressionTools.GetGreaterOrEqualExpression(Expression.Constant(MaxValue), Expression.Invoke(selector, parameter))); } return (Expression>) Expression.Lambda(testExpression, parameter); } } }