|
4 | 4 | | Project Topics Library
|
5 | 5 | \=============================================================================================================================*/
|
6 | 6 | using System;
|
| 7 | +using System.Collections.Generic; |
7 | 8 | using System.Diagnostics.CodeAnalysis;
|
8 | 9 | using System.Globalization;
|
9 | 10 | using System.Linq;
|
10 | 11 | using OnTopic.Attributes;
|
11 | 12 | using OnTopic.Internal.Diagnostics;
|
| 13 | +using OnTopic.Mapping.Annotations; |
12 | 14 | using OnTopic.Querying;
|
13 | 15 |
|
14 | 16 | namespace OnTopic.Data.Transfer.Interchange {
|
@@ -161,6 +163,72 @@ public static TopicData Export(this Topic topic, [NotNull]ExportOptions? options
|
161 | 163 | /// <param name="options">An optional <see cref="ImportOptions"/> object to specify import settings.</param>
|
162 | 164 | public static void Import(this Topic topic, TopicData topicData, [NotNull]ImportOptions? options = null) {
|
163 | 165 |
|
| 166 | + /*------------------------------------------------------------------------------------------------------------------------ |
| 167 | + | Establish cache |
| 168 | + \-----------------------------------------------------------------------------------------------------------------------*/ |
| 169 | + var unresolvedRelationships = new List<Tuple<Topic, string, string>>(); |
| 170 | + |
| 171 | + /*------------------------------------------------------------------------------------------------------------------------ |
| 172 | + | Handle first pass |
| 173 | + \-----------------------------------------------------------------------------------------------------------------------*/ |
| 174 | + topic.Import(topicData, options, unresolvedRelationships); |
| 175 | + |
| 176 | + /*------------------------------------------------------------------------------------------------------------------------ |
| 177 | + | Attempt to resolve outstanding relationships |
| 178 | + \-----------------------------------------------------------------------------------------------------------------------*/ |
| 179 | + foreach (var relationship in unresolvedRelationships) { |
| 180 | + |
| 181 | + //Attempt to find the target relationship |
| 182 | + var source = relationship.Item1; |
| 183 | + var target = topic.GetByUniqueKey(relationship.Item3); |
| 184 | + var key = relationship.Item2; |
| 185 | + |
| 186 | + //If the relationship STILL can't be resolved, skip it |
| 187 | + if (target == null) { |
| 188 | + continue; |
| 189 | + } |
| 190 | + |
| 191 | + //Wire up derived topics |
| 192 | + if (key.Equals("DerivedTopic")) { |
| 193 | + source.DerivedTopic = target; |
| 194 | + } |
| 195 | + |
| 196 | + //Wire up relationships |
| 197 | + else { |
| 198 | + source.Relationships.SetTopic(key, target); |
| 199 | + } |
| 200 | + |
| 201 | + } |
| 202 | + |
| 203 | + } |
| 204 | + |
| 205 | + /// <summary> |
| 206 | + /// Imports a <see cref="TopicData"/> data transfer object—and, potentially, its descendants—into an existing <see |
| 207 | + /// cref="Topic"/> entity. Track unmatched relationships. |
| 208 | + /// </summary> |
| 209 | + /// <remarks> |
| 210 | + /// <para> |
| 211 | + /// While traversing a topic graph with many new topics, scenarios emerge where the topic graph cannot be fully |
| 212 | + /// reconstructed since the relationships and derived topics may refer to new topics that haven't yet been imported. To |
| 213 | + /// mitigate that, this overload accepts and populates a cache of such relationships, so that they can be recreated |
| 214 | + /// afterwards. |
| 215 | + /// </para> |
| 216 | + /// <para> |
| 217 | + /// This does <i>not</i> address the scenario where implicit topic pointers (i.e., attributes ending in <c>Id</c>) |
| 218 | + /// cannot be resolved because the target topics haven't yet been saved—and, therefore, the <see |
| 219 | + /// cref="Topic.GetUniqueKey"/> cannot be translated to a <see cref="Topic.Id"/>. There isn't any obvious way to address |
| 220 | + /// this via <see cref="Import"/> directly. |
| 221 | + /// </para> |
| 222 | + /// </remarks> |
| 223 | + /// <param name="topic">The source <see cref="Topic"/> to operate off of.</param> |
| 224 | + /// <param name="options">An optional <see cref="ImportOptions"/> object to specify import settings.</param> |
| 225 | + private static void Import( |
| 226 | + this Topic topic, |
| 227 | + TopicData topicData, |
| 228 | + [NotNull]ImportOptions? options, |
| 229 | + List<Tuple<Topic, string, string>> unresolvedRelationships |
| 230 | + ) { |
| 231 | + |
164 | 232 | /*------------------------------------------------------------------------------------------------------------------------
|
165 | 233 | | Validate topic
|
166 | 234 | \-----------------------------------------------------------------------------------------------------------------------*/
|
@@ -194,7 +262,13 @@ public static void Import(this Topic topic, TopicData topicData, [NotNull]Import
|
194 | 262 | }
|
195 | 263 |
|
196 | 264 | if (topicData.DerivedTopicKey?.Length > 0) {
|
197 |
| - topic.DerivedTopic = topic.GetByUniqueKey(topicData.DerivedTopicKey)?? topic.DerivedTopic; |
| 265 | + var target = topic.GetByUniqueKey(topicData.DerivedTopicKey); |
| 266 | + if (target != null) { |
| 267 | + topic.DerivedTopic = target; |
| 268 | + } |
| 269 | + else { |
| 270 | + unresolvedRelationships.Add(new Tuple<Topic, string, string>(topic, "DerivedTopic", topicData.DerivedTopicKey)); |
| 271 | + } |
198 | 272 | }
|
199 | 273 |
|
200 | 274 | /*------------------------------------------------------------------------------------------------------------------------
|
@@ -272,7 +346,10 @@ public static void Import(this Topic topic, TopicData topicData, [NotNull]Import
|
272 | 346 | var relatedTopic = topic.GetByUniqueKey(relatedTopicKey);
|
273 | 347 | if (relationship.Key != null && relatedTopic != null) {
|
274 | 348 | topic.Relationships.SetTopic(relationship.Key, relatedTopic);
|
275 |
| - }; |
| 349 | + } |
| 350 | + else { |
| 351 | + unresolvedRelationships.Add(new Tuple<Topic, string, string>(topic, relationship.Key!, relatedTopicKey)); |
| 352 | + } |
276 | 353 | }
|
277 | 354 | }
|
278 | 355 |
|
|
0 commit comments