Index: Application/Ringtoets/src/Application.Ringtoets.Storage/Application.Ringtoets.Storage.csproj =================================================================== diff -u -rd180f991b1e2664695dc4e98118e3159256fe3cd -r3c1b05ca357443b861187ba196b806ebab57a929 --- Application/Ringtoets/src/Application.Ringtoets.Storage/Application.Ringtoets.Storage.csproj (.../Application.Ringtoets.Storage.csproj) (revision d180f991b1e2664695dc4e98118e3159256fe3cd) +++ Application/Ringtoets/src/Application.Ringtoets.Storage/Application.Ringtoets.Storage.csproj (.../Application.Ringtoets.Storage.csproj) (revision 3c1b05ca357443b861187ba196b806ebab57a929) @@ -62,14 +62,20 @@ RingtoetsEntities.tt + + + RingtoetsEntities.tt + RingtoetsEntities.tt Code + + @@ -115,10 +121,18 @@ {c90b77da-e421-43cc-b82e-529651bc21ac} Core.Common.Version + + {d4200f43-3f72-4f42-af0a-8ced416a38ec} + Ringtoets.Common.Data + {11F1F874-45AF-43E4-8AE5-15A5C9593E28} Ringtoets.Integration.Data + + {CE994CC9-6F6A-48AC-B4BE-02C30A21F4DB} + Ringtoets.Piping.Data + @@ -161,9 +175,7 @@ Designer - - - + @@ -97,6 +122,11 @@ + + + + + @@ -127,6 +157,7 @@ + @@ -163,6 +194,27 @@ + + + + + + + + + + + + + + + + + + + + + @@ -210,6 +262,15 @@ + + + + + + + + + Index: Application/Ringtoets/src/Application.Ringtoets.Storage/DbContext/RingtoetsEntities.edmx.diagram =================================================================== diff -u -rd180f991b1e2664695dc4e98118e3159256fe3cd -r3c1b05ca357443b861187ba196b806ebab57a929 --- Application/Ringtoets/src/Application.Ringtoets.Storage/DbContext/RingtoetsEntities.edmx.diagram (.../RingtoetsEntities.edmx.diagram) (revision d180f991b1e2664695dc4e98118e3159256fe3cd) +++ Application/Ringtoets/src/Application.Ringtoets.Storage/DbContext/RingtoetsEntities.edmx.diagram (.../RingtoetsEntities.edmx.diagram) (revision 3c1b05ca357443b861187ba196b806ebab57a929) @@ -11,6 +11,8 @@ + + Index: Application/Ringtoets/src/Application.Ringtoets.Storage/Persistors/DikeAssessmentSectionEntityPersistor.cs =================================================================== diff -u -rd180f991b1e2664695dc4e98118e3159256fe3cd -r3c1b05ca357443b861187ba196b806ebab57a929 --- Application/Ringtoets/src/Application.Ringtoets.Storage/Persistors/DikeAssessmentSectionEntityPersistor.cs (.../DikeAssessmentSectionEntityPersistor.cs) (revision d180f991b1e2664695dc4e98118e3159256fe3cd) +++ Application/Ringtoets/src/Application.Ringtoets.Storage/Persistors/DikeAssessmentSectionEntityPersistor.cs (.../DikeAssessmentSectionEntityPersistor.cs) (revision 3c1b05ca357443b861187ba196b806ebab57a929) @@ -42,6 +42,8 @@ private readonly Dictionary insertedList = new Dictionary(); private readonly ICollection modifiedList = new List(); + private readonly PipingFailureMechanismPersistor pipingFailureMechanismPersistor; + /// /// New instance of . /// @@ -56,6 +58,8 @@ dbContext = ringtoetsContext; converter = new DikeAssessmentSectionEntityConverter(); + + pipingFailureMechanismPersistor = new PipingFailureMechanismPersistor(dbContext); } /// @@ -65,7 +69,17 @@ /// A new instance of , based on the properties of . public DikeAssessmentSection LoadModel(DikeAssessmentSectionEntity entity) { - return converter.ConvertEntityToModel(entity); + var dikeAssessmentSection = converter.ConvertEntityToModel(entity); + + foreach (var failureMechanismEntity in entity.FailureMechanismEntities) + { + if (failureMechanismEntity.FailureMechanismType == (int) FailureMechanismType.PipingFailureMechanism) + { + PipingFailureMechanismPersistor.LoadModel(dikeAssessmentSection.PipingFailureMechanism, failureMechanismEntity); + } + } + + return dikeAssessmentSection; } /// @@ -154,21 +168,31 @@ public void PerformPostSaveActions() { UpdateStorageIdsInModel(); + + pipingFailureMechanismPersistor.PerformPostSaveActions(); } /// /// Updates the children of , in reference to , in the storage. /// /// The of which children need to be updated. /// Referenced . - public void UpdateChildren(DikeAssessmentSection model, DikeAssessmentSectionEntity entity) {} + public void UpdateChildren(DikeAssessmentSection model, DikeAssessmentSectionEntity entity) + { + pipingFailureMechanismPersistor.UpdateModel(entity.FailureMechanismEntities, model.PipingFailureMechanism); + pipingFailureMechanismPersistor.RemoveUnModifiedEntries(entity.FailureMechanismEntities); + } /// /// Inserts the children of , in reference to , in the storage. /// /// The of which children need to be inserted. /// Referenced . - public void InsertChildren(DikeAssessmentSection model, DikeAssessmentSectionEntity entity) {} + public void InsertChildren(DikeAssessmentSection model, DikeAssessmentSectionEntity entity) + { + pipingFailureMechanismPersistor.InsertModel(entity.FailureMechanismEntities, model.PipingFailureMechanism); + pipingFailureMechanismPersistor.RemoveUnModifiedEntries(entity.FailureMechanismEntities); + } /// /// Performs the update of to . Index: Application/Ringtoets/src/Application.Ringtoets.Storage/Persistors/FailureMechanismEntityPersistorBase.cs =================================================================== diff -u --- Application/Ringtoets/src/Application.Ringtoets.Storage/Persistors/FailureMechanismEntityPersistorBase.cs (revision 0) +++ Application/Ringtoets/src/Application.Ringtoets.Storage/Persistors/FailureMechanismEntityPersistorBase.cs (revision 3c1b05ca357443b861187ba196b806ebab57a929) @@ -0,0 +1,164 @@ +// 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 Application.Ringtoets.Storage.Exceptions; +using Application.Ringtoets.Storage.Properties; +using Ringtoets.Common.Data; +using Ringtoets.Piping.Data; + +namespace Application.Ringtoets.Storage.Persistors +{ + public abstract class FailureMechanismEntityPersistorBase + { + protected readonly IRingtoetsEntities dbContext; + private readonly Dictionary insertedList = new Dictionary(); + private readonly ICollection modifiedList = new List(); + + protected FailureMechanismEntityPersistorBase(IRingtoetsEntities ringtoetsContext) + { + if (ringtoetsContext == null) + { + throw new ArgumentNullException("ringtoetsContext"); + } + dbContext = ringtoetsContext; + } + + public void RemoveUnModifiedEntries(ICollection parentNavigationProperty) + { + var originalList = parentNavigationProperty.ToList(); + foreach (var u in modifiedList) + { + originalList.Remove(u); + } + + foreach (var toDelete in originalList) + { + // If id = 0, the entity is marked as inserted + if (toDelete.FailureMechanismEntityId > 0) + { + dbContext.FailureMechanismEntities.Remove(toDelete); + } + } + + modifiedList.Clear(); + } + + public void PerformPostSaveActions() + { + foreach (var entry in insertedList) + { + entry.Value.StorageId = entry.Key.FailureMechanismEntityId; + } + insertedList.Clear(); + } + + protected void InsertModel(ICollection parentNavigationProperty, IFailureMechanism model) + { + if (parentNavigationProperty == null) + { + throw new ArgumentNullException("parentNavigationProperty"); + } + + var entity = new FailureMechanismEntity(); + parentNavigationProperty.Add(entity); + insertedList.Add(entity, model); + + ConvertModelToEntity(model, entity); + + if (model.StorageId > 0) + { + modifiedList.Add(entity); + } + } + + protected void UpdateModel(ICollection parentNavigationProperty, IFailureMechanism model) + { + if (model == null) + { + throw new ArgumentNullException("model"); + } + if (model.StorageId < 1) + { + InsertModel(parentNavigationProperty, model); + return; + } + + if (parentNavigationProperty == null) + { + throw new ArgumentNullException("parentNavigationProperty"); + } + + FailureMechanismEntity entity; + try + { + entity = parentNavigationProperty.SingleOrDefault(db => db.FailureMechanismEntityId == model.StorageId); + } + catch (InvalidOperationException exception) + { + throw new EntityNotFoundException(String.Format(Resources.Error_Entity_Not_Found_0_1, "FailureMechanismEntity", model.StorageId), exception); + } + if (entity == null) + { + throw new EntityNotFoundException(String.Format(Resources.Error_Entity_Not_Found_0_1, "FailureMechanismEntity", model.StorageId)); + } + + modifiedList.Add(entity); + + ConvertModelToEntity(model, entity); + } + + protected static void LoadModel(IFailureMechanism model, FailureMechanismType modelType, FailureMechanismEntity entity) + { + if (model == null) + { + throw new ArgumentNullException("model"); + } + if (entity == null) + { + throw new ArgumentNullException("entity"); + } + if (entity.FailureMechanismType != (int) modelType) + { + throw new ArgumentException("Incorrect modelType", "entity"); + } + model.StorageId = entity.FailureMechanismEntityId; + } + + private static void ConvertModelToEntity(IFailureMechanism modelObject, FailureMechanismEntity entity) + { + if (modelObject == null) + { + throw new ArgumentNullException("modelObject"); + } + entity.FailureMechanismEntityId = modelObject.StorageId; + if (modelObject is PipingFailureMechanism) + { + entity.FailureMechanismType = (int) FailureMechanismType.PipingFailureMechanism; + return; + } + throw new InvalidOperationException("modelObject is not a known implementation of IFailureMechanism"); + } + } +} \ No newline at end of file Index: Application/Ringtoets/src/Application.Ringtoets.Storage/Persistors/PipingFailureMechanismPersistor.cs =================================================================== diff -u --- Application/Ringtoets/src/Application.Ringtoets.Storage/Persistors/PipingFailureMechanismPersistor.cs (revision 0) +++ Application/Ringtoets/src/Application.Ringtoets.Storage/Persistors/PipingFailureMechanismPersistor.cs (revision 3c1b05ca357443b861187ba196b806ebab57a929) @@ -0,0 +1,51 @@ +// 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.Collections.Generic; +using Application.Ringtoets.Storage.DbContext; +using Ringtoets.Piping.Data; + +namespace Application.Ringtoets.Storage.Persistors +{ + public class PipingFailureMechanismPersistor : FailureMechanismEntityPersistorBase + { + public PipingFailureMechanismPersistor(IRingtoetsEntities ringtoetsContext) : base(ringtoetsContext) {} + + public static void LoadModel(PipingFailureMechanism model, FailureMechanismEntity entity) + { + LoadModel(model, FailureMechanismType.PipingFailureMechanism, entity); + } + + public void InsertModel(ICollection parentNavigationProperty, PipingFailureMechanism model) + { + base.InsertModel(parentNavigationProperty, model); + + // Insert Children comes here + } + + public void UpdateModel(ICollection parentNavigationProperty, PipingFailureMechanism model) + { + base.UpdateModel(parentNavigationProperty, model); + + // Update Children comes here + } + } +} \ No newline at end of file Index: Application/Ringtoets/src/Application.Ringtoets.Storage/Ringtoets.rtd =================================================================== diff -u -re7acba10209b18e88bf89d9211f6fc031d0f992e -r3c1b05ca357443b861187ba196b806ebab57a929 Binary files differ Index: Application/Ringtoets/test/Application.Ringtoets.Storage.Test/Application.Ringtoets.Storage.Test.csproj =================================================================== diff -u -ra65bc56647a666fad39e7fe48fbce3a5c040dfee -r3c1b05ca357443b861187ba196b806ebab57a929 --- Application/Ringtoets/test/Application.Ringtoets.Storage.Test/Application.Ringtoets.Storage.Test.csproj (.../Application.Ringtoets.Storage.Test.csproj) (revision a65bc56647a666fad39e7fe48fbce3a5c040dfee) +++ Application/Ringtoets/test/Application.Ringtoets.Storage.Test/Application.Ringtoets.Storage.Test.csproj (.../Application.Ringtoets.Storage.Test.csproj) (revision 3c1b05ca357443b861187ba196b806ebab57a929) @@ -74,6 +74,7 @@ + @@ -85,6 +86,7 @@ Code + Code @@ -109,10 +111,18 @@ {D749EE4C-CE50-4C17-BF01-9A953028C126} Core.Common.TestUtil + + {d4200f43-3f72-4f42-af0a-8ced416a38ec} + Ringtoets.Common.Data + {11f1f874-45af-43e4-8ae5-15a5c9593e28} Ringtoets.Integration.Data + + {CE994CC9-6F6A-48AC-B4BE-02C30A21F4DB} + Ringtoets.Piping.Data + {50963f12-448c-41ba-a62c-cdb0ab8d21e0} Application.Ringtoets.Storage Index: Application/Ringtoets/test/Application.Ringtoets.Storage.Test/DbContext/FailureMechanismEntityTest.cs =================================================================== diff -u --- Application/Ringtoets/test/Application.Ringtoets.Storage.Test/DbContext/FailureMechanismEntityTest.cs (revision 0) +++ Application/Ringtoets/test/Application.Ringtoets.Storage.Test/DbContext/FailureMechanismEntityTest.cs (revision 3c1b05ca357443b861187ba196b806ebab57a929) @@ -0,0 +1,43 @@ +using Application.Ringtoets.Storage.DbContext; +using NUnit.Framework; + +namespace Application.Ringtoets.Storage.Test.DbContext +{ + [TestFixture] + public class FailureMechanismEntityTest + { + [Test] + public void DefaultConstructor_Always_ExpectedValues() + { + // Call + FailureMechanismEntity failureMechanismEntity = new FailureMechanismEntity(); + + // Assert + Assert.AreEqual(0, failureMechanismEntity.FailureMechanismEntityId); + Assert.AreEqual(0, failureMechanismEntity.DikeAssessmentSectionEntityId); + Assert.AreEqual(0, failureMechanismEntity.FailureMechanismType); + } + + [Test] + public void GetProperties_WithData_ReturnExpectedValues() + { + // Setup + const long expectedParentId = 1L; + const long expectedId = 1024L; + int failureMechanismType = (int) FailureMechanismType.PipingFailureMechanism; + + // Call + FailureMechanismEntity failureMechanismEntity = new FailureMechanismEntity + { + DikeAssessmentSectionEntityId = expectedParentId, + FailureMechanismEntityId = expectedId, + FailureMechanismType = failureMechanismType + }; + + // Assert + Assert.AreEqual(expectedParentId, failureMechanismEntity.DikeAssessmentSectionEntityId); + Assert.AreEqual(expectedId, failureMechanismEntity.FailureMechanismEntityId); + Assert.AreEqual(failureMechanismType, failureMechanismEntity.FailureMechanismType); + } + } +} \ No newline at end of file Index: Application/Ringtoets/test/Application.Ringtoets.Storage.Test/Persistors/DikeAssessmentSectionEntityPersistorTest.cs =================================================================== diff -u -rd180f991b1e2664695dc4e98118e3159256fe3cd -r3c1b05ca357443b861187ba196b806ebab57a929 --- Application/Ringtoets/test/Application.Ringtoets.Storage.Test/Persistors/DikeAssessmentSectionEntityPersistorTest.cs (.../DikeAssessmentSectionEntityPersistorTest.cs) (revision d180f991b1e2664695dc4e98118e3159256fe3cd) +++ Application/Ringtoets/test/Application.Ringtoets.Storage.Test/Persistors/DikeAssessmentSectionEntityPersistorTest.cs (.../DikeAssessmentSectionEntityPersistorTest.cs) (revision 3c1b05ca357443b861187ba196b806ebab57a929) @@ -64,17 +64,24 @@ } [Test] - public void LoadModel_ValidEntity_EntityAsModelInList() + public void LoadModel_ValidEntity_EntityAsModel() { // Setup const long storageId = 1234L; const string name = "test"; const int norm = 30000; + const long pipingFailureMechanismStorageId = 1L; var ringtoetsEntities = mockRepository.StrictMock(); DikeAssessmentSectionEntityPersistor persistor = new DikeAssessmentSectionEntityPersistor(ringtoetsEntities); var entity = new DikeAssessmentSectionEntity { - DikeAssessmentSectionEntityId = storageId, Name = name, Norm = norm + DikeAssessmentSectionEntityId = storageId, Name = name, Norm = norm, FailureMechanismEntities = new List + { + new FailureMechanismEntity + { + FailureMechanismType = (int) FailureMechanismType.PipingFailureMechanism, FailureMechanismEntityId = pipingFailureMechanismStorageId + } + } }; mockRepository.ReplayAll(); @@ -85,12 +92,13 @@ Assert.AreEqual(storageId, section.StorageId); Assert.AreEqual(name, section.Name); Assert.AreEqual(norm, section.FailureMechanismContribution.Norm); + Assert.AreEqual(pipingFailureMechanismStorageId, section.PipingFailureMechanism.StorageId); mockRepository.VerifyAll(); } [Test] - public void LoadModel_MultipleEntitiesInDataset_EntitiesAsModelInList() + public void LoadModel_MultipleEntitiesInDataset_EntitiesAsModel() { // Setup var ringtoetsEntities = mockRepository.StrictMock(); @@ -214,16 +222,15 @@ DikeAssessmentSectionEntityPersistor persistor = new DikeAssessmentSectionEntityPersistor(ringtoetsEntities); - DikeAssessmentSection dikeAssessmentSection = - new DikeAssessmentSection + DikeAssessmentSection dikeAssessmentSection = new DikeAssessmentSection + { + StorageId = storageId, + Name = name, + FailureMechanismContribution = { - StorageId = storageId, - Name = name, - FailureMechanismContribution = - { - Norm = norm - } - }; + Norm = norm + } + }; mockRepository.ReplayAll(); // Call @@ -241,6 +248,30 @@ } [Test] + public void InsertModel_ValidDikeAssessmentSectionWithChildren_InsertedDikeAssessmentSectionWithChildren() + { + // Setup + var ringtoetsEntities = mockRepository.StrictMock(); + DikeAssessmentSectionEntityPersistor persistor = new DikeAssessmentSectionEntityPersistor(ringtoetsEntities); + DikeAssessmentSection dikeAssessmentSection = new DikeAssessmentSection(); + IList parentNavigationProperty = new List(); + mockRepository.ReplayAll(); + + // Call + persistor.InsertModel(parentNavigationProperty, dikeAssessmentSection, 0); + + // Assert + Assert.AreEqual(1, parentNavigationProperty.Count); + var entity = parentNavigationProperty.ToList()[0]; + Assert.AreNotEqual(dikeAssessmentSection, entity); + + Assert.AreEqual(1, entity.FailureMechanismEntities.Count); + Assert.AreEqual(1, entity.FailureMechanismEntities.Count(db => db.FailureMechanismType.Equals((int) FailureMechanismType.PipingFailureMechanism))); + + mockRepository.VerifyAll(); + } + + [Test] public void UpdateModel_NullParentNavigationProperty_ThrowsArgumentNullException() { // Setup @@ -503,9 +534,43 @@ } [Test] - public void RemoveUnModifiedEntries_SingleEntityInParentNavigationPropertySingleDikeAssessmentSectionWithoutStorageId_UpdatedDikeAssessmentSectionAsEntityInParentNavigationPropertyAndOthersDeletedInDbSet() + public void UpdateModel_ValidDikeAssessmentSectionWithChildren_UpdatedDikeAssessmentSectionWithChildren() { // Setup + const long storageId = 1234L; + var ringtoetsEntities = mockRepository.StrictMock(); + DikeAssessmentSectionEntityPersistor persistor = new DikeAssessmentSectionEntityPersistor(ringtoetsEntities); + DikeAssessmentSection dikeAssessmentSection = new DikeAssessmentSection + { + StorageId = storageId + }; + IList parentNavigationProperty = new List + { + new DikeAssessmentSectionEntity + { + DikeAssessmentSectionEntityId = storageId + } + }; + mockRepository.ReplayAll(); + + // Call + persistor.UpdateModel(parentNavigationProperty, dikeAssessmentSection, 0); + + // Assert + Assert.AreEqual(1, parentNavigationProperty.Count); + var entity = parentNavigationProperty.ToList()[0]; + Assert.AreNotEqual(dikeAssessmentSection, entity); + + Assert.AreEqual(1, entity.FailureMechanismEntities.Count); + Assert.AreEqual(1, entity.FailureMechanismEntities.Count(db => db.FailureMechanismType.Equals((int) FailureMechanismType.PipingFailureMechanism))); + + mockRepository.VerifyAll(); + } + + [Test] + public void RemoveUnModifiedEntries_SingleEntityInParentNavigationPropertyModelWithoutStorageId_UpdatedDikeAssessmentSectionAsEntityInParentNavigationPropertyAndOthersDeletedInDbSet() + { + // Setup const string name = "test"; const long storageId = 0L; // Newly inserted entities have Id = 0 untill they are saved const int norm = 30000; @@ -553,6 +618,63 @@ } [Test] + public void RemoveUnModifiedEntries_MultipleEntitiesInnParentNavigationPropertySingleModelStorageId_UpdatedDikeAssessmentSectionAsEntityAndOtherDeletedInDbSet() + { + // Setup + const string name = "test"; + const long storageId = 1234L; + const int norm = 30000; + DikeAssessmentSectionEntity entityToUpdate = new DikeAssessmentSectionEntity + { + DikeAssessmentSectionEntityId = storageId, + Name = "Entity to update" + }; + DikeAssessmentSectionEntity entityToDelete = new DikeAssessmentSectionEntity + { + DikeAssessmentSectionEntityId = 4567L, + Name = "First entity to delete" + }; + + IList parentNavigationProperty = new List + { + entityToDelete, + entityToUpdate + }; + var dbset = DbTestSet.GetDbTestSet(mockRepository, parentNavigationProperty); + dbset.Expect(x => x.Remove(entityToDelete)).Return(entityToDelete); + + var ringtoetsEntities = mockRepository.StrictMock(); + ringtoetsEntities.Expect(x => x.DikeAssessmentSectionEntities).Return(dbset); + + DikeAssessmentSectionEntityPersistor persistor = new DikeAssessmentSectionEntityPersistor(ringtoetsEntities); + DikeAssessmentSection dikeAssessmentSection = new DikeAssessmentSection + { + Name = name, + FailureMechanismContribution = + { + Norm = norm + }, + StorageId = storageId + }; + mockRepository.ReplayAll(); + + TestDelegate updateTest = () => persistor.UpdateModel(parentNavigationProperty, dikeAssessmentSection, 0); + Assert.DoesNotThrow(updateTest, "Precondition failed: Update should not throw exception."); + + // Call + persistor.RemoveUnModifiedEntries(parentNavigationProperty); + + // Assert + Assert.AreEqual(2, parentNavigationProperty.Count); + Assert.IsInstanceOf(entityToUpdate); + Assert.AreEqual(storageId, entityToUpdate.DikeAssessmentSectionEntityId); + Assert.AreEqual(name, entityToUpdate.Name); + Assert.AreEqual(norm, entityToUpdate.Norm); + + mockRepository.VerifyAll(); + } + + [Test] public void RemoveUnModifiedEntries_MultipleEntitiesInParentNavigationPropertyEmptyDikeAssessmentSection_EmptyDatabaseSet() { // Setup Index: Application/Ringtoets/test/Application.Ringtoets.Storage.Test/Persistors/DuneAssessmentSectionEntityPersistorTest.cs =================================================================== diff -u -rd180f991b1e2664695dc4e98118e3159256fe3cd -r3c1b05ca357443b861187ba196b806ebab57a929 --- Application/Ringtoets/test/Application.Ringtoets.Storage.Test/Persistors/DuneAssessmentSectionEntityPersistorTest.cs (.../DuneAssessmentSectionEntityPersistorTest.cs) (revision d180f991b1e2664695dc4e98118e3159256fe3cd) +++ Application/Ringtoets/test/Application.Ringtoets.Storage.Test/Persistors/DuneAssessmentSectionEntityPersistorTest.cs (.../DuneAssessmentSectionEntityPersistorTest.cs) (revision 3c1b05ca357443b861187ba196b806ebab57a929) @@ -64,7 +64,7 @@ } [Test] - public void LoadModel_ValidEntity_EntityAsModelInList() + public void LoadModel_ValidEntity_EntityAsModel() { // Setup const long storageId = 1234L; @@ -92,7 +92,7 @@ } [Test] - public void LoadModel_MultipleEntitiesInDataset_EntitiesAsModelInList() + public void LoadModel_MultipleEntitiesInDataset_EntitiesAsModel() { // Setup var ringtoetsEntities = mockRepository.StrictMock(); @@ -546,6 +546,63 @@ } [Test] + public void RemoveUnModifiedEntries_MultipleEntitiesInnParentNavigationPropertySingleModelStorageId_UpdatedDuneAssessmentSectionAsEntityAndOtherDeletedInDbSet() + { + // Setup + const string name = "test"; + const long storageId = 1234L; + const int norm = 30000; + DuneAssessmentSectionEntity entityToUpdate = new DuneAssessmentSectionEntity + { + DuneAssessmentSectionEntityId = storageId, + Name = "Entity to update" + }; + DuneAssessmentSectionEntity entityToDelete = new DuneAssessmentSectionEntity + { + DuneAssessmentSectionEntityId = 4567L, + Name = "First entity to delete" + }; + + IList parentNavigationProperty = new List + { + entityToDelete, + entityToUpdate + }; + var dbset = DbTestSet.GetDbTestSet(mockRepository, parentNavigationProperty); + dbset.Expect(x => x.Remove(entityToDelete)).Return(entityToDelete); + + var ringtoetsEntities = mockRepository.StrictMock(); + ringtoetsEntities.Expect(x => x.DuneAssessmentSectionEntities).Return(dbset); + + DuneAssessmentSectionEntityPersistor persistor = new DuneAssessmentSectionEntityPersistor(ringtoetsEntities); + DuneAssessmentSection duneAssessmentSection = new DuneAssessmentSection + { + Name = name, + FailureMechanismContribution = + { + Norm = norm + }, + StorageId = storageId + }; + mockRepository.ReplayAll(); + + TestDelegate updateTest = () => persistor.UpdateModel(parentNavigationProperty, duneAssessmentSection, 0); + Assert.DoesNotThrow(updateTest, "Precondition failed: Update should not throw exception."); + + // Call + persistor.RemoveUnModifiedEntries(parentNavigationProperty); + + // Assert + Assert.AreEqual(2, parentNavigationProperty.Count); + Assert.IsInstanceOf(entityToUpdate); + Assert.AreEqual(storageId, entityToUpdate.DuneAssessmentSectionEntityId); + Assert.AreEqual(name, entityToUpdate.Name); + Assert.AreEqual(norm, entityToUpdate.Norm); + + mockRepository.VerifyAll(); + } + + [Test] public void RemoveUnModifiedEntries_MultipleEntitiesInParentNavigationPropertyEmptyDuneAssessmentSection_EmptyDatabaseSet() { // Setup Index: Application/Ringtoets/test/Application.Ringtoets.Storage.Test/Persistors/PipingFailureMechanismPersistorTest.cs =================================================================== diff -u --- Application/Ringtoets/test/Application.Ringtoets.Storage.Test/Persistors/PipingFailureMechanismPersistorTest.cs (revision 0) +++ Application/Ringtoets/test/Application.Ringtoets.Storage.Test/Persistors/PipingFailureMechanismPersistorTest.cs (revision 3c1b05ca357443b861187ba196b806ebab57a929) @@ -0,0 +1,541 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Application.Ringtoets.Storage.DbContext; +using Application.Ringtoets.Storage.Exceptions; +using Application.Ringtoets.Storage.Persistors; +using Application.Ringtoets.Storage.Test.DbContext; +using NUnit.Framework; +using Rhino.Mocks; +using Ringtoets.Piping.Data; + +namespace Application.Ringtoets.Storage.Test.Persistors +{ + [TestFixture] + public class PipingFailureMechanismPersistorTest + { + private MockRepository mockRepository; + + [SetUp] + public void SetUp() + { + mockRepository = new MockRepository(); + } + + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void Constructor_NullDataSet_ThrowsArgumentNullException() + { + // Call + PipingFailureMechanismPersistor p = new PipingFailureMechanismPersistor(null); + } + + [Test] + public void Constructor_EmptyDataset_NewInstance() + { + // Setup + var ringtoetsEntities = mockRepository.StrictMock(); + mockRepository.ReplayAll(); + + // Call + PipingFailureMechanismPersistor persistor = new PipingFailureMechanismPersistor(ringtoetsEntities); + + // Assert + Assert.IsInstanceOf(persistor); + + mockRepository.VerifyAll(); + } + + [Test] + public void LoadModel_NullEntityValidModel_ThrowsArgumentNullException() + { + // Setup + PipingFailureMechanism model = new PipingFailureMechanism(); + + // Call + TestDelegate test = () => PipingFailureMechanismPersistor.LoadModel(model, null); + + // Assert + Assert.Throws(test); + } + + [Test] + public void LoadModel_ValidEntityNullModel_ThrowsArgumentNullException() + { + // Setup + FailureMechanismEntity entity = new FailureMechanismEntity(); + + // Call + TestDelegate test = () => PipingFailureMechanismPersistor.LoadModel(null, entity); + + // Assert + Assert.Throws(test); + } + + [Test] + public void LoadModel_EntityWithIncorrectTypeValidModel_UpdatedModel() + { + // Setup + const long storageId = 1234L; + PipingFailureMechanism model = new PipingFailureMechanism(); + FailureMechanismEntity entity = new FailureMechanismEntity + { + FailureMechanismEntityId = storageId, + FailureMechanismType = (int) FailureMechanismType.StoneRevetmentFailureMechanism, + }; + + // Call + TestDelegate test = () => PipingFailureMechanismPersistor.LoadModel(model, entity); + + // Assert + Assert.Throws(test); + } + + [Test] + public void LoadModel_ValidEntityValidModel_UpdatedModel() + { + // Setup + const long storageId = 1234L; + PipingFailureMechanism model = new PipingFailureMechanism(); + FailureMechanismEntity entity = new FailureMechanismEntity + { + FailureMechanismEntityId = storageId, + FailureMechanismType = (int) FailureMechanismType.PipingFailureMechanism, + }; + + // Call + PipingFailureMechanismPersistor.LoadModel(model, entity); + + // Assert + Assert.IsInstanceOf(model); + Assert.AreEqual(model.StorageId, entity.FailureMechanismEntityId); + } + + [Test] + public void InsertModel_NullDatasetValidModel_ThrowsArgumentNullException() + { + // Setup + var ringtoetsEntities = mockRepository.StrictMock(); + PipingFailureMechanismPersistor persistor = new PipingFailureMechanismPersistor(ringtoetsEntities); + PipingFailureMechanism model = new PipingFailureMechanism(); + mockRepository.ReplayAll(); + + // Call + TestDelegate test = () => persistor.InsertModel(null, model); + + // Assert + Assert.Throws(test); + + mockRepository.VerifyAll(); + } + + [Test] + public void InsertModel_EmptyDatasetNullModel_ThrowsArgumentNullException() + { + // Setup + var ringtoetsEntities = mockRepository.StrictMock(); + PipingFailureMechanismPersistor persistor = new PipingFailureMechanismPersistor(ringtoetsEntities); + IList parentNavigationProperty = new List(); + mockRepository.ReplayAll(); + + // Call + TestDelegate test = () => persistor.InsertModel(parentNavigationProperty, null); + + // Assert + Assert.Throws(test); + + mockRepository.VerifyAll(); + } + + [Test] + public void InsertModel_EmptyDatasetValidModel_ValidEntityInDataModel() + { + // Setup + var ringtoetsEntities = mockRepository.StrictMock(); + PipingFailureMechanismPersistor persistor = new PipingFailureMechanismPersistor(ringtoetsEntities); + IList parentNavigationProperty = new List(); + PipingFailureMechanism model = new PipingFailureMechanism(); + + mockRepository.ReplayAll(); + + // Call + persistor.InsertModel(parentNavigationProperty, model); + + // Assert + Assert.AreEqual(1, parentNavigationProperty.Count); + var entity = parentNavigationProperty[0]; + Assert.AreNotEqual(model, entity); + Assert.AreEqual((int) FailureMechanismType.PipingFailureMechanism, entity.FailureMechanismType); + + mockRepository.VerifyAll(); + } + + [Test] + public void InsertModel_SingleEntityInParentNavigationPropertySinglePipingFailureMechanismWithSameStorageId_PipingFailureMechanismAsEntityInParentNavigationProperty() + { + // Setup + const long storageId = 1234L; + FailureMechanismEntity entityToDelete = new FailureMechanismEntity + { + FailureMechanismEntityId = storageId, + FailureMechanismType = (int) FailureMechanismType.PipingFailureMechanism + }; + IList parentNavigationProperty = new List + { + entityToDelete + }; + var ringtoetsEntities = mockRepository.StrictMock(); + PipingFailureMechanismPersistor persistor = new PipingFailureMechanismPersistor(ringtoetsEntities); + PipingFailureMechanism pipingFailureMechanism = new PipingFailureMechanism + { + StorageId = storageId + }; + mockRepository.ReplayAll(); + + // Call + persistor.InsertModel(parentNavigationProperty, pipingFailureMechanism); + + // Assert + Assert.AreEqual(2, parentNavigationProperty.Count); + var parentNavigationPropertyList = parentNavigationProperty.ToList(); + var entity = parentNavigationPropertyList[1]; + Assert.AreEqual(storageId, entity.FailureMechanismEntityId); + + mockRepository.VerifyAll(); + } + + [Test] + public void UpdateModel_NullDataSetValidModel_ThrowsArgumentNullException() + { + // Setup + const long storageId = 1234L; + var ringtoetsEntities = mockRepository.StrictMock(); + PipingFailureMechanismPersistor persistor = new PipingFailureMechanismPersistor(ringtoetsEntities); + PipingFailureMechanism model = new PipingFailureMechanism + { + StorageId = storageId + }; + mockRepository.ReplayAll(); + + // Call + TestDelegate test = () => persistor.UpdateModel(null, model); + + // Assert + Assert.Throws(test); + + mockRepository.VerifyAll(); + } + + [Test] + public void UpdateModel_EmptyDataSetNullModel_ThrowsArgumentNullException() + { + // Setup + var ringtoetsEntities = mockRepository.StrictMock(); + PipingFailureMechanismPersistor persistor = new PipingFailureMechanismPersistor(ringtoetsEntities); + IList parentNavigationProperty = new List(); + mockRepository.ReplayAll(); + + // Call + TestDelegate test = () => persistor.UpdateModel(parentNavigationProperty, null); + + // Assert + Assert.Throws(test); + + mockRepository.VerifyAll(); + } + + [Test] + public void UpdateModel_EmptyDataset_ThrowsEntityNotFoundException() + { + // Setup + const long storageId = 1234L; + var ringtoetsEntities = mockRepository.StrictMock(); + PipingFailureMechanismPersistor persistor = new PipingFailureMechanismPersistor(ringtoetsEntities); + IList parentNavigationProperty = new List(); + PipingFailureMechanism model = new PipingFailureMechanism + { + StorageId = storageId + }; + mockRepository.ReplayAll(); + + // Call + TestDelegate test = () => persistor.UpdateModel(parentNavigationProperty, model); + + // Assert + Assert.Throws(test); + + mockRepository.VerifyAll(); + } + + [Test] + public void UpdateModel_DuplicateEntityInDataset_ThrowsEntityNotFoundException() + { + // Setup + const long storageId = 1234L; + var ringtoetsEntities = mockRepository.StrictMock(); + PipingFailureMechanismPersistor persistor = new PipingFailureMechanismPersistor(ringtoetsEntities); + IList parentNavigationProperty = new List + { + new FailureMechanismEntity + { + FailureMechanismEntityId = storageId, + FailureMechanismType = (int) FailureMechanismType.PipingFailureMechanism + }, + new FailureMechanismEntity + { + FailureMechanismEntityId = storageId, + FailureMechanismType = (int) FailureMechanismType.PipingFailureMechanism + } + }; + PipingFailureMechanism model = new PipingFailureMechanism + { + StorageId = storageId + }; + mockRepository.ReplayAll(); + + // Call + TestDelegate test = () => persistor.UpdateModel(parentNavigationProperty, model); + + // Assert + Assert.Throws(test); + + mockRepository.VerifyAll(); + } + + [Test] + public void UpdateModel_SingleEntityInParentNavigationPropertySinglePipingFailureMechanismWithStorageId_UpdatedPipingFailureMechanismAsEntityInParentNavigationProperty() + { + // Setup + const long storageId = 1234L; + var ringtoetsEntities = mockRepository.StrictMock(); + PipingFailureMechanismPersistor persistor = new PipingFailureMechanismPersistor(ringtoetsEntities); + ICollection parentNavigationProperty = new List + { + new FailureMechanismEntity + { + FailureMechanismEntityId = storageId, + FailureMechanismType = (int) FailureMechanismType.PipingFailureMechanism + } + }; + PipingFailureMechanism model = new PipingFailureMechanism + { + StorageId = storageId + }; + mockRepository.ReplayAll(); + + // Call + persistor.UpdateModel(parentNavigationProperty, model); + + // Assert + Assert.AreEqual(1, parentNavigationProperty.Count); + var parentNavigationPropertyList = parentNavigationProperty.ToList(); + var entity = parentNavigationPropertyList[0]; + Assert.AreEqual(storageId, entity.FailureMechanismEntityId); + + mockRepository.VerifyAll(); + } + + [Test] + public void RemoveUnModifiedEntries_SingleEntityInParentNavigationPropertySinglePipingFailureMechanismWithoutStorageId_UpdatedPipingFailureMechanismAsEntityInParentNavigationPropertyAndOthersDeletedInDbSet() + { + // Setup + const long storageId = 0L; // Newly inserted entities have Id = 0 untill they are saved + FailureMechanismEntity entityToDelete = new FailureMechanismEntity + { + FailureMechanismEntityId = 4567L, + FailureMechanismType = (int) FailureMechanismType.PipingFailureMechanism + }; + + IList parentNavigationProperty = new List + { + entityToDelete + }; + var dbset = DbTestSet.GetDbTestSet(mockRepository, parentNavigationProperty); + dbset.Expect(x => x.Remove(entityToDelete)).Return(entityToDelete); + + var ringtoetsEntities = mockRepository.StrictMock(); + ringtoetsEntities.Expect(x => x.FailureMechanismEntities).Return(dbset); + + PipingFailureMechanismPersistor persistor = new PipingFailureMechanismPersistor(ringtoetsEntities); + PipingFailureMechanism pipingFailureMechanism = new PipingFailureMechanism(); + mockRepository.ReplayAll(); + + // Call + persistor.UpdateModel(parentNavigationProperty, pipingFailureMechanism); + persistor.RemoveUnModifiedEntries(parentNavigationProperty); + + // Assert + Assert.AreEqual(2, parentNavigationProperty.Count); + var entity = parentNavigationProperty.SingleOrDefault(x => x.FailureMechanismEntityId == storageId); + Assert.IsInstanceOf(entity); + Assert.AreEqual(storageId, entity.FailureMechanismEntityId); + + mockRepository.VerifyAll(); + } + + [Test] + public void RemoveUnModifiedEntries_MultipleEntitiesInnParentNavigationPropertySingleModelStorageId_UpdatedPipingFailureMechanismAsEntityAndOtherDeletedInDbSet() + { + // Setup + const long storageId = 1234L; + FailureMechanismEntity entityToUpdate = new FailureMechanismEntity + { + FailureMechanismEntityId = storageId, + FailureMechanismType = (int) FailureMechanismType.PipingFailureMechanism + }; + FailureMechanismEntity entityToDelete = new FailureMechanismEntity + { + FailureMechanismEntityId = 4567L, + FailureMechanismType = (int) FailureMechanismType.PipingFailureMechanism + }; + + IList parentNavigationProperty = new List + { + entityToDelete, + entityToUpdate + }; + var dbset = DbTestSet.GetDbTestSet(mockRepository, parentNavigationProperty); + dbset.Expect(x => x.Remove(entityToDelete)).Return(entityToDelete); + + var ringtoetsEntities = mockRepository.StrictMock(); + ringtoetsEntities.Expect(x => x.FailureMechanismEntities).Return(dbset); + + PipingFailureMechanismPersistor persistor = new PipingFailureMechanismPersistor(ringtoetsEntities); + PipingFailureMechanism pipingFailureMechanism = new PipingFailureMechanism + { + StorageId = storageId + }; + mockRepository.ReplayAll(); + + TestDelegate updateTest = () => persistor.UpdateModel(parentNavigationProperty, pipingFailureMechanism); + Assert.DoesNotThrow(updateTest, "Precondition failed: Update should not throw exception."); + + // Call + persistor.RemoveUnModifiedEntries(parentNavigationProperty); + + // Assert + Assert.AreEqual(2, parentNavigationProperty.Count); + Assert.IsInstanceOf(entityToUpdate); + Assert.AreEqual(storageId, entityToUpdate.FailureMechanismEntityId); + + mockRepository.VerifyAll(); + } + + [Test] + public void RemoveUnModifiedEntries_MultipleEntitiesInParentNavigationPropertyEmptyPipingFailureMechanism_EmptyDatabaseSet() + { + // Setup + FailureMechanismEntity firstEntityToDelete = new FailureMechanismEntity + { + FailureMechanismEntityId = 1234L, + FailureMechanismType = (int) FailureMechanismType.PipingFailureMechanism + }; + FailureMechanismEntity secondEntityToDelete = new FailureMechanismEntity + { + FailureMechanismEntityId = 4567L, + FailureMechanismType = (int) FailureMechanismType.PipingFailureMechanism + }; + IList parentNavigationProperty = new List + { + firstEntityToDelete, + secondEntityToDelete + }; + + var dbset = DbTestSet.GetDbTestSet(mockRepository, parentNavigationProperty); + dbset.Expect(x => x.Remove(firstEntityToDelete)).Return(firstEntityToDelete); + dbset.Expect(x => x.Remove(secondEntityToDelete)).Return(secondEntityToDelete); + + var ringtoetsEntities = mockRepository.StrictMock(); + ringtoetsEntities.Expect(x => x.FailureMechanismEntities).Return(dbset).Repeat.Twice(); + PipingFailureMechanismPersistor persistor = new PipingFailureMechanismPersistor(ringtoetsEntities); + + PipingFailureMechanism pipingFailureMechanism = new PipingFailureMechanism(); + mockRepository.ReplayAll(); + + TestDelegate test = () => persistor.UpdateModel(parentNavigationProperty, pipingFailureMechanism); + Assert.DoesNotThrow(test, "Precondition failed: UpdateModel"); + + // Call + persistor.RemoveUnModifiedEntries(parentNavigationProperty); + + // Assert + mockRepository.VerifyAll(); + } + + [Test] + public void PerformPostSaveActions_NoInserts_DoesNotThrowException() + { + // Setup + var ringtoetsEntities = mockRepository.StrictMock(); + PipingFailureMechanismPersistor persistor = new PipingFailureMechanismPersistor(ringtoetsEntities); + mockRepository.ReplayAll(); + + // Call + TestDelegate test = () => persistor.PerformPostSaveActions(); + + // Assert + Assert.DoesNotThrow(test); + + mockRepository.VerifyAll(); + } + + [Test] + [TestCase(0)] + [TestCase(1)] + [TestCase(2)] + public void PerformPostSaveActions_MultipleModelsInsertedWithoutStorageId_ModelsWithStorageId(int numberOfInserts) + { + // Setup + var insertedFailureMechanismEntities = new List(); + var parentNavigationPropertyMock = mockRepository.StrictMock>(); + parentNavigationPropertyMock.Expect(m => m.Add(null)).IgnoreArguments().WhenCalled(x => + { + var insertedDikeAssessmentSectionEntity = x.Arguments.GetValue(0); + Assert.IsInstanceOf(insertedDikeAssessmentSectionEntity); + insertedFailureMechanismEntities.Add((FailureMechanismEntity) insertedDikeAssessmentSectionEntity); + }).Repeat.Times(numberOfInserts); + + IList pipingFailureMechanisms = new List(); + for (var i = 0; i < numberOfInserts; i++) + { + pipingFailureMechanisms.Add(new PipingFailureMechanism + { + StorageId = 0L + }); + } + + var ringtoetsEntities = mockRepository.StrictMock(); + PipingFailureMechanismPersistor persistor = new PipingFailureMechanismPersistor(ringtoetsEntities); + mockRepository.ReplayAll(); + + foreach (var pipingFailureMechanism in pipingFailureMechanisms) + { + try + { + persistor.UpdateModel(parentNavigationPropertyMock, pipingFailureMechanism); + } + catch (Exception) + { + Assert.Fail("Precondition failed: persistor.UpdateModel"); + } + } + + // Call + for (var i = 0; i < insertedFailureMechanismEntities.Count; i++) + { + insertedFailureMechanismEntities[i].FailureMechanismEntityId = 1L + i; + } + persistor.PerformPostSaveActions(); + + // Assert + Assert.AreEqual(pipingFailureMechanisms.Count, insertedFailureMechanismEntities.Count); + foreach (var entity in insertedFailureMechanismEntities) + { + var insertedModel = pipingFailureMechanisms.SingleOrDefault(x => x.StorageId == entity.FailureMechanismEntityId); + Assert.IsInstanceOf(insertedModel); + } + + mockRepository.VerifyAll(); + } + } +} \ No newline at end of file Index: Application/Ringtoets/test/Application.Ringtoets.Storage.Test/test-data/DatabaseFiles/ValidRingtoetsDatabase.rtd =================================================================== diff -u -re7acba10209b18e88bf89d9211f6fc031d0f992e -r3c1b05ca357443b861187ba196b806ebab57a929 Binary files differ Index: Ringtoets/Common/src/Ringtoets.Common.Data/BaseFailureMechanism.cs =================================================================== diff -u -r4512af7782ee31b36941bb280b54d9da2953dd71 -r3c1b05ca357443b861187ba196b806ebab57a929 --- Ringtoets/Common/src/Ringtoets.Common.Data/BaseFailureMechanism.cs (.../BaseFailureMechanism.cs) (revision 4512af7782ee31b36941bb280b54d9da2953dd71) +++ Ringtoets/Common/src/Ringtoets.Common.Data/BaseFailureMechanism.cs (.../BaseFailureMechanism.cs) (revision 3c1b05ca357443b861187ba196b806ebab57a929) @@ -49,6 +49,14 @@ } } + /// + /// Gets or sets the name of the failure mechanism. + /// public string Name { get; protected set; } + + /// + /// Gets or sets the unique identifier for the storage of the class. + /// + public long StorageId { get; set; } } } \ No newline at end of file Index: Ringtoets/Common/src/Ringtoets.Common.Data/IFailureMechanism.cs =================================================================== diff -u -r4512af7782ee31b36941bb280b54d9da2953dd71 -r3c1b05ca357443b861187ba196b806ebab57a929 --- Ringtoets/Common/src/Ringtoets.Common.Data/IFailureMechanism.cs (.../IFailureMechanism.cs) (revision 4512af7782ee31b36941bb280b54d9da2953dd71) +++ Ringtoets/Common/src/Ringtoets.Common.Data/IFailureMechanism.cs (.../IFailureMechanism.cs) (revision 3c1b05ca357443b861187ba196b806ebab57a929) @@ -20,13 +20,14 @@ // All rights reserved. using System; +using Core.Common.Base.Storage; namespace Ringtoets.Common.Data { /// /// Defines a failure mechanism. /// - public interface IFailureMechanism + public interface IFailureMechanism : IStorable { /// /// Gets the amount of contribution as a percentage (0-100) for the