Skip to content

Commit 4885958

Browse files
committed
Merge branch 'feature/collection.IsFullyLoaded' into develop
Introduced an `IsFullyLoaded` property to both the `TopicRelationshipMultiMap` and `TopicReferenceDictionary` collections. If, during `ITopicRepository.Load()`, a `Target_TopicID` cannot be discovered within the scoped topic graph—either from the e.g. `GetTopics` call, or from the `referenceTopic` graph—then `IsFullyLoaded` is set to `false`, indicating that the in-memory collection doesn't fully represent the saved state of the `Topic`. In this case, when `ITopicRepository.Save()` is called, `UpdateRelationships` and/or `UpdateReferences` will disable `DeleteUnmatched` in order to protect against a scenario where these target topics are inadvertently deleted. This should be a rare scenario. Nevertheless, it helps safeguard against potential data integrity issues when loading individual topics or topic branches with a missing or incomplete `referenceTopic` parameter.
2 parents 1d122e0 + 20f2fc5 commit 4885958

File tree

4 files changed

+59
-7
lines changed

4 files changed

+59
-7
lines changed

OnTopic.Data.Sql/SqlDataReaderExtensions.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -364,8 +364,11 @@ private static void SetRelationships(this SqlDataReader reader, TopicIndex topic
364364
related = topics[targetTopicId];
365365
}
366366

367-
// Bypass if either of the objects are missing
368-
if (related is null) return;
367+
// Bypass if the target object is missing
368+
if (related is null) {
369+
current.Relationships.IsFullyLoaded = false;
370+
return;
371+
}
369372

370373
/*------------------------------------------------------------------------------------------------------------------------
371374
| Set relationship on object
@@ -417,8 +420,11 @@ private static void SetReferences(this SqlDataReader reader, TopicIndex topics,
417420
referenced = topics[targetTopicId.Value];
418421
}
419422

420-
// Bypass if either of the objects are missing
421-
if (referenced is null) return;
423+
// Bypass if the target object is missing
424+
if (referenced is null) {
425+
current.References.IsFullyLoaded = false;
426+
return;
427+
}
422428

423429
/*------------------------------------------------------------------------------------------------------------------------
424430
| Set relationship on object

OnTopic.Data.Sql/SqlTopicRepository.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,7 @@ private static void PersistRelations(Topic topic, SqlDateTime version, SqlConnec
684684
command.AddParameter("RelationshipKey", key);
685685
command.AddParameter("RelatedTopics", targetIds);
686686
command.AddParameter("Version", version.Value);
687-
command.AddParameter("DeleteUnmatched", true);
687+
command.AddParameter("DeleteUnmatched", topic.Relationships.IsFullyLoaded);
688688

689689
command.ExecuteNonQuery();
690690

@@ -743,7 +743,7 @@ private static void PersistReferences(Topic topic, SqlDateTime version, SqlConne
743743
command.AddParameter("TopicID", topicId);
744744
command.AddParameter("ReferencedTopics", references);
745745
command.AddParameter("Version", version.Value);
746-
command.AddParameter("DeleteUnmatched", true);
746+
command.AddParameter("DeleteUnmatched", topic.References.IsFullyLoaded);
747747

748748
command.ExecuteNonQuery();
749749

OnTopic/References/TopicReferenceDictionary.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using OnTopic.Attributes;
1010
using OnTopic.Internal.Diagnostics;
1111
using OnTopic.Internal.Reflection;
12+
using OnTopic.Repositories;
1213

1314
namespace OnTopic.References {
1415

@@ -61,11 +62,33 @@ public TopicReferenceDictionary(Topic parent) {
6162
public int Count => _storage.Count;
6263

6364
/*==========================================================================================================================
64-
| IsReadOnly
65+
| IS READ ONLY?
6566
\-------------------------------------------------------------------------------------------------------------------------*/
6667
/// <inheritdoc/>
6768
public bool IsReadOnly => false;
6869

70+
/*==========================================================================================================================
71+
| IS FULLY LOADED?
72+
\-------------------------------------------------------------------------------------------------------------------------*/
73+
/// <summary>
74+
/// Determines whether or not the collection was fully loaded from the persistence store.
75+
/// </summary>
76+
/// <remarks>
77+
/// <para>
78+
/// When loading an individual <see cref="Topic"/> or branch from the persistence store, it is possible that topic
79+
/// references may not be fully available. In this scenario, updating topic references while e.g. deleting unmatched
80+
/// relationships can result in unintended data loss. To account for this, the <see cref="IsFullyLoaded"/> property '
81+
/// tracks whether a collection was fully loaded from the persistence store; if it wasn't, the <see cref="
82+
/// ITopicRepository"/> should not deleted unmatched topic references.
83+
/// </para>
84+
/// <para>
85+
/// The <see cref="IsFullyLoaded"/> property defaults to <c>true</c>. It should be set to <c>false</c> during the <see cref="
86+
/// ITopicRepository.Load(String?, Topic?, Boolean)"/> method if any members of the collection cannot be mapped back to
87+
/// a valid <see cref="Topic"/> reference in memory.
88+
/// </para>
89+
/// </remarks>
90+
public bool IsFullyLoaded { get; set; } = true;
91+
6992
/*==========================================================================================================================
7093
| ITEM
7194
\-------------------------------------------------------------------------------------------------------------------------*/

OnTopic/References/TopicRelationshipMultiMap.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Collections.Generic;
88
using OnTopic.Collections;
99
using OnTopic.Internal.Diagnostics;
10+
using OnTopic.Repositories;
1011

1112
namespace OnTopic.References {
1213

@@ -210,6 +211,28 @@ internal void SetTopic(string relationshipKey, Topic topic, bool? markDirty, boo
210211

211212
}
212213

214+
/*==========================================================================================================================
215+
| IS FULLY LOADED?
216+
\-------------------------------------------------------------------------------------------------------------------------*/
217+
/// <summary>
218+
/// Determines whether or not the collection was fully loaded from the persistence store.
219+
/// </summary>
220+
/// <remarks>
221+
/// <para>
222+
/// When loading an individual <see cref="Topic"/> or branch from the persistence store, it is possible that the
223+
/// relationships may not be fully available. In this scenario, updating relationships while e.g. deleting unmatched
224+
/// relationships can result in unintended data loss. To account for this, the <see cref="IsFullyLoaded"/> property
225+
/// tracks whether a collection was fully loaded from the persistence store; if it wasn't, the <see cref="
226+
/// ITopicRepository"/> should not deleted unmatched relationships.
227+
/// </para>
228+
/// <para>
229+
/// The <see cref="IsFullyLoaded"/> property defaults to <c>true</c>. It should be set to <c>false</c> during the <see cref="
230+
/// ITopicRepository.Load(String?, Topic?, Boolean)"/> method if any members of the collection cannot be mapped back to
231+
/// a valid <see cref="Topic"/> reference in memory.
232+
/// </para>
233+
/// </remarks>
234+
public bool IsFullyLoaded { get; set; } = true;
235+
213236
/*==========================================================================================================================
214237
| METHOD: IS DIRTY?
215238
\-------------------------------------------------------------------------------------------------------------------------*/

0 commit comments

Comments
 (0)