#region License Information /* HeuristicLab * Copyright (C) 2002-2008 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.Generic; using System.Linq; using System.Reflection; using HeuristicLab.Core; using HeuristicLab.DataAnalysis; using HeuristicLab.Data; using System.Data.Linq; namespace HeuristicLab.Modeling.Database.SQLServerCompact { public class DatabaseService : IModelingDatabase { private readonly string fileName; public DatabaseService(string fileName) { this.fileName = fileName; this.readOnly = false; } public DatabaseService(string fileName, bool readOnly) : this(fileName) { this.readOnly = readOnly; } private string ConnectionString { get { string connection = "Data Source =" + fileName + ";"; if (this.readOnly) connection += "File Mode = Read Only; Temp Path =" + System.IO.Path.GetTempPath() + ";"; else connection += "File Mode = Shared Read;"; return connection; } } private bool readOnly; public bool ReadOnly { get { return this.readOnly; } set { if (ctx != null) throw new InvalidOperationException("Could not change readonly attribute of DatabaseService because connection is opened."); this.readOnly = value; } } public void EmptyDatabase() { ctx.Connection.Dispose(); ctx.DeleteDatabase(); Connect(); ctx.CreateDatabase(); Disconnect(); } private ModelingDataContext ctx; public void Connect() { if (ctx != null) Disconnect(); ctx = new ModelingDataContext(this.ConnectionString); DataLoadOptions dlo = new DataLoadOptions(); dlo.LoadWith(mr => mr.Result); dlo.LoadWith(mmd => mmd.MetaData); dlo.LoadWith(ir => ir.Variable); dlo.LoadWith(ir => ir.Result); dlo.LoadWith(m => m.TargetVariable); dlo.LoadWith(m => m.Algorithm); ctx.LoadOptions = dlo; if (!ctx.DatabaseExists()) ctx.CreateDatabase(); } public void Disconnect() { if (ctx == null) return; ctx.Connection.Dispose(); ctx.Dispose(); ctx = null; } public IEnumerable GetAllModels() { return ctx.Models.ToList().Cast(); } public IEnumerable GetAllModelIds() { return from m in ctx.Models select m.Id; } public IEnumerable GetAllVariables() { return ctx.Variables.ToList().Cast(); } public IEnumerable GetAllResults() { return ctx.Results.ToList().Cast(); } public IEnumerable GetAllResultsForInputVariables() { return (from ir in ctx.InputVariableResults select ir.Result).Distinct().ToList().Cast(); } public IEnumerable GetAllMetaData() { return ctx.MetaData.ToList().Cast(); } public IEnumerable GetAllAlgorithms() { return ctx.Algorithms.ToList().Cast(); } public IModel CreateModel(int id, string modelName, ModelType modelType, IAlgorithm algorithm, IVariable targetVariable, int trainingSamplesStart, int trainingSamplesEnd, int validationSamplesStart, int validationSamplesEnd, int testSamplesStart, int testSamplesEnd) { Model m = (Model)CreateModel(modelName, modelType, algorithm, targetVariable, trainingSamplesStart, trainingSamplesEnd, validationSamplesStart, validationSamplesEnd, testSamplesStart, testSamplesEnd); m.Id = id; return m; } public IModel CreateModel(string modelName, ModelType modelType, IAlgorithm algorithm, IVariable targetVariable, int trainingSamplesStart, int trainingSamplesEnd, int validationSamplesStart, int validationSamplesEnd, int testSamplesStart, int testSamplesEnd) { Variable target = (Variable)targetVariable; Algorithm algo = (Algorithm)algorithm; Model model = new Model(target, algo, modelType); model.Name = modelName; model.TrainingSamplesStart = trainingSamplesStart; model.TrainingSamplesEnd = trainingSamplesEnd; model.ValidationSamplesStart = validationSamplesStart; model.ValidationSamplesEnd = validationSamplesEnd; model.TestSamplesStart = testSamplesStart; model.TestSamplesEnd = testSamplesEnd; return model; } public IModel GetModel(int id) { var model = ctx.Models.Where(m => m.Id == id); if (model.Count() == 1) return model.Single(); return null; } public void PersistModel(IModel model) { using (ModelingDataContext ctx = new ModelingDataContext(this.ConnectionString)) { Model m = (Model)model; //check if model has to be updated or inserted if (ctx.Models.Any(x => x.Id == model.Id)) { Model orginal = ctx.Models.GetOriginalEntityState(m); if (orginal == null) ctx.Models.Attach(m); ctx.Refresh(RefreshMode.KeepCurrentValues, m); } else ctx.Models.InsertOnSubmit(m); ctx.SubmitChanges(); } } public void DeleteModel(IModel model) { Model m = (Model)model; ctx.ModelData.DeleteAllOnSubmit(ctx.ModelData.Where(x => x.Model == m)); ctx.ModelMetaData.DeleteAllOnSubmit(ctx.ModelMetaData.Where(x => x.Model == m)); ctx.ModelResults.DeleteAllOnSubmit(ctx.ModelResults.Where(x => x.Model == m)); ctx.InputVariableResults.DeleteAllOnSubmit(ctx.InputVariableResults.Where(x => x.Model == m)); ctx.InputVariables.DeleteAllOnSubmit(ctx.InputVariables.Where(x => x.Model == m)); Model orginal = ctx.Models.GetOriginalEntityState(m); if (orginal == null) ctx.Models.Attach(m); ctx.Models.DeleteOnSubmit(m); ctx.SubmitChanges(); } public Dataset GetDataset() { if (ctx.Problems.Count() > 1) throw new InvalidOperationException("Could not get dataset. More than one problems are persisted in the database."); if (ctx.Problems.Count() == 1) return ctx.Problems.Single().Dataset; return null; } public void PersistProblem(Dataset dataset) { Problem problem; using (ModelingDataContext ctx = new ModelingDataContext(this.ConnectionString)) { if (ctx.Problems.Count() != 0) throw new InvalidOperationException("Could not persist dataset. A dataset is already saved in the database."); problem = new Problem(dataset); ctx.Problems.InsertOnSubmit(problem); foreach (string variable in dataset.VariableNames) { ctx.Variables.InsertOnSubmit(new Variable(variable)); } ctx.SubmitChanges(); } } public IVariable GetVariable(string variableName) { var variables = ctx.Variables.Where(v => v.Name == variableName); if (variables.Count() != 1) throw new ArgumentException("Zero or more than one variable with the name " + variableName + " are persisted in the database."); return variables.Single(); } public IPredictor GetModelPredictor(IModel model) { var data = (from md in ctx.ModelData where md.Model == model select md); if (data.Count() != 1) throw new ArgumentException("No predictor persisted for given model!"); return (IPredictor)PersistenceManager.RestoreFromGZip(data.Single().Data); } public void PersistPredictor(IModel model, IPredictor predictor) { using (ModelingDataContext ctx = new ModelingDataContext(this.ConnectionString)) { Model m = (Model)model; ctx.ModelData.DeleteAllOnSubmit(ctx.ModelData.Where(x => x.Model == m)); ctx.ModelResults.DeleteAllOnSubmit(ctx.ModelResults.Where(x => x.Model == m)); ctx.InputVariableResults.DeleteAllOnSubmit(ctx.InputVariableResults.Where(x => x.Model == m)); ctx.InputVariables.DeleteAllOnSubmit(ctx.InputVariables.Where(x => x.Model == m)); ctx.ModelData.InsertOnSubmit(new ModelData(m, PersistenceManager.SaveToGZip(predictor))); foreach (string variableName in predictor.GetInputVariables()) ctx.InputVariables.InsertOnSubmit(new InputVariable(m, (Variable)GetVariable(variableName))); ctx.SubmitChanges(); } } public IInputVariable GetInputVariable(IModel model, string inputVariableName) { var inputVariables = ctx.InputVariables.Where(i => i.Model == model && i.Variable.Name == inputVariableName); if (inputVariables.Count() == 1) return inputVariables.Single(); if (inputVariables.Count() > 1) throw new ArgumentException("More than one input variable with the same name are for the given model persisted."); return null; } public IAlgorithm GetOrPersistAlgorithm(string algorithmName) { Algorithm algorithm; using (ModelingDataContext ctx = new ModelingDataContext(this.ConnectionString)) { var algorithms = ctx.Algorithms.Where(algo => algo.Name == algorithmName); if (algorithms.Count() == 0) { algorithm = new Algorithm(algorithmName, ""); ctx.Algorithms.InsertOnSubmit(algorithm); ctx.SubmitChanges(); } else if (algorithms.Count() == 1) algorithm = algorithms.Single(); else throw new ArgumentException("Could not get Algorithm. More than one algorithm with the name " + algorithmName + " are saved in database."); } return algorithm; } public IResult GetOrPersistResult(string resultName) { Result result; using (ModelingDataContext ctx = new ModelingDataContext(this.ConnectionString)) { var results = ctx.Results.Where(r => r.Name == resultName); if (results.Count() == 0) { result = new Result(resultName); ctx.Results.InsertOnSubmit(result); ctx.SubmitChanges(); } else if (results.Count() == 1) result = results.Single(); else throw new ArgumentException("Could not get result. More than one result with the name " + resultName + " are saved in database."); } return result; } public IMetaData GetOrPersistMetaData(string metaDataName) { MetaData metadata; using (ModelingDataContext ctx = new ModelingDataContext(this.ConnectionString)) { var md = ctx.MetaData.Where(r => r.Name == metaDataName); if (md.Count() == 0) { metadata = new MetaData(metaDataName); ctx.MetaData.InsertOnSubmit(metadata); ctx.SubmitChanges(); } else if (md.Count() == 1) metadata = md.Single(); else throw new ArgumentException("Could not get metadata. More than one metadata with the name " + metaDataName + " are saved in database."); } return metadata; } public IEnumerable GetModelResults(IModel model) { return ctx.ModelResults.Where(mr => mr.Model == model).Cast(); } public IEnumerable GetInputVariableResults(IModel model) { return ctx.InputVariableResults.Where(ivr => ivr.Model == model).Cast(); } public IEnumerable GetModelMetaData(IModel model) { return ctx.ModelMetaData.Where(md => md.Model == model).Cast(); } public IModelResult CreateModelResult(IModel model, IResult result, double value) { Model m = (Model)model; Result r = (Result)result; return new ModelResult(m, r, value); } public void PersistModelResults(IModel model, IEnumerable modelResults) { using (ModelingDataContext ctx = new ModelingDataContext(this.ConnectionString)) { ctx.ModelResults.DeleteAllOnSubmit(GetModelResults(model).Cast()); ctx.ModelResults.InsertAllOnSubmit(modelResults.Cast()); ctx.SubmitChanges(); } } public IInputVariable CreateInputVariable(IModel model, IVariable variable) { InputVariable inputVariable = new InputVariable((Model)model, (Variable)variable); return inputVariable; } public IInputVariableResult CreateInputVariableResult(IInputVariable inputVariable, IResult result, double value) { InputVariable i = (InputVariable)inputVariable; Result r = (Result)result; return new InputVariableResult(i, r, value); } public void PersistInputVariableResults(IModel model, IEnumerable inputVariableResults) { using (ModelingDataContext ctx = new ModelingDataContext(this.ConnectionString)) { ctx.InputVariableResults.DeleteAllOnSubmit(GetInputVariableResults(model).Cast()); ctx.InputVariableResults.InsertAllOnSubmit(inputVariableResults.Cast()); ctx.SubmitChanges(); } } public IModelMetaData CreateModelMetaData(IModel model, IMetaData metadata, double value) { Model m = (Model)model; MetaData md = (MetaData)metadata; return new ModelMetaData(m, md, value); } public void PersistModelMetaData(IModel model, IEnumerable modelMetaData) { using (ModelingDataContext ctx = new ModelingDataContext(this.ConnectionString)) { ctx.ModelMetaData.DeleteAllOnSubmit(GetModelMetaData(model).Cast()); ctx.ModelMetaData.InsertAllOnSubmit(modelMetaData.Cast()); ctx.SubmitChanges(); } } public IModel Persist(HeuristicLab.Modeling.IAlgorithm algorithm) { if (ctx.Problems.Count() == 0) PersistProblem(algorithm.Dataset); return Persist(algorithm.Model, algorithm.Name, algorithm.Description); } public IModel Persist(HeuristicLab.Modeling.IAnalyzerModel model, string algorithmName, string algorithmDescription) { Algorithm algorithm = (Algorithm)GetOrPersistAlgorithm(algorithmName); Variable targetVariable = (Variable)GetVariable(model.TargetVariable); Model m = (Model)CreateModel(null, model.Type, algorithm, targetVariable, model.TrainingSamplesStart, model.TrainingSamplesEnd, model.ValidationSamplesStart, model.ValidationSamplesEnd, model.TestSamplesStart, model.TestSamplesEnd); using (ModelingDataContext ctx = new ModelingDataContext(this.ConnectionString)) { ctx.Models.InsertOnSubmit(m); ctx.SubmitChanges(); ctx.ModelData.InsertOnSubmit(new ModelData(m, PersistenceManager.SaveToGZip(model.Predictor))); foreach (string variableName in model.Predictor.GetInputVariables()) ctx.InputVariables.InsertOnSubmit(new InputVariable(m, (Variable)GetVariable(variableName))); foreach (KeyValuePair pair in model.MetaData) { MetaData metaData = (MetaData)GetOrPersistMetaData(pair.Key); ctx.ModelMetaData.InsertOnSubmit(new ModelMetaData(m, metaData, pair.Value)); } foreach (KeyValuePair pair in model.Results) { Result result = (Result)GetOrPersistResult(pair.Key.ToString()); ctx.ModelResults.InsertOnSubmit(new ModelResult(m, result, pair.Value)); } foreach (InputVariable variable in ctx.InputVariables.Where(iv => iv.Model == m)) { foreach (KeyValuePair variableResult in model.GetVariableResults(variable.Variable.Name)) { Result result = (Result)GetOrPersistResult(variableResult.Key.ToString()); ctx.InputVariableResults.InsertOnSubmit(new InputVariableResult(variable, result, variableResult.Value)); } } ctx.SubmitChanges(); } //if connected to database return inserted model if (this.ctx != null) return this.ctx.Models.Where(x => x.Id == m.Id).Single(); return null; } } }