1212using System . Linq ;
1313using System . Text ;
1414using Microsoft . Data . SqlClient ;
15+ using OnTopic . Collections ;
1516using OnTopic . Data . Sql . Models ;
1617using OnTopic . Internal . Diagnostics ;
1718using OnTopic . Querying ;
@@ -335,79 +336,16 @@ public override void Refresh(Topic referenceTopic, DateTime since) {
335336 /*==========================================================================================================================
336337 | METHOD: SAVE
337338 \-------------------------------------------------------------------------------------------------------------------------*/
338- /// <inheritdoc />
339- public override void Save ( [ NotNull ] Topic topic , bool isRecursive = false ) {
340-
341- /*------------------------------------------------------------------------------------------------------------------------
342- | Establish dependencies
343- \-----------------------------------------------------------------------------------------------------------------------*/
344- var version = DateTime . UtcNow ;
345- var unresolvedTopics = new List < Topic > ( ) ;
346-
347- using var connection = new SqlConnection ( _connectionString ) ;
348-
349- connection . Open ( ) ;
350-
351- /*------------------------------------------------------------------------------------------------------------------------
352- | Handle first pass
353- \-----------------------------------------------------------------------------------------------------------------------*/
354- Save ( topic , isRecursive , connection , unresolvedTopics , version ) ;
355-
356- /*------------------------------------------------------------------------------------------------------------------------
357- | Attempt to resolve outstanding relationships
358- \-----------------------------------------------------------------------------------------------------------------------*/
359- foreach ( var unresolvedTopic in unresolvedTopics ) {
360- Save ( unresolvedTopic , false , connection , unresolvedTopics , version ) ;
361- }
362-
363- /*------------------------------------------------------------------------------------------------------------------------
364- | Close shared connection
365- \-----------------------------------------------------------------------------------------------------------------------*/
366- connection . Close ( ) ;
367-
368- }
369-
370- /// <summary>
371- /// The private overload of the <see cref="Save"/> method provides support for sharing the <see cref="SqlConnection"/>
372- /// between multiple requests, and maintaining a list of <paramref name="unresolvedRelationships"/>.
373- /// </summary>
374- /// <remarks>
375- /// <para>
376- /// When recursively saving a topic graph, it is conceivable that references to other topics—such as <see
377- /// cref="Topic.Relationships"/> or <see cref="Topic.DerivedTopic"/>—can't yet be persisted because the target <see
378- /// cref="Topic"/> hasn't yet been saved, and thus the <see cref="Topic.Id"/> is still set to <c>-1</c>. To mitigate
379- /// this, the <paramref name="unresolvedRelationships"/> allows this private overload to keep track of unresolved
380- /// relationships. The public <see cref="Save(Topic, Boolean, Boolean)"/> overload uses this list to resave any topics
381- /// that include such references. This adds some overhead due to the duplicate <see cref="Save"/>, but helps avoid
382- /// potential data loss when working with complex topic graphs.
383- /// </para>
384- /// <para>
385- /// The connection sharing probably doesn't provide that much of a gain in that .NET does a good job of connection
386- /// pooling. Nevertheless, there is some overhead to opening a new connection, so sharing an open connection when we
387- /// doing a recursive save could potentially provide some performance benefit.
388- /// </para>
389- /// </remarks>
390- /// <param name="topic">The source <see cref="Topic"/> to save.</param>
391- /// <param name="isRecursive">Determines whether or not to recursively save <see cref="Topic.Children"/>.</param>
392- /// <param name="connection">The open <see cref="SqlConnection"/> to use for executing <see cref="SqlCommand"/>s.</param>
393- /// <param name="unresolvedRelationships">A list of <see cref="Topic"/>s with unresolved topic references.</param>
394- private void Save (
339+ /// <inheritdoc/>
340+ protected override sealed void Save (
395341 [ NotNull ] Topic topic ,
396- bool isRecursive ,
397- SqlConnection connection ,
398- List < Topic > unresolvedRelationships ,
399- DateTime version
342+ DateTime version ,
343+ bool persistRelationships
400344 ) {
401345
402- /*------------------------------------------------------------------------------------------------------------------------
403- | Call base method - will trigger any events associated with the save
404- \-----------------------------------------------------------------------------------------------------------------------*/
405- base . Save ( topic , isRecursive ) ;
406-
407346 /*------------------------------------------------------------------------------------------------------------------------
408347 | Define variables
409348 \-----------------------------------------------------------------------------------------------------------------------*/
410- var areReferencesResolved = true ;
411349 var isTopicDirty = topic . IsDirty ( ) ;
412350 var areRelationshipsDirty = topic . Relationships . IsDirty ( ) ;
413351 var areReferencesDirty = topic . References . IsDirty ( ) ;
@@ -440,7 +378,6 @@ DateTime version
440378 | Bypass is not dirty
441379 \-----------------------------------------------------------------------------------------------------------------------*/
442380 if ( ! isDirty ) {
443- recurse ( ) ;
444381 return ;
445382 }
446383
@@ -494,29 +431,15 @@ DateTime version
494431 /*------------------------------------------------------------------------------------------------------------------------
495432 | Establish database connection
496433 \-----------------------------------------------------------------------------------------------------------------------*/
434+ using var connection = new SqlConnection ( _connectionString ) ;
497435 var procedureName = topic . IsNew ? "CreateTopic" : "UpdateTopic" ;
498436
437+ connection . Open ( ) ;
438+
499439 using var command = new SqlCommand ( procedureName , connection ) {
500440 CommandType = CommandType . StoredProcedure
501441 } ;
502442
503- /*------------------------------------------------------------------------------------------------------------------------
504- | Handle unresolved references
505- >-------------------------------------------------------------------------------------------------------------------------
506- | If it's a recursive save and there are any unresolved relationships, come back to this after the topic graph has been
507- | saved; that ensures that any relationships within the topic graph have been saved and can be properly persisted. The
508- | same can be done for DerivedTopics references, which are effectively establish a 1:1 relationship.
509- \-----------------------------------------------------------------------------------------------------------------------*/
510- if (
511- isRecursive &&
512- ( topic . Relationships . Any ( r => r . Values . Any ( t => t . Id < 0 ) ) ||
513- topic . References . Values . Any ( t => t . Id < 0 )
514- )
515- ) {
516- unresolvedRelationships . Add ( topic ) ;
517- areReferencesResolved = false ;
518- }
519-
520443 /*------------------------------------------------------------------------------------------------------------------------
521444 | Establish query parameters
522445 \-----------------------------------------------------------------------------------------------------------------------*/
@@ -553,18 +476,14 @@ DateTime version
553476 "The call to the CreateTopic stored procedure did not return the expected 'Id' parameter."
554477 ) ;
555478
556- if ( areReferencesResolved && areRelationshipsDirty ) {
479+ if ( persistRelationships && areRelationshipsDirty ) {
557480 PersistRelations ( topic , version , connection ) ;
558481 }
559482
560- if ( areReferencesResolved && areReferencesDirty ) {
483+ if ( persistRelationships && areReferencesDirty ) {
561484 PersistReferences ( topic , version , connection ) ;
562485 }
563486
564- if ( ! topic . VersionHistory . Contains ( version ) ) {
565- topic . VersionHistory . Insert ( 0 , version ) ;
566- }
567-
568487 topic . Attributes . MarkClean ( version ) ;
569488
570489 }
@@ -580,20 +499,10 @@ DateTime version
580499 }
581500
582501 /*------------------------------------------------------------------------------------------------------------------------
583- | Recuse over any children
502+ | Close connection
584503 \-----------------------------------------------------------------------------------------------------------------------*/
585- recurse ( ) ;
586-
587- /*------------------------------------------------------------------------------------------------------------------------
588- | Function: Recurse
589- \-----------------------------------------------------------------------------------------------------------------------*/
590- void recurse ( ) {
591- if ( isRecursive ) {
592- foreach ( var childTopic in topic . Children ) {
593- childTopic . Attributes . SetValue ( "ParentID" , topic . Id . ToString ( CultureInfo . InvariantCulture ) ) ;
594- Save ( childTopic , isRecursive , connection , unresolvedRelationships , version ) ;
595- }
596- }
504+ finally {
505+ connection . Close ( ) ;
597506 }
598507
599508 }
0 commit comments