// 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.Collections.Generic;
using System.Linq;
using Application.Ringtoets.Storage.DbContext;
using Core.Common.Base.Data;
using Core.Common.Base.Geometry;
using Core.Common.Utils;
using Ringtoets.Common.Data.Calculation;
using Ringtoets.Common.Data.FailureMechanism;
using Ringtoets.HydraRing.Data;
using Ringtoets.Integration.Data;
using Ringtoets.Piping.Data;
using Ringtoets.Piping.Primitives;
namespace Application.Ringtoets.Storage.Create
{
///
/// This class can be used to keep track of create and update operations on a database.
/// This information can be used to reuse objects. When all operations have been performed,
/// then the collected information can be used to transfer the ids assigned to the created
/// database instances back to the data model or to clean up orphans.
///
internal class PersistenceRegistry
{
private readonly Dictionary projects = new Dictionary(new ReferenceEqualityComparer());
private readonly Dictionary assessmentSections = new Dictionary(new ReferenceEqualityComparer());
private readonly Dictionary failureMechanisms = new Dictionary(new ReferenceEqualityComparer());
private readonly Dictionary failureMechanismSections = new Dictionary();
private readonly Dictionary hydraulicLocations = new Dictionary(new ReferenceEqualityComparer());
private readonly Dictionary calculationGroups = new Dictionary(new ReferenceEqualityComparer());
private readonly Dictionary pipingCalculations = new Dictionary(new ReferenceEqualityComparer());
private readonly Dictionary stochasticSoilModels = new Dictionary(new ReferenceEqualityComparer());
private readonly Dictionary stochasticSoilProfiles = new Dictionary(new ReferenceEqualityComparer());
private readonly Dictionary soilProfiles = new Dictionary(new ReferenceEqualityComparer());
private readonly Dictionary soilLayers = new Dictionary(new ReferenceEqualityComparer());
private readonly Dictionary surfaceLines = new Dictionary(new ReferenceEqualityComparer());
private readonly Dictionary surfaceLinePoints = new Dictionary(new ReferenceEqualityComparer());
private readonly Dictionary characteristicPoints = new Dictionary(new ReferenceEqualityComparer());
private readonly Dictionary pipingProbabilityAssessmentInputs = new Dictionary(new ReferenceEqualityComparer());
///
/// Registers a create or update operation for and the
/// that was constructed with the information.
///
/// The that was registered.
/// The which needed to registered.
/// Thrown when either:
///
/// - is null
/// - is null
///
public void Register(FailureMechanismSectionEntity entity, FailureMechanismSection model)
{
Register(failureMechanismSections, entity, model);
}
///
/// Registers a create or update operation for and the
/// that was constructed with the information.
///
/// The that was registered.
/// The which needed to registered.
/// Thrown when either:
///
/// - is null
/// - is null
///
public void Register(CalculationGroupEntity entity, CalculationGroup model)
{
Register(calculationGroups, entity, model);
}
///
/// Registers a create or update operation for and the
/// that was constructed with the information.
///
/// The that was registered.
/// The which needed to registered.
/// Thrown when either:
///
/// - is null
/// - is null
///
public void Register(PipingCalculationEntity entity, PipingCalculationScenario model)
{
Register(pipingCalculations, entity, model);
}
///
/// Registers a create or update operation for and the
/// that was constructed with the information.
///
/// The that was registered.
/// The which needed to be registered.
/// Thrown when either:
///
/// - is null
/// - is null
///
internal void Register(ProjectEntity entity, Project model)
{
Register(projects, entity, model);
}
///
/// Registers a create or update operation for and the
/// that was constructed with the information.
///
/// The that was registered.
/// The which needed to be registered.
/// Thrown when either:
///
/// - is null
/// - is null
///
internal void Register(AssessmentSectionEntity entity, AssessmentSection model)
{
Register(assessmentSections, entity, model);
}
///
/// Registers a create or update operation for and the
/// that was constructed with the information.
///
/// The that was registered.
/// The which needed to be registered.
/// Thrown when either:
///
/// - is null
/// - is null
///
internal void Register(HydraulicLocationEntity entity, HydraulicBoundaryLocation model)
{
Register(hydraulicLocations, entity, model);
}
///
/// Registers a create or update operation for and the
/// that was constructed with the information.
///
/// The that was registered.
/// The which needed to be registered.
/// Thrown when either:
///
/// - is null
/// - is null
///
internal void Register(FailureMechanismEntity entity, IFailureMechanism model)
{
Register(failureMechanisms, entity, model);
}
///
/// Registers a create or update operation for and the
/// that was constructed with the information.
///
/// The that was registered.
/// The which needed to be registered.
/// Thrown when either:
///
/// - is null
/// - is null
///
internal void Register(StochasticSoilModelEntity entity, StochasticSoilModel model)
{
Register(stochasticSoilModels, entity, model);
}
///
/// Registers a create or update operation for and the
/// that was constructed with the information.
///
/// The that was registered.
/// The which needed to be registered.
/// Thrown when either:
///
/// - is null
/// - is null
///
internal void Register(StochasticSoilProfileEntity entity, StochasticSoilProfile model)
{
Register(stochasticSoilProfiles, entity, model);
}
///
/// Registers a create or update operation for and the
/// that was constructed with the information.
///
/// The that was registered.
/// The which needed to be registered.
/// Thrown when either:
///
/// - is null
/// - is null
///
internal void Register(SoilProfileEntity entity, PipingSoilProfile model)
{
Register(soilProfiles, entity, model);
}
///
/// Registers a create or update operation for and the
/// that was constructed with the information.
///
/// The that was registered.
/// The which needed to be registered.
/// Thrown when either:
///
/// - is null
/// - is null
///
internal void Register(SoilLayerEntity entity, PipingSoilLayer model)
{
Register(soilLayers, entity, model);
}
///
/// Checks whether a create or update operations has been registered for the given
/// .
///
/// The to check for.
/// true if the was created before, false otherwise.
/// Thrown when is null.
internal bool Contains(StochasticSoilModel model)
{
return ContainsValue(stochasticSoilModels, model);
}
///
/// Checks whether a create or update operations has been registered for the given
/// .
///
/// The to check for.
/// true if the was created before, false otherwise.
/// Thrown when is null.
internal bool Contains(StochasticSoilProfile model)
{
return ContainsValue(stochasticSoilProfiles, model);
}
///
/// Checks whether a create or update operations has been registered for the given
/// .
///
/// The to check for.
/// true if the was created before, false otherwise.
/// Thrown when is null.
internal bool Contains(PipingSoilProfile model)
{
return ContainsValue(soilProfiles, model);
}
///
/// Checks whether a create or update operations has been registered for the given
/// .
///
/// The to check for.
/// true if the was created before, false otherwise.
/// Thrown when is null.
internal bool Contains(HydraulicBoundaryLocation model)
{
return ContainsValue(hydraulicLocations, model);
}
///
/// Checks whether a create or update operations has been registered for the given
/// .
///
/// The to check for.
/// true if the was created before, false otherwise.
/// Thrown when is null.
internal bool Contains(RingtoetsPipingSurfaceLine model)
{
return ContainsValue(surfaceLines, model);
}
///
/// Obtains the which was registered for
/// the given .
///
/// The for which a read/update
/// operation has been registered.
/// The created .
/// Thrown when is null.
/// Thrown when no create operation
/// has been registered for .
/// Use to find out whether
/// a create operation has been registered for .
internal StochasticSoilModelEntity Get(StochasticSoilModel model)
{
return Get(stochasticSoilModels, model);
}
///
/// Obtains the which was registered for
/// the given .
///
/// The for which a read/update
/// operation has been registered.
/// The created .
/// Thrown when is null.
/// Thrown when no create operation
/// has been registered for .
/// Use to find out whether
/// a create operation has been registered for .
internal StochasticSoilProfileEntity Get(StochasticSoilProfile model)
{
return Get(stochasticSoilProfiles, model);
}
///
/// Obtains the which was registered for the given
/// .
///
/// The for which a read operation has been registered.
/// The constructed .
/// Thrown when is null.
/// Thrown when no create operation
/// has been registered for .
/// Use to find out whether a create operation has
/// been registered for .
internal SoilProfileEntity Get(PipingSoilProfile model)
{
return Get(soilProfiles, model);
}
///
/// Obtains the which was registered for the given
/// .
///
/// The for which a
/// read/update operation has been registered.
/// The constructed .
/// Thrown when is null.
/// Thrown when no create/update operation
/// has been registered for .
/// Use to find out
/// whether a create/update operation has been registered for .
internal SurfaceLineEntity Get(RingtoetsPipingSurfaceLine model)
{
return Get(surfaceLines, model);
}
///
/// Obtains the which was registered for the
/// given .
///
/// The for which a
/// read/update operation has been registered.
/// The constructed .
/// Thrown when is null.
/// Thrown when no create/update operation
/// has been registered for .
/// Use to find out
/// whether a create/update operation has been registered for .
internal HydraulicLocationEntity Get(HydraulicBoundaryLocation model)
{
return Get(hydraulicLocations, model);
}
///
/// Registers a create or update operation for and the
/// that was constructed with the information.
///
/// The that was registered.
/// The which needed
/// to be registered.
/// Thrown when either:
///
/// - is null
/// - is null
///
internal void Register(SurfaceLineEntity entity, RingtoetsPipingSurfaceLine model)
{
Register(surfaceLines, entity, model);
}
///
/// Registers a create or update operation for and the
/// that was constructed with the information.
///
/// The that was registered.
/// The surfaceline geometry corresponding
/// the registered database entity.
/// Thrown when either:
///
/// - is null
/// - is null
///
internal void Register(SurfaceLinePointEntity entity, Point3D model)
{
Register(surfaceLinePoints, entity, model);
}
///
/// Obtains the which was registered for the
/// given .
///
/// The surfaceline geometry for which
/// a create or update operation has been registered.
/// Thrown when is null.
/// Thrown when no create operation
/// has been registered for .
internal SurfaceLinePointEntity GetSurfaceLinePoint(Point3D model)
{
return Get(surfaceLinePoints, model);
}
///
/// Registers a create or update operation for and the
/// that was constructed with the information.
///
/// The that was registered.
/// The surfaceline geometry corresponding
/// to the characteristic point data being registered.
/// Thrown when either:
///
/// - is null
/// - is null
///
internal void Register(CharacteristicPointEntity entity, Point3D model)
{
Register(characteristicPoints, entity, model);
}
internal void Register(PipingFailureMechanismMetaEntity entity, PipingProbabilityAssessmentInput model)
{
Register(pipingProbabilityAssessmentInputs, entity, model);
}
///
/// Transfer ids from the created entities to the domain model objects' property.
///
internal void TransferIds()
{
foreach (var entity in projects.Keys)
{
projects[entity].StorageId = entity.ProjectEntityId;
}
foreach (var entity in failureMechanisms.Keys)
{
failureMechanisms[entity].StorageId = entity.FailureMechanismEntityId;
}
foreach (var entity in failureMechanismSections.Keys)
{
failureMechanismSections[entity].StorageId = entity.FailureMechanismSectionEntityId;
}
foreach (var entity in assessmentSections.Keys)
{
assessmentSections[entity].StorageId = entity.AssessmentSectionEntityId;
}
foreach (var entity in hydraulicLocations.Keys)
{
hydraulicLocations[entity].StorageId = entity.HydraulicLocationEntityId;
}
foreach (var entity in calculationGroups.Keys)
{
calculationGroups[entity].StorageId = entity.CalculationGroupEntityId;
}
foreach (var entity in pipingCalculations.Keys)
{
pipingCalculations[entity].StorageId = entity.PipingCalculationEntityId;
}
foreach (var entity in stochasticSoilModels.Keys)
{
stochasticSoilModels[entity].StorageId = entity.StochasticSoilModelEntityId;
}
foreach (var entity in stochasticSoilProfiles.Keys)
{
stochasticSoilProfiles[entity].StorageId = entity.StochasticSoilProfileEntityId;
}
foreach (var entity in soilProfiles.Keys)
{
soilProfiles[entity].StorageId = entity.SoilProfileEntityId;
}
foreach (var entity in soilLayers.Keys)
{
soilLayers[entity].StorageId = entity.SoilLayerEntityId;
}
foreach (var entity in surfaceLines.Keys)
{
surfaceLines[entity].StorageId = entity.SurfaceLineEntityId;
}
foreach (var entity in surfaceLinePoints.Keys)
{
surfaceLinePoints[entity].StorageId = entity.SurfaceLinePointEntityId;
}
foreach (var entity in pipingProbabilityAssessmentInputs.Keys)
{
pipingProbabilityAssessmentInputs[entity].StorageId = entity.PipingFailureMechanismMetaEntityId;
}
// CharacteristicPoints do not really have a 'identity' within the object-model.
// As such, no need to copy StorageId. This is already covered by surfaceLinePoints.
}
///
/// Removes all the entities for which no update operation was registered from the .
///
/// The from which to remove the entities.
internal void RemoveUntouched(IRingtoetsEntities dbContext)
{
IList orphanedProjectEntities = new List();
foreach (ProjectEntity projectEntity in dbContext.ProjectEntities
.Where(e => e.ProjectEntityId > 0))
{
if (!projects.ContainsKey(projectEntity))
{
orphanedProjectEntities.Add(projectEntity);
}
}
dbContext.ProjectEntities.RemoveRange(orphanedProjectEntities);
IList orphanedAssessmentSectionEntities = new List();
foreach (AssessmentSectionEntity assessmentSectionEntity in dbContext.AssessmentSectionEntities
.Where(e => e.AssessmentSectionEntityId > 0))
{
if (!assessmentSections.ContainsKey(assessmentSectionEntity))
{
orphanedAssessmentSectionEntities.Add(assessmentSectionEntity);
}
}
dbContext.AssessmentSectionEntities.RemoveRange(orphanedAssessmentSectionEntities);
IList orphanedFailureMechanismEntities = new List();
foreach (FailureMechanismEntity failureMechanismEntity in dbContext.FailureMechanismEntities
.Where(e => e.FailureMechanismEntityId > 0))
{
if (!failureMechanisms.ContainsKey(failureMechanismEntity))
{
orphanedFailureMechanismEntities.Add(failureMechanismEntity);
}
}
dbContext.FailureMechanismEntities.RemoveRange(orphanedFailureMechanismEntities);
IList orphanedFailureMechanismSectionEntities = new List();
foreach (FailureMechanismSectionEntity failureMechanismSectionEntity in dbContext.FailureMechanismSectionEntities
.Where(e => e.FailureMechanismSectionEntityId > 0))
{
if (!failureMechanismSections.ContainsKey(failureMechanismSectionEntity))
{
orphanedFailureMechanismSectionEntities.Add(failureMechanismSectionEntity);
}
}
dbContext.FailureMechanismSectionEntities.RemoveRange(orphanedFailureMechanismSectionEntities);
IList orphanedHydraulicLocationEntities = new List();
foreach (HydraulicLocationEntity hydraulicLocationEntity in dbContext.HydraulicLocationEntities
.Where(e => e.HydraulicLocationEntityId > 0))
{
if (!hydraulicLocations.ContainsKey(hydraulicLocationEntity))
{
orphanedHydraulicLocationEntities.Add(hydraulicLocationEntity);
}
}
dbContext.HydraulicLocationEntities.RemoveRange(orphanedHydraulicLocationEntities);
IList orphanedCalculationGroupEntities = new List();
foreach (CalculationGroupEntity calculationGroupEntity in dbContext.CalculationGroupEntities
.Where(e => e.CalculationGroupEntityId > 0))
{
if (!calculationGroups.ContainsKey(calculationGroupEntity))
{
orphanedCalculationGroupEntities.Add(calculationGroupEntity);
}
}
dbContext.CalculationGroupEntities.RemoveRange(orphanedCalculationGroupEntities);
IList orphanedPipingCalculationEntities = new List();
foreach (PipingCalculationEntity pipingCalculationEntity in dbContext.PipingCalculationEntities
.Where(e => e.PipingCalculationEntityId > 0))
{
if (!pipingCalculations.ContainsKey(pipingCalculationEntity))
{
orphanedPipingCalculationEntities.Add(pipingCalculationEntity);
}
}
dbContext.PipingCalculationEntities.RemoveRange(orphanedPipingCalculationEntities);
IList orphanedStochasticSoilModelEntities = new List();
foreach (StochasticSoilModelEntity stochasticSoilModelEntity in dbContext.StochasticSoilModelEntities
.Where(e => e.StochasticSoilModelEntityId > 0))
{
if (!stochasticSoilModels.ContainsKey(stochasticSoilModelEntity))
{
orphanedStochasticSoilModelEntities.Add(stochasticSoilModelEntity);
}
}
dbContext.StochasticSoilModelEntities.RemoveRange(orphanedStochasticSoilModelEntities);
IList orphanedStochasticSoilProfileEntities = new List();
foreach (StochasticSoilProfileEntity stochasticSoilProfileEntity in dbContext.StochasticSoilProfileEntities
.Where(e => e.StochasticSoilProfileEntityId > 0))
{
if (!stochasticSoilProfiles.ContainsKey(stochasticSoilProfileEntity))
{
orphanedStochasticSoilProfileEntities.Add(stochasticSoilProfileEntity);
}
}
dbContext.StochasticSoilProfileEntities.RemoveRange(orphanedStochasticSoilProfileEntities);
IList orphanedSoilProfileEntities = new List();
foreach (SoilProfileEntity soilProfileEntity in dbContext.SoilProfileEntities
.Where(e => e.SoilProfileEntityId > 0))
{
if (!soilProfiles.ContainsKey(soilProfileEntity))
{
orphanedSoilProfileEntities.Add(soilProfileEntity);
}
}
dbContext.SoilProfileEntities.RemoveRange(orphanedSoilProfileEntities);
IList orphanedSoilLayerEntities = new List();
foreach (SoilLayerEntity soilLayerEntity in dbContext.SoilLayerEntities
.Where(e => e.SoilLayerEntityId > 0))
{
if (!soilLayers.ContainsKey(soilLayerEntity))
{
orphanedSoilLayerEntities.Add(soilLayerEntity);
}
}
dbContext.SoilLayerEntities.RemoveRange(orphanedSoilLayerEntities);
IList orphanedSurfaceLineEntities = new List();
foreach (SurfaceLineEntity surfaceLineEntity in dbContext.SurfaceLineEntities
.Where(e => e.SurfaceLineEntityId > 0))
{
if (!surfaceLines.ContainsKey(surfaceLineEntity))
{
orphanedSurfaceLineEntities.Add(surfaceLineEntity);
}
}
dbContext.SurfaceLineEntities.RemoveRange(orphanedSurfaceLineEntities);
IList orphanedSurfaceLinePointEntities = new List();
foreach (SurfaceLinePointEntity surfaceLinePointEntity in dbContext.SurfaceLinePointEntities
.Where(e => e.SurfaceLinePointEntityId > 0))
{
if (!surfaceLinePoints.ContainsKey(surfaceLinePointEntity))
{
orphanedSurfaceLinePointEntities.Add(surfaceLinePointEntity);
}
}
dbContext.SurfaceLinePointEntities.RemoveRange(orphanedSurfaceLinePointEntities);
IList orphanedCharacteristicPointEntities = new List();
foreach (CharacteristicPointEntity characteristicPointEntity in dbContext.CharacteristicPointEntities
.Where(e => e.CharacteristicPointEntityId > 0))
{
if (!characteristicPoints.ContainsKey(characteristicPointEntity))
{
orphanedCharacteristicPointEntities.Add(characteristicPointEntity);
}
}
dbContext.CharacteristicPointEntities.RemoveRange(orphanedCharacteristicPointEntities);
IList orphanedPipingFailureMechanismMetaEntities = new List();
foreach (PipingFailureMechanismMetaEntity pipingFailureMechanismMetaEntity in dbContext.PipingFailureMechanismMetaEntities
.Where(e => e.PipingFailureMechanismMetaEntityId > 0))
{
if (!pipingProbabilityAssessmentInputs.ContainsKey(pipingFailureMechanismMetaEntity))
{
orphanedPipingFailureMechanismMetaEntities.Add(pipingFailureMechanismMetaEntity);
}
}
dbContext.PipingFailureMechanismMetaEntities.RemoveRange(orphanedPipingFailureMechanismMetaEntities);
}
private bool ContainsValue(Dictionary collection, U model)
{
if (model == null)
{
throw new ArgumentNullException("model");
}
return collection.ContainsValue(model);
}
private void Register(Dictionary collection, T entity, U model)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
if (model == null)
{
throw new ArgumentNullException("model");
}
collection[entity] = model;
}
private T Get(Dictionary collection, U model)
{
if (model == null)
{
throw new ArgumentNullException("model");
}
return collection.Keys.Single(k => ReferenceEquals(collection[k], model));
}
}
}