// Copyright (C) Stichting Deltares 2016. All rights reserved. // // This file is part of Ringtoets. // // Ringtoets 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. // // This program 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 this program. If not, see . // // All names, logos, and references to "Deltares" are registered trademarks of // Stichting Deltares and remain full property of Stichting Deltares at all times. // All rights reserved. using System; using System.Data; using System.Data.Entity; using System.IO; using System.Linq; using Application.Ringtoets.Storage.Create; using Application.Ringtoets.Storage.DbContext; using Application.Ringtoets.Storage.Exceptions; using Application.Ringtoets.Storage.Properties; using Application.Ringtoets.Storage.Read; using Application.Ringtoets.Storage.Update; using Core.Common.Base.Data; using Core.Common.Base.Storage; using Core.Common.Utils; using Core.Common.Utils.Builders; using UtilsResources = Core.Common.Utils.Properties.Resources; namespace Application.Ringtoets.Storage { /// /// This class interacts with an SQLite database file using the Entity Framework. /// public class StorageSqLite : IStoreProject { private string filePath; private string connectionString; public string FileFilter { get { return Resources.Ringtoets_project_file_filter; } } /// /// Converts to a new in the database. /// /// Path to database file. /// to save. /// Returns the number of changes that were saved in . /// Thrown when is null. /// is invalid. /// Thrown when /// /// The database does not contain the table version /// THe file was not created. /// Saving the to the database failed. /// The connection to the database file failed. /// /// public int SaveProjectAs(string databaseFilePath, Project project) { if (project == null) { throw new ArgumentNullException("project"); } SetConnectionToNewFile(databaseFilePath); using (var dbContext = new RingtoetsEntities(connectionString)) { try { var collector = new CreateConversionCollector(); dbContext.ProjectEntities.Add(project.Create(collector)); var changes = dbContext.SaveChanges(); collector.TransferIds(); project.Name = Path.GetFileNameWithoutExtension(databaseFilePath); return changes; } catch (DataException exception) { throw CreateStorageWriterException(Resources.Error_Update_Database, exception); } catch (SystemException exception) { if (exception is InvalidOperationException || exception is NotSupportedException) { throw CreateStorageWriterException(Resources.Error_During_Connection, exception); } throw; } } } /// /// Converts to an existing in the database. /// /// Path to database file. /// to save. /// Returns the number of changes that were saved in . /// Thrown when is null. /// is invalid. /// Thrown when /// /// does not exist. /// The database does not contain the table version. /// Saving the to the database failed. /// The connection to the database file failed. /// The related entity was not found in the database. Therefore, no update was possible. /// /// public int SaveProject(string databaseFilePath, Project project) { if (project == null) { throw new ArgumentNullException("project"); } SetConnectionToFile(databaseFilePath); using (var dbContext = new RingtoetsEntities(connectionString)) { try { var updateCollector = new CreateConversionCollector(); project.Update(updateCollector, dbContext); updateCollector.RemoveUntouched(dbContext); var changes = dbContext.SaveChanges(); updateCollector.TransferIds(); return changes; } catch (EntityNotFoundException e) { throw CreateStorageWriterException(e.Message, e); } catch (DataException exception) { throw CreateStorageWriterException(Resources.Error_Update_Database, exception); } catch (SystemException exception) { if (exception is InvalidOperationException || exception is NotSupportedException) { throw CreateStorageWriterException(Resources.Error_During_Connection, exception); } throw; } } } /// /// Attempts to load the from the SQLite database. /// /// Path to database file. /// Returns a new instance of with the data from the database or null when not found. /// is invalid. /// Thrown when /// /// does not exist. /// The database does not contain all requested tables. /// The connection to the database file failed. /// The related entity was not found in the database. /// /// public Project LoadProject(string databaseFilePath) { SetConnectionToFile(databaseFilePath); try { using (var dbContext = new RingtoetsEntities(connectionString)) { var projectEntity = GetSingleProject(dbContext); if (projectEntity == null) { throw CreateStorageReaderException(Resources.StorageSqLite_LoadProject_Invalid_Ringtoets_database_file); } var project = projectEntity.Read(new ReadConversionCollector()); project.Name = Path.GetFileNameWithoutExtension(databaseFilePath); return project; } } catch (DataException exception) { throw CreateStorageReaderException(string.Empty, exception); } catch (SystemException exception) { throw CreateStorageReaderException(string.Empty, exception); } } public bool HasChanges(Project project) { if (string.IsNullOrWhiteSpace(connectionString)) { return true; } using (var dbContext = new RingtoetsEntities(connectionString)) { try { var updateConversionCollector = new CreateConversionCollector(); project.Update(updateConversionCollector, dbContext); updateConversionCollector.RemoveUntouched(dbContext); return dbContext.ChangeTracker.HasChanges(); } catch (EntityNotFoundException) {} catch (SystemException) {} return false; } } private ProjectEntity GetSingleProject(RingtoetsEntities dbContext) { try { return dbContext.ProjectEntities.Single(); } catch (InvalidOperationException) { return null; } } /// /// Throws a configured instance of when writing to the storage file failed. /// /// The critical error message. /// Optional: exception that caused this exception to be thrown. /// Returns a new . private StorageException CreateStorageWriterException(string errorMessage, Exception innerException = null) { var message = new FileWriterErrorMessageBuilder(filePath).Build(errorMessage); return new StorageException(message, innerException); } /// /// Throws a configured instance of when reading the storage file failed. /// /// The critical error message. /// Optional: exception that caused this exception to be thrown. /// Returns a new . private StorageException CreateStorageReaderException(string errorMessage, Exception innerException = null) { var message = new FileReaderErrorMessageBuilder(filePath).Build(errorMessage); return new StorageException(message, innerException); } /// /// Attempts to set the connection to an existing storage file . /// /// Path to database file. /// is invalid. /// Thrown when: /// does not exist /// the database does not contain the table version. /// /// private void SetConnectionToFile(string databaseFilePath) { FileUtils.ValidateFilePath(databaseFilePath); filePath = databaseFilePath; if (!File.Exists(databaseFilePath)) { throw CreateStorageReaderException(string.Empty, new CouldNotConnectException(UtilsResources.Error_File_does_not_exist)); } connectionString = SqLiteConnectionStringBuilder.BuildSqLiteEntityConnectionString(databaseFilePath); ValidateStorage(); } /// /// Sets the connection to a newly created (empty) Ringtoets database file. /// /// Path to database file. /// is invalid. /// Thrown when: /// was not created /// executing DatabaseStructure script failed /// the database does not contain the table version. /// /// private void SetConnectionToNewFile(string databaseFilePath) { StorageSqliteCreator.CreateDatabaseStructure(databaseFilePath); SetConnectionToFile(databaseFilePath); } /// /// Validates if the connected storage is a valid Ringtoets database. /// /// Thrown when the database does not contain the table version. private void ValidateStorage() { using (var dbContext = new RingtoetsEntities(connectionString)) { try { dbContext.Database.Initialize(true); dbContext.VersionEntities.Load(); } catch (Exception exception) { throw CreateStorageReaderException(string.Empty, new StorageValidationException(string.Format(Resources.Error_Validating_Database_0, filePath), exception)); } } } } }