Quintiq file version 2.0 
 | 
#parent: #root 
 | 
StaticMethod CopyDatasetRobust (LibOpt_Task task, String namenewdataset, String componentpositionname,  
 | 
  Key mdsid) as LibOpt_SnapshotReplannableCopyDataset 
 | 
{ 
 | 
  Description: 
 | 
  [* 
 | 
    Copy the dataset in a slow (non-reactive) way that is robust against rollbacks and errors.  
 | 
    An optimizer run has to wait until the dataset copy is created before the optmizer run can continue.  
 | 
    Please override the `[YourOptimizationSubtype].GetMDSObject()` method before using this method. 
 | 
  *] 
 | 
  TextBody: 
 | 
  [* 
 | 
    // evr3 Mar-19-2020 (created) 
 | 
    component := task.Component(); 
 | 
    run := component.Run(); 
 | 
    snapshot := LibOpt_SnapshotReplannableCopyDataset::Create( run, 
 | 
                                                               task,  
 | 
                                                               namenewdataset,  
 | 
                                                               componentpositionname,                                               
 | 
                                                               true // IsMemoryOnly  
 | 
                                                               ); 
 | 
    // LibOpt_Optimization::GetMDSObject should be overridden. 
 | 
    mdsobject := LibOpt_DatasetCopyConditional::GetMDSObject( run.Optimization() ); 
 | 
    snapshot.IsGetMDSObjectOverridden( not isnull( mdsobject ) ); 
 | 
    snapshot.HasFailedToCreateDataset( isnull( mdsobject ) ); 
 | 
     
 | 
    // Create the dataset after creating the snapshot, to ensure that the snapshot shows up in the 'snapshots' and 'replannable snapshots' forms.  
 | 
    if( not isnull( mdsobject ) ) 
 | 
    { 
 | 
      parameters := MDSParameters::Create(); 
 | 
      // It is not possible to use StandAloneStorage. This results in empty datasets. 
 | 
      // The dataset is later converted to a StandAloneStorage dataset in LibOpt_Component::DatasetCopyChangeToStandAlone() 
 | 
      parameters.State( DatasetState::MemoryOnly().AsString() );   
 | 
     
 | 
      // An error can occur when mdsobject.Copy is called. 
 | 
      // This happens, for example, when a circularity is created in the current transaction (but not propagated). 
 | 
      // An error is also thrown if the name of the dataset copy is too long. 
 | 
      // When the error occurs, the following steps happen: 
 | 
      // - The onfailure block is entered 
 | 
      // - HandleQuillErrorFromOnFailure is called 
 | 
      // - If there is a dataset copy snapshot on the 'Handle error' component position, then the current method is called again. 
 | 
      // - The try block is entered again. 
 | 
      // - The dataset is copied succesfully (This dataset copy might be in a unpropagated or semi-propgated state) 
 | 
      // - The HandleQuillErrorFromOnFailure call will roll back the current iteration to resolve the propagation error 
 | 
       
 | 
      // Note: If another error happens when mdsobject.Copy is called the second time,  
 | 
      // then the if-block in the onfailure ensures that HandleQuillErrorFromOnFailure method won't be called again. This is to prevent an inescapable loop. 
 | 
      try 
 | 
      {  
 | 
        // Using mdsobject.Copy() is less efficient than using 'MDSObject::Create'.  
 | 
        // However, datasets created by using mdsobject.Copy() are not rolled back after an error or rollback.  
 | 
        mdsobject.Copy( namenewdataset, parameters );   
 | 
        snapshot.HasCreatedDataset( true ); 
 | 
      } 
 | 
      onfailure 
 | 
      { 
 | 
        snapshot.HasFailedToCreateDataset( true );     
 | 
        numberofsnapshots := counter( task, 
 | 
                                      SnapshotComponent.Children.astype( LibOpt_SnapshotReplannableCopyDataset ), 
 | 
                                      snapshotreplannable, 
 | 
                                      snapshotreplannable.ComponentPositionName() = componentpositionname ); 
 | 
        // In the unlikely case that a failure occurs every time that mdsobject.Copy() is called, then we could end up in an endless dataset creation loop. 
 | 
        // Therefore, we attempt to create at most 1 additional dataset copy. 
 | 
        if( numberofsnapshots <= 1 ) 
 | 
        { 
 | 
          transaction := LibOpt_CurrentTransaction::GetCurrentTransaction( component ); 
 | 
          transaction.HandleQuillErrorFromOnFailure( e ); 
 | 
        } 
 | 
      } 
 | 
    } 
 | 
     
 | 
    return snapshot; 
 | 
  *] 
 | 
  InterfaceProperties { Accessibility: 'Module' } 
 | 
} 
 |