To work with preliminary data for one or multiple shared record instances, and apply or discard the modifications later, create a change proxy over your shared record and change the data of this object instead: the change proxy object holds your changes, while the proxied record instance remains unchanged. You can then either apply the changes to the proxied record instance or abandon the change proxy.
Important: Proxies are not supported in ui::forms. Use the View Model component instead.
When you create a change proxy, it is not created in the current execution context but in its equivalent context on a proxy execution level. The proxy execution level overlays the current level.
Proxies can see only data in their own proxy level and the levels of their ancestors: All proxy objects can see the original record instance and any proxies in the overlay levels.
You can create a proxy either based on an existing record instance or based on a record. Once you have applied all the required changes on the proxy, you can merge it.
proxy(<RecordInstance>, <PropertiesOfRelatedRecords>, ..)
or proxy(Collection<RecordInstances>, <PropertiesOfRelatedRecords>, ..)
. The proxy is automatically created in the context on the immediate proxy level. The changes are applied on the underlying record instance on merge. Note that the record instance might be a proxy as well. //creating proxy of the shared record instance and
//properties of the related shared records:
proxy(jane, Persona.address)
proxy([jane, john], Persona.address);
proxy(<SharedRecord>)
. Alternatively use proxy(<SharedRecord>, <ProxyLevel>)
to create a proxy on another level. This allows you to create and abandon the proxy without actually ever having created the record instance. On merge, a new record instance with the proxy data on the underlying level is created. //proxy of the record Persona on the proxy level 2:
proxy(Persona, 2)
You can create the proxy of a related record instance with the proxy(<RecordInstance>, <PropertiesOfRelatedRecords>, ..)
call when creating the proxy.
If you need to create a proxy of a record instance with a related record without creating the related record on the underlying execution level, do the following:
def Persona persona := proxy(Persona)
persona.address := proxy(Address)
If you do not create a change proxy of a related record, the system will access the record instance on the underlying level when you navigate from the proxy to the related record.
Example related record proxy: Let us assume a record hierarchy with multiple related records:
Let's have the following proxy://Shared record instance: def Persona persona := new Persona( name -> "Night Mare", address -> new Address(street -> new Street(number -> 0, name -> "Elm Street")), documents -> new IDs( driversLicense -> "A000-0000-0000", insuranceNumber -> "000-00-0000-A", passport -> "00000000" ) ); //Proxy: def Persona proxyPersona := proxy(persona, Persona.address);
We have created a proxy object only over the Persona record and its Address record. If we access its documents via
proxyPersona.documents
, we will access the non-proxied record Address: to create a proxy of such a related record, add the property to theproxy()
call:def Persona proxyPersona := proxy(persona, Persona.address, Persona.documents);
Note that it is not possible to proxy the Street record from Persona.
You can create the proxy of record properties with the proxyOfProperties(<RecordInstance>, <Properties>, ..)
call, for example proxyOfProperties(a, Author.name)
. If you want to create proxies of all record properties, call the function without specifying the properties, for example, proxyOfProperties(a)
.
You can check if a record is a proxy with the isProxy()
call.
You can check the proxy level of a proxy with the getProxyLevel(<Proxy>)
call, which returns an Integer. 0 designates the execution level with "real" context data.
To merge proxies or to create the proxied record without optimistic lock check, you can use the following functions:
mergeProxies(recordInstance1, ..)
and mergeAllProxies(List<RecordInstances>)
merge the changes on the proxies into the underlying records or the immediate parent proxies.mergeProxiesDeep(recordInstance1, ..)
and mergeAllProxiesDeep(List<RecordInstances>)
merge the changes on the proxies, their proxy properties, and any proxies of their related records on the same proxy level.For example, in the case of the proxy of a persona with an address, mergeProxiesDeep()
merges the persona as well as its related address proxy.
The merge() call store the data in the record even if the record uses the optimistic lock mechanism. To perform the optimistic locking check before merging, use an overloaded merge call.
If you assign to a proxied property an object from a higher proxy level, on merge, the association is applied on the target object: the original relationship is removed.
When merging a proxy of a versioned shared record with active optimistic locking and you want to apply the optimistic locking, use a merge call that checks whether the underlying entity has been changed since the proxy was created:
mergeAllProxies(checkConflicts, Collection<proxyObject>)
, for example, mergeAllProxies(true, [ proxyPersona, proxyAddress]);
mergeProxiesDeep(checkConflicts, proxyPersona)
, for example,mergeProxiesDeep(true, proxyPersona, proxyAddress);
The merge fails if a proxy or shared record on the underlying level has been modified in another transaction since the proxy had been created or when the underlying record is changed in the same transaction.
When merging with checkConflicts set to true, consider either handling the potential optimistic-lock exception or adjust your data model so that a collision cannot occur; for example, aggregate the data that might collide in a collection and create the resulting entity later.
Example merge of related proxies: Author and Book are in 1:1 relationships named book and author
def Book book := new Book(title -> "Catch-22");
def Author heller := new Author(name -> "Heller", book -> book);
def Author hellerProxy := proxy(heller, Author.book);
hellerProxy.book.title := "God Knows";
//book title is update in the db to "God Knows":
try mergeProxiesDeep(true, hellerProxy)
catch "com.whitestein.lsps.common.OptimisticLockException" ->
//log a message if the record has been changed:
log("failed to merge changes", 100)
end