3.2 Other Collection Messages
By using asOrderedCollection you can convert an instancesOf: collection into a regular OrderedCollection. An advantage of this is that the limitations on enumeration blocks no longer apply - you are now dealing with a real Smalltalk collection.
Implicit in this is that all objects forming the collection in the database are brought into your Smalltalk image; if this is a large number then asOrderedCollection may take a while to execute. Together with the overhead of allocating the memory for a significant number of objects, this means asOrderedCollection should be used with care.
asSortedCollection and asSortedCollection:
In a similar way to asOrderedCollection, asSortedCollection and asSortedCollection: can convert an instancesOf: collection into a regular SortedCollection.
If the instancesOf: collection already has a sort defined (via sortBlock:), then asSortedCollection will use that sort block, otherwise the default sort for the class of object in the collection will be used (i.e. its implementation of <=). asSortedCollection:, like the standard Collection implementation, takes the sort block to use as its parameter.
As with sortBlock:, the sort block or implementation of <= must conform to the rules for use with ReStore.
As with a standard collection, size will return the number of elements of an instancesOf: collection. However, rather than fetching the entire collection from the database, this is done by issuing a 'count' query, thus the overhead is minimal. It can be a good idea to use size before asOrderedCollection to check that the collection to be fetched is not unreasonably large.
isEmpty is provided for convenience. This simply uses size to test for an empty collection, and hence has the same performance advantages.
first will attempt to fetch the first object in the instancesOf: collection. Like a regular collection, this will error if the collection has no members.
The operation of do: is exactly the same as when used with a regular collection – the argument block is evaluated with each of the member objects of the collection. The distinguishing factor is that at no point is an actual collection holding all the member objects constructed. Instead, the elements are iterated over directly from the database, in a similar manner to a Stream. For a very large collection this has performance benefits, since allocating the memory for such a collection (and garbage collecting it again following the do:) can carry a heavy overhead.
Using collectAsSet: can, in certain situations, be more efficient than the equivalent
(collect: [ :each | …]) asSet.
This is because the asSet operation is done by the database, potentially reducing the number of objects returned. As an example, consider two ways to extract all surnames within a database of Person objects:
((aReStore instancesOf: Person) collect: [ :each | each surname]) asSet.
(aReStore instancesOf: Person) collectAsSet: [ :each | each surname]
The first way would fetch from the database the surname of every single Person – there would likely be a high degree of duplication in this collection, which would then be removed by asSet. With the second method, using collectAsSet: would remove the duplicates before returning the collection from the database, reducing the number of objects significantly.
modify: is an enumeration message where the argument block is expected to update some aspect of the member objects. However, it is important to understand that the update is done directly within the database – this makes the update very efficient (since no objects are fetched from the database), but has the limitation that any objects already in memory (either in your image, or that of another user) will not be updated. Thus modify: is most suitable for 'supervisor'-type activities, ideally when no other image is connected to the database.
As an example of its use, let's say that you've just added the instance variable country to the class Address, in preparation for handling overseas customers. All current addresses are (by default) in your home country, and you want to update these to make this explicit. This is an ideal application for modify:
(aReStore instancesOf: Address) modify: [ :each | each country: 'United Kingdom']
unstore and unstore:
unstore can be used to quickly delete from the database all members of an instancesOf: collection. For example, the following would delete all Person objects from the database:
(aReStore instancesOf: Person) unstore
unstore: operates in a similar way, but takes as its parameter a select:-style block which restricts the objects to delete. The following would delete all Orders placed before 1995:
(aReStore instancesOf: Person) unstore: [ :each | each orderDate year < 1995]
Naturally, such a powerful deletion facility should be used with extreme caution - you are strongly recommended to ensure you have an up-to-date backup of your data before using either of these messages.