private void afElementFindCtrl1_AFElementUpdated(object sender, CancelEventArgs e) { _TargetElement = afElementFindCtrl1.AFElement; //Resets attribute filter state ReinitializeAttributeFilter(); }
private void btnDatabase_Click(object sender, EventArgs e) { OSIsoft.AF.AFDatabase dbSelected = OSIsoft.AF.UI.AFOperations.SelectDatabase(this, _AFServer, _AFDB); if (dbSelected == null) { MessageBox.Show("Database was not changed", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); } else { _AFDB = dbSelected; afElementFindCtrl1.Text = ""; _TargetElement = null; afElementFindCtrl1.Database = _AFDB; this.Text = _AFDB.GetPath() + " - PI Analysis Output Bulk Deleter"; } }
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { List <object> args = (List <object>)e.Argument; OSIsoft.AF.Asset.AFValues afValues = new OSIsoft.AF.Asset.AFValues(); //Parsing arguments from object sender DateTime dtStartTime = (DateTime)args[0]; //start time DateTime dtEndTime = (DateTime)args[1]; //end time OSIsoft.AF.Asset.AFElement elTargetElement = (OSIsoft.AF.Asset.AFElement)args[2]; //target AF element int opCode = ((int)args[3]); //operation code (delete pi tags only, EF only or both) string attrPathFilter = ((string)args[4]); //filter by attribute name using wildcards (*, ?) DateTime writeTime = dtStartTime; OSIsoft.AF.Time.AFTimeRange timeRange = new OSIsoft.AF.Time.AFTimeRange(dtStartTime, dtEndTime); backgroundWorker1.ReportProgress(0, "Searching elements for data deletion..."); OSIsoft.AF.AFNamedCollectionList <OSIsoft.AF.Asset.AFElement> AnalysesElements; if (ckbIncludeChildElements.Checked) //Searchs for child elements { AnalysesElements = OSIsoft.AF.Asset.AFElement.FindElements(_AFDB, _TargetElement, "*", OSIsoft.AF.AFSearchField.Name, true, OSIsoft.AF.AFSortField.Name, OSIsoft.AF.AFSortOrder.Ascending, iMaxRetrievedObjects); } else //just creates an empty list { AnalysesElements = new OSIsoft.AF.AFNamedCollectionList <OSIsoft.AF.Asset.AFElement>(); } //Add the target element if (_TargetElement != null) { AnalysesElements.Add(_TargetElement); //Including the root element to be processed too } backgroundWorker1.ReportProgress(0, AnalysesElements.Count.ToString() + " elements found.\n"); double elementCount = AnalysesElements.Count; double operationsCount = 1; int processingElementCount = 1; //Searching all elements in the list to obtain the attributes used as analyses outputs foreach (var element in AnalysesElements) { if (backgroundWorker1.CancellationPending) { backgroundWorker1.ReportProgress(100, "Delete operation cancelled.\n"); return; } //Used to track operation progress - ##### not being used because I changed the progress bar style to marquee ##### int progressPercent = (int)(operationsCount / elementCount * 100); //int numOfEventsDeleted = 0; //Reporting the order of the element being processed backgroundWorker1.ReportProgress(processingElementCount, "Processing element " + processingElementCount.ToString() + " of " + elementCount.ToString() + "...\n"); processingElementCount++; //Obtaining the list of analysis associated with the current element OSIsoft.AF.AFNamedCollectionList <OSIsoft.AF.Analysis.AFAnalysis> elAnalyses = element.GetAnalyses(OSIsoft.AF.AFSortField.Name, OSIsoft.AF.AFSortOrder.Ascending, element.Analyses.Count + 1); if (opCode == 0 || opCode == 2) //To be executed if asked to delete PI Values only or (PI Values + EFs) { backgroundWorker1.ReportProgress(progressPercent, "Deleting analyses output attributes from " + element.GetPath() + "...\n"); //Obtaining the list of attributes that are PI Point DRs associated with the analyses List <OSIsoft.AF.Asset.AFAttribute> attrOutputs = GetAnalysesOutputPointDR(elAnalyses); //Using parallelism to speed up the deletes Parallel.ForEach(attrOutputs, new ParallelOptions() { MaxDegreeOfParallelism = iAFThreadCount }, (attr) => //foreach (var attr in attrOutputs) { OSIsoft.AF.Asset.AFValues values = null; int valueCount = 0; if (_AttributeListFilterIsActive) { bool bValueFound; //Flag to inform if the attr is selected in the filter list bool IsSelected = _AttributeFilter.TryGetValue(attr.GetPath(), out bValueFound); if (bValueFound) { //Perform the tasks //Search values if the attribute is selected in the attribute list filter if (IsSelected) { backgroundWorker1.ReportProgress(progressPercent, "Deleting values from attribute " + attr.GetPath() + "...\n"); values = attr.Data.RecordedValues(timeRange, OSIsoft.AF.Data.AFBoundaryType.Inside, null, null, true); valueCount = values.Count(); backgroundWorker1.ReportProgress(progressPercent, "Deleting " + valueCount.ToString() + " values from attribute " + attr.GetPath() + "...\n"); } } else { //backgroundWorker1.ReportProgress(progressPercent, "The attribute " + attr.GetPath() + " was not processed (filtered out). \n"); //values = attr.Data.RecordedValues(timeRange, OSIsoft.AF.Data.AFBoundaryType.Inside, null, null, true); } } else { //Search values only for those attributes included by the attribute path filter // of if the filter is empty (not set) //This will already return everything in upper case and convert the wild cards expressions to regular expressions string attrNameFilterRegExpression = WildcardToRegex(attrPathFilter); if (attrPathFilter == String.Empty || System.Text.RegularExpressions.Regex.IsMatch(attr.GetPath().ToUpper(), attrNameFilterRegExpression)) { values = attr.Data.RecordedValues(timeRange, OSIsoft.AF.Data.AFBoundaryType.Inside, null, null, true); valueCount = values.Count(); } else { //backgroundWorker1.ReportProgress(progressPercent, "The attribute " + attr.Name + " from element " + element.Name + " was not processed (filtered out). \n"); } } if (valueCount > 0) { try { //This is the new method supported only in PI Data Archive 2015 and above (don't need to retrieve all values - just pass the range) //attr.Data.ReplaceValues(timeRange, new OSIsoft.AF.Asset.AFValues(), OSIsoft.AF.Data.AFBufferOption.BufferIfPossible); //This is the only method supported for PI Data Archive 2015 and below (need to retrieve all values before deleting it) attr.Data.UpdateValues(values, OSIsoft.AF.Data.AFUpdateOption.Remove, OSIsoft.AF.Data.AFBufferOption.BufferIfPossible); backgroundWorker1.ReportProgress(progressPercent, "Deleted " + valueCount.ToString() + " values from " + attr.GetPath() + ".\n"); } catch { backgroundWorker1.ReportProgress(progressPercent, "Error deleting tag events from " + attr.GetPath() + ".\n"); } } if (backgroundWorker1.CancellationPending) { backgroundWorker1.ReportProgress(100, "Delete operation cancelled.\n"); return; } //numOfEventsDeleted += values.Count; --> Can't use this "as is" inside the paralle foreach loop, otherwise we lose parallelism efficiency }); int numAttrFilteredOut = GetAttributeFilteredCount(); int numAttrProcessed = attrOutputs.Count - numAttrFilteredOut; //backgroundWorker1.ReportProgress(progressPercent, numOfEventsDeleted.ToString() + " tag events were deleted from " + attrOutputs.Count.ToString() + " analysis output(s)\n"); backgroundWorker1.ReportProgress(progressPercent, "Finished processing PI values deletion for element " + element.GetPath() + ".\n"); } if (opCode == 1 || opCode == 2) //To be executed if asked to delete EFs only or (PI Values + EFs) { /* * foreach (var analysis in elAnalyses) * { * // var analysesEventFrameList = OSIsoft.AF.EventFrame.AFEventFrame.FindEventFramesByAnalysis(analysis, OSIsoft.AF.Asset.AFSearchMode.Overlapped, * // timeRange.StartTime, timeRange.EndTime, OSIsoft.AF.AFSortField.Name, OSIsoft.AF.AFSortOrder.Ascending, 0, iMaxRetrievedObjects); * } */ backgroundWorker1.ReportProgress(progressPercent, "Searching event frames for the " + element.Name + " element.\n"); var analysesEventFrameList = element.GetEventFrames(OSIsoft.AF.Asset.AFSearchMode.StartInclusive, timeRange.StartTime, timeRange.EndTime, "*", null, null, OSIsoft.AF.AFSortField.StartTime, OSIsoft.AF.AFSortOrder.Ascending, 0, iMaxRetrievedObjects); int efCount = analysesEventFrameList.Count; //Deleting each individual event frame from the current element Parallel.ForEach(analysesEventFrameList, new ParallelOptions() { MaxDegreeOfParallelism = iAFThreadCount }, (ef) => //foreach (var ef in analysesEventFrameList) { try { ef.Delete(); } catch { backgroundWorker1.ReportProgress(progressPercent, "Error deleting the following event: " + ef.Name); } }); backgroundWorker1.ReportProgress(progressPercent, "Deleted " + efCount.ToString() + " event frames from the " + element.Name + " element.\n"); //Commiting changes to database _AFDB.CheckIn(); } //Update counter used to calculate the operation progress operationsCount++; } backgroundWorker1.ReportProgress(100, "Operation completed.\n"); }