Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to copy or 'save as' a record using ReStore

32 views
Skip to first unread message

Scott McWilliams

unread,
Sep 13, 2023, 4:05:33 PM9/13/23
to
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

john.a...@gmail.com

unread,
Sep 15, 2023, 12:14:25 PM9/15/23
to
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

Scott McWilliams

unread,
Sep 20, 2023, 9:30:56 AM9/20/23
to
Thank you John!

Regards,
Scott
0 new messages