Transactions
Record_transaction
The record_transaction exemplar is the preferred methodology to insert/update/delete objects in the database. It is a robust methodology that supports embedding other record_transactions within a record_transaction to support creation of joined objects.
BOLOs
- When you run an insert transaction, no result is returned and no result is stored within the transaction.
- If you have the method fire_pre_insert_actions() or fire_pre_update_actions() defined on the record exemplar, ensure it is returning a property_list. Probably the one passed in as an argument.
- The errors you see will not necessarily point you to this fact.
- If you have the method fire_post_insert_actions() or fire_post_update_actions() defined on the record exemplar, ensure it is returning self. See method comments for dd_record_mixin.fire_post_insert_actions().
- You will may errors in the following areas.
- Updating the feature in the editor
- Merging will error during conflict resolution
- You will may errors in the following areas.
- If you have the method fire_pre_insert_actions() or fire_pre_update_actions() defined on the record exemplar, ensure it is returning a property_list. Probably the one passed in as an argument.
Post Actions Information
The methods fire_post_insert_actions() or fire_post_update_actions() have a second optional argument. This argument is the item returned as the second returned item from the fire_pre_insert_actions() or fire_pre_update_actions(). So if you do something in the pre actions that you want to use in the post actions, return that object as the second item in the multiple return statement.
Application Transaction Context
Predicates
Case Insensitivity
You can use the modifiers option in a predicate to search collections on fields that do not have case insensitive field type. In the following example :ci is passed along to the wild call. Other options are :not for negated and :partial for prefix test.
pred << predicate.wild(:a_fld_name,"search criteria*",:ci)
Multi-Collection
Do you want to easily search for a record that may be in one of several collections based on a field name? You can use the following to get all records in all collections that have the field name of interest. Then you can find the matching criteria from them.
!rs << gis_program_manager.databases[:gis].rwo_set().select(:field,{:name})
!ms << !rs.select(predicate.eq(:name,"a name")
Differences
Smallworld has functionality used internally for merge/post to determine differences between the alternatives.
Table Differences
In order to get the table differences you need to compare two alternatives. So for this example let's say we are going to compare the current and the parent alternatives. You will need to get a handle on the alternatives. Here is an example of getting the views needed for the GIS dataset.
current_view << gis-program_manager.databases[:gis]
parent_view << current_view.replicate(-1) # this gets a "replica" view or the parent alternative
base_view << current_view.replicate(:base)
You can use current_view.table_changes_to(parent_view) to get the list of table/collection names that have been changed.
Record Differences
Typically you will run the difference stream on the current collection and parent collection. You will need to get a handle on the 2 or 3 collections. If doing a basic what changed comparison, you could get away with the current alternative collection and the parent alternative collection. But you may want to compare to the base as well (The parent alternative as it was when you created/aligned/posted the current current alternative). Here are 2 examples on table/collection named street and using the above views.
# Basic comparison of the parent & current views
diff_strm << ds_difference_stream.new_on(current_view.collections[:street],parent_view.collections[:street])
(change,curr_rec,base_rec,new_rec) << diff_strm.get()
diff_strm.close()
# Comparison of the parent, current, and base views
diff_strm << ds_difference_stream.new_on(current_view.collections[:street],
base_view.collections[:street],
parent_view.collections[:street])
(change,curr_rec,base_rec,new_rec) << diff_strm.get()
diff_strm.close()
Merging
view.merge() is how to merge changes. Note that with the auto-conflict resolution functionality, you should run this within a ACE somehow… This should be documented somewhere….
Multi-Merge
There is a way to submit designs to the job manager to merge. These would run on the # or job servers you have set up. You can create a Job type that does this auto-magikally also so you don't have to select the jobs, it does all of them, or some sort of filtered set that you can create.
datamodel_merge_engine
You can use the datamodel_merge_engine exemplar (available in at least 4.3+). There are several ways you can use it. Here are 2
- datamodel_merge_engine.new(:preset_dataset_name,:ace).merge_alternatives() - This would merge all the ACEs. You will need to be at the top ace alternative when you do this.
- datamodel_merge_engine.new(:dataset_name, :gis).merge_alternatives() - Will merge down to all children from current :gis alternative.
Writable Alternatives
User ACE and Scratch views are normally required to be writable. But if you have multiple sessions up, the system will create numbered child alternatives. This functionality is provided from the method select_writable_alternative() on the view. If you want to force a child alternative, you can use the restricted method select_writable_subalternative() from the current alternative.
Scratch View
Scratch view is where you can hold "temporary" data. My understanding is it the "middle ground" between actual storage in the database and in memory objects. So if you have a large amount of data that is going to be needed for processing, this might be a good option. It supports creation of tables on the fly also.
Table Creation
You can use .create_scratch_collection() on gis_program_manager (gpm) to create a scratch collection.
gpm.create_scratch_collection(:my_test,{{:id,:ds_int},{:num,:ds_int}},1)
Table/Record interaction
Once the collection has been created, you can interact with records from that collection. Here are some examples.
# Insert a record
gpm.scratch_table(:my_test).insert({1,100})
# Get the record
gpm.scratch_table(:my_test).at(1)
# Describe fields
gpm.scratch_table(:my_test).at(1).describe_fields()
You can send this collection to the explorer.
I have seen scratch data support geometries as well.
+Scratchpad
This is a temporary alternative that is forgotten about when leaving the alternative or closing the view. It appears to use UVAs like a normal alternative.