In Script Editor, I have written a simple MACRO like below:
iCounter = 0
Set oObjectsList = GetSelection("query selecting my objects")
Print oObjectsList.Count() =======================> total = 5 for instance
For Each oListItem In oObjectsList
iCounter = iCounter + 1
Print iCounter =================================> 2 objects deleted for instance
Why the total number of deleted object is not equal to the total number of element in the array ? (no errors are displayed in the script editor when I execute the macro and nothing in logfile). To delete all objects I need to execute the same macro several times...not cool
Real example, if I create 7 objects one after the other:
-> only objects with odd numbers are deleted when the macro is executed for the first time
-> only Object-2 and Object-6 the second time
-> and Object-4 the last time.
If I do the same example several times, the behavior is exactly the same.
But if I modify the macro with renaming the objects instead of deleting them, ALL are renamed.
So it seems that this is an "issue" about the Delete method.
It is very weird. Any idea ?
Solved! Go to Solution.
to delete all objects from a collection, you should write
For i = 1 to oObjectsList.count oObjectsList.item(1).delete Next
For i = oObjectsList.count to 1 Step -1 oObjectsList.item(i).delete Next
If you write as you did
For Each oListItem In oObjectsList oListItem.Delete Next
You will delete the first Item, and so the second item will become the first one, and when you will delete the second item you will in fact delete the third one...(you will miss half of the items in the end)
Ok I see.
Via "For Each..." the list is updated each time an element is deleted.
Is this additional script is correct or should be avoid ?
While oObjectsList.Count() > 0
because I used it before but I had a similar issue (but with error).
Sometime for the an object, if I launch the macro for the first time, I have an error like:
Error(0x800aa002) : object XXXXXX: Error
and if I relaunch the macro a second time without changing anything the object is deleted.
While oObjectsList.Count() > 0 oObjectsList.Item(1).Delete("NoCheck") Wend
seems OK to me.
Do you always have an error using this code "for the first time" ?
If so, can you post the error log (even though I'm not sure to be able to help you on this).
And one last question, if you have errors with this code, do you have the same error with the example I gave you ?
Sorry for the delay....I did lot of tests
I tried to execute my former macro.....I did not succeed in reproducing the bug I have given you.
Your example works perfectly. problem solved.
I encountered a new bug that does not appear each time I execute the same Macro; not during deletion but during the renaming of an object. I know this is not the same subject but I used your piece of code for renaming object instead of deleting objects.
For i=1 To oObjectsList.Count()
oObjectslist.item(i).SetProp "Name", NewName
I lauched 4 times the same Macro:
- first time, the bug appears after renaming 785 objects
- second time, the bug appears after renaming596 objects
- third time, after 276 objects
- last time, no bug and all objects (37873) were renamed correctly after 5h48min
As I said, I used the same Macro and each time I reused the same database.
The bug was:
c:\.....\MyMacro.vbs : property update Error line 148, offeset 12 :
Error(0x800ac012): object XXXXXXXXX, Property Name: Access already freed : 38546c0
It seems that there is a problem in managing objects behind the execution of the macro which is independant of the coding.
And this issue appears in a random way and not often.
My log file does not containt any additional information.
This is for your information.
As this post is solved, I gonna close it.
Are you running on Gbms or Oracle/SQLServer?
We had some weird script behaviour in the past under SQLServer but it was because the DBA's did not install the required stored procedures. Once they were installed, we had no issues anymore
As you all noticed above, updating a collection may cause unconsistent behavior if we are fetching the updated collection.
This problem is not reserved to mega, and the for-each documentation of vbScript explains that it can happen for any kind of collection.
The problem is that the behavior of the fetch depends on the kind of collection you are using.
If the collection is obtained through a metaassociationend, the deleted object is immediately removed from the list, and the list is now unpositionned : so which is the 'next' object ? in fact we can't decide !
Some other kind of collections have the hability of keeping deleted object; so you can fetch consistenly those collections. If you want to use a generic code, it may fail for one collection and not for the other...
Let's have a consistent strategy to delete objects in a collection.
The aim is to delete the collection item without fetching the collection.
1/ If you want to delete an entire collection obtained from a metassociationend, you can always delete the first item
set itm = myCol.Item(1)
if itm.exists then itm.delete
loop while itm.exists
in fact Item(1) begins a new fetch for the collection that is always consistent.
But it is dangerous : if you use this code for another kind of collection, it can raise an infinite loop !
2/ the more consistent - and universal - solution is to pre-build a collection involving all the objects you what do delete
Set collectionToDelete = GetSelection
collectionToDelete.insert myCol ' in this example we will delete all the items of myCol
set ObjToDelete = collectionToDelete.item(1)
set foundobject = myCol.item(ObjToDelete.getid)
if foundobject.exists then foundobject.delete
Loop while collectionToDelete.count
in such a code you can insert a fail-proof code (for example when you have not the right to delete a specific item) and avoid an infinite loop issue, because the scanned object is always removed from the remoting collection.
Let's now have a look on the "renaming" issue.
You may have noticed that the behavior of the code depends on the database typology.
There is a explainable issue when you try to rename a collection build from an entire metaclass fetch in a non-rdbms database.
In such a repository, the index used to fetch a metaclass is the name index - it is the only index that is consistent for all the metaclasses.
You can figure that if you rename objects while fetching the collection, you modify the index while using it... and the result is unpredictable.
The RDMS databases use another way to fetch a metaclass to there may be no problem in this case.
There is no universal solution for a code that rename all the objects of a metaclass, regarding the fact that there may be a large amount of objects to rename; building a working collection may take a long time an maybe raise a memory exception.
You can nevertheless try such a code to do your job.
Another way is to rename through a collection sorted by the "_idabs" attribute: the fetch of such a collection will not depend on the name value.
If possible, a more efficient way (in term of memory) may be to use a multi-pass algorithm that loops while there is something to do