///<summary>Uses reflection to invoke private methods of the ConvertDatabase class in order from least to greatest if needed.
 ///The old way of converting the database was to manually daisy chain methods together.
 ///The new way is to just add a method that follows a strict naming pattern which this method will invoke when needed.</summary>
 public static void InvokeConvertMethods()
 {
     DataConnection.CommandTimeout = 43200; //12 hours, because conversion commands may take longer to run.
     ConvertDatabases.To2_8_2();            //begins going through the chain of conversion steps
     Logger.DoVerboseLoggingArgs doVerboseLogging = Logger.DoVerboseLogging;
     ODException.SwallowAnyException(() => {
         //Need to run queries here because PrefC has not been initialized.
         string command     = "SELECT ValueString FROM preference WHERE PrefName='HasVerboseLogging'";
         string valueString = Db.GetScalar(command);
         if (valueString.ToLower().Split(',').ToList().Exists(x => x == Environment.MachineName.ToLower()))
         {
             Logger.DoVerboseLogging = () => true;
             //Switch logger to a directory that won't have permissions issues.
             Logger.UseMyDocsDirectory();
         }
         Logger.LogVerbose("Starting convert script");
     });
     //Continue going through the chain of conversion methods starting at v17.1.1 via reflection.
     //Loop through the list of convert databases methods from front to back because it has already been sorted (least to greatest).
     foreach (ConvertDatabasesMethodInfo convertMethodInfo in ListConvertMethods)
     {
         //This pattern of using reflection to invoke our convert methods started in v17.1 so we will skip all methods prior to that version.
         if (convertMethodInfo.VersionCur < new Version(17, 1))
         {
             continue;
         }
         //Skip all methods that are below or equal to our "from" version.
         if (convertMethodInfo.VersionCur <= FromVersion)
         {
             continue;
         }
         //This convert method needs to be invoked.
         ODEvent.Fire(ODEventType.ConvertDatabases, "Upgrading database to version: " //No translations in convert script.
                      + convertMethodInfo.VersionCur.ToString(3));                    //Only show the major, minor, build (preserves old functionality).
         try {
             //Use reflection to invoke the private static method.
             convertMethodInfo.MethodInfoCur.Invoke(null, new object[] { });
         }
         catch (Exception ex) {
             string message = Lans.g("ClassConvertDatabase", "Convert Database failed ");
             try {
                 string methodName = convertMethodInfo.MethodInfoCur.Name;
                 if (!string.IsNullOrEmpty(methodName))
                 {
                     message += Lans.g("ClassConvertDatabase", "during: ") + methodName + "() ";
                 }
                 string command = Db.LastCommand;
                 if (!string.IsNullOrEmpty(command))
                 {
                     message += Lans.g("ClassConvertDatabase", "while running: ") + command + ";";
                 }
             }
             catch (Exception e) {
                 e.DoNothing();                        //If this fails for any reason then just continue.
             }
             throw new Exception(message + "  " + ex.Message + "  " + ex.InnerException.Message, ex.InnerException);
         }
         //Update the preference that keeps track of what version Open Dental has successfully upgraded to.
         //Always require major, minor, build, revision.  Will throw an exception if the revision was not explicitly set (which we always set).
         Prefs.UpdateStringNoCache(PrefName.DataBaseVersion, convertMethodInfo.VersionCur.ToString(4));
     }
     ODException.SwallowAnyException(() => {
         Logger.LogVerbose("Ending convert script");
         Logger.DoVerboseLogging = doVerboseLogging;
     });
     DataConnection.CommandTimeout = 3600;          //Set back to default of 1 hour.
 }