File Exists BAQ

I have a UBAQ that runs a little C# in post processing GetList to check if a file exists. It works fine in a dashboard because I can filter the grid in the dashboard, but I would like to have it show up in the BAQ gadget, which does not have the ability to filter post BAQ. Does anyone know of a way to check for a network file comparing it to a calculated field and have it filtered in the BAQ? Reference this old thread. (I keep asking the question because I keep getting in trouble for not checking in time.)

Can I delete rows in the ttTable in the post processing BPM?

Sure I don’t see why not

Any tips on how to do that? I have a loop going through the grid already to set the exist field to true or false, can I delete the row in there as it loops? Or do I need to loop through this again to do the delete?

foreach(var x in ttResults)

{
  string[] files = Directory.GetFiles(x.Calculated_FileLocation,x.Calculated_FileName +"*");
  if (files.Length>0)
     {
      x.Calculated_FileExists = true;
      x.Calculated_FoundFileName = string.Join(",",files);
      x.Calculated_CountFilesFound = files.Count();
      }
    else
      {
      //do some deleting here?
      }
}

So I’m looking at the information in here. And it says you shouldn’t delete or remove in a for each loop. If I don’t loop through the table, how can I know which row to delete? I’m so confused.

One option is to create another array of strings with the filenames to delete. Add the filenames of the files to be deleted in the first loop and then run through the delete array afterwards.

Mark W.

I just want to delete the rows in the datatable in order to filter the results. I don’t want to delete the files.

But not by looping through the array. :slight_smile:

Right you have to loop using a for instead of a foreach and do it backwards.

1 Like

Ahhh. I thought you needed to “clean up” files that were out there. (Forgot the original business case…).

In short, you want to eliminate records that are not associated with a created file in the BAQ itself?

The reason you don’t want to delete the same records as the foreach, you may change the next pointer in the array so you skip the next record. Epicor kind of gets around this with the ROW_MOD = “D” so it marks it for deletion and then deletes the record on update. Most likely they are using an ADO command to do a delete where row_mod =“D” and not a foreach. You can use the array notation and go backwards to delete though.

Mark W.

What Jose said. :grinning:

This is what I have in there right now

foreach(var x in ttResults)

{
  string[] files = Directory.GetFiles(x.Calculated_FileLocation,x.Calculated_FileName +"*");
  if (files.Length>0)
     {
      x.Calculated_FileExists = true;
      x.Calculated_FoundFileName = string.Join(",",files);
      x.Calculated_CountFilesFound = files.Count();
      }
    if (files.Length > 0)
      {       
      ttResults.Remove(x);
      }    
      
 }

It compiles, but when I try to run the get list, is errors out like this.

Server Side Exception

BPM runtime caught an unexpected exception of 'InvalidOperationException' type.
See more info in the Inner Exception section of Exception Details.

Exception caught in: Epicor.ServiceModel

Error Detail 
============
Description:  BPM runtime caught an unexpected exception of 'InvalidOperationException' type.
See more info in the Inner Exception section of Exception Details.
Program:  CommonLanguageRuntimeLibrary
Method:  ThrowInvalidOperationException
Original Exception Type:  InvalidOperationException
Framework Method:  A001_CustomCodeAction
Framework Line Number:  0
Framework Column Number:  0
Framework Source:  A001_CustomCodeAction at offset 598 in file:line:column <filename unknown>:0:0

Server Trace Stack:     at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
   at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
   at Epicor.Customization.Bpm.Ubaq5A11D41C6861440D9591476882C857D1.GetListPostProcessingDirective_CheckFileExists_C751051625994AF3AAFA91A4676DB6B3.A001_CustomCodeAction()
   at Epicor.Customization.Bpm.Ubaq5A11D41C6861440D9591476882C857D1.GetListPostProcessingDirective_CheckFileExists_C751051625994AF3AAFA91A4676DB6B3.ExecuteCore()
   at Epicor.Customization.Bpm.DirectiveBase`3.Execute(TParam parameters) in C:\_Releases\ICE\ICE3.2.200.13\Source\Server\Internal\Lib\Epicor.Customization.BPM\DirectiveBase.Generic.cs:line 147



Client Stack Trace 
==================
   at Epicor.ServiceModel.Channels.ImplBase`1.ShouldRethrowNonRetryableException(Exception ex, DataSet[] dataSets)
   at Ice.Proxy.BO.DynamicQueryImpl.GetList(DynamicQueryDataSet queryDS, QueryExecutionDataSet executionParams, Int32 pageSize, Int32 absolutePage, Boolean& hasMorePage)
   at Ice.Adapters.DynamicQueryAdapter.<>c__DisplayClass35_0.<GetList>b__0(DataSet datasetToSend)
   at Ice.Adapters.DynamicQueryAdapter.ProcessUbaqMethod(String methodName, DataSet updatedDS, Func`2 methodExecutor, Boolean refreshQueryResultsDataset)
   at Ice.Adapters.DynamicQueryAdapter.GetList(DynamicQueryDataSet queryDS, QueryExecutionDataSet execParams, Int32 pageSize, Int32 absolutePage, Boolean& hasMorePage)
   at Ice.UI.App.BAQDesignerEntry.BAQTransaction.TestCallListBckg()
   at Ice.UI.App.BAQDesignerEntry.BAQTransaction.<>c__DisplayClass221_0.<BeginExecute>b__0()
   at System.Threading.Tasks.Task.InnerInvoke()
   at System.Threading.Tasks.Task.Execute()

Inner Exception 
===============
Collection was modified; enumeration operation may not execute.

That’s probably why I’m not supposed to do that.

So I do the for each loop, and in that loop get a row count, then use a for loop with that count and go through the array again to remove the rows that I don’t want displayed.

http://www.tutorialsteacher.com/csharp/csharp-for-loop

Does that sound correct or am I over complicating it? This is new to me so bear with me.

1 Like
for(int i=ttResults.Count-1; i>=0;i--)
{
           ttResults.Remove(ttResults[i]);
}
1 Like

Perfect. I was getting pretty close to what you gave me, but I was getting screwed up with syntax for the rows.
This is what I ended up with everything. It’s checking for a file in a master location, and for a file in a holding location. Those are the 2 string sections. Then the for loop that you helped with at the end to remove any rows that are true in the master location.

Thanks guys!!

foreach(var x in ttResults)
{
  string[] files = Directory.GetFiles(x.Calculated_FileLocation,x.Calculated_FileName +"*");
  if (files.Length>0)
     {
      x.Calculated_FileExists = true;
      x.Calculated_FoundFileName = string.Join(",",files);
      x.Calculated_CountFilesFound = files.Count();
      }
  
  string[] Holdfiles = Directory.GetFiles(x.Calculated_HoldFileLocation,x.Calculated_FileName +"*",System.IO.SearchOption.AllDirectories);
  if (Holdfiles.Length>0)
     {
      x.Calculated_HoldFileExists = true;
      x.Calculated_HoldFoundFileName = string.Join(",",Holdfiles);
      }
        
 }
   for (int i = ttResults.Count-1; i>=0;i--)
     {
        if (ttResults[i].Calculated_FileExists == true)
        {       
        ttResults.Remove(ttResults[i]);
        }
}

You could make that in a single loop if you wanted to. Just a comment,

Loop through backwards (for loop) inside check if file exists, if it does remove, else… check Hold Files and assign variables.

That makes sense.

It has to go backwards because the rows are changing as you loop through right? So if you start at the max and go to 0 you can get away with deleting the rows at the end?

Correct. you are modifying the collection as you loop so you need to go backwards if you were going forward then the index would be outside the bounds of the array. Like on the 10th loop index =9 but if you deleted 3 items then the length of the array may be 7 and you’d get an exception.

1 Like

I was getting an exception when I was trying things out. I was about to ask why, and that explains it.

1 Like