Hi Scott,
When copying objects in Smalltalk you may also need to copy some component objects to ensure the copy has a sensible structure. This is particularly important when copying objects persisted with ReStore (in some cases ReStore will complain about invalid
structures) however the principle is the same as for non-persistent objects.
As an example I'll use the classes from the "SSW ReStore Examples" package (see the package comment for more details). Starting with an empty database let's first create a Customer with an Address:
Customer new
firstName: 'John';
surname: 'Smith';
address: (Address new line1: '123 Oxford Street'; yourself);
store.
You should now have a database containing one Customer and one Address:
Customer storedInstances size. "1"
Address storedInstances size. "1"
Now let's try to copy the customer and persist the copy:
customer := Customer storedInstances first.
copy := customer copy.
copy firstName: 'James'; store.
At this point you should receive the error "attempt to assign collection to > 1 persistent object". This is because the default implementation of copy will just return a shallowCopy, so the copy has the exact same 'orders' collection as the original.
Sharing persistent collections isn't valid in ReStore so the copy needs its own collection - we do this by adding an implementation of postCopy to Customer:
postCopy
super postCopy.
self orders: OrderedCollection new
We should now be able to create and persist a new copy of the customer:
copy := customer copy.
copy firstName: 'James'; store.
However note that although we've copied the customer the address has not been copied:
Customer storedInstances size. "2"
Address storedInstances size. "1"
The single persistent Address is shared by both customers (it's valid to share persistent non-collection objects in ReStore). It may be that this would be a valid situation in some databases, however for a database of customers lets assume we want each
customer to have its own independent address, so we should also copy the address as part of the customer's postCopy method:
postCopy
super postCopy.
self orders: OrderedCollection new.
self address: self address copy
If we now create and persist an additional copy we will get both a new customer and a new address:
copy := customer copy.
copy firstName: 'Jack'; store.
Customer storedInstances size. "3"
Address storedInstances size. "2"
Just to reiterate, the important thing is to implement postCopy methods in your persistent classes so that the resulting copies represent a valid structure according to the requirements of your data model.
Hope this helps,
John Aspinall
On Wednesday, September 13, 2023 at 9:05:33 PM UTC+1, Scott McWilliams wrote:
What is the recommended approach to to copy or 'save as' a record using ReStore? Using #copy or #deepCopy just seems to update the original.
I have tried creating a new, 'empty' object of a class and populating just the fields of interest, which seems to work sometimes, but other times results in either an 'index of bounds' error or fails trying to (re-) insert a duplicate key value in a
related table.
Thanks in advance for any and all ideas.
Regards,
Scott
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)