Skip to content

Commit

Permalink
Simplify GeodatabaseTransactions workflow (#1522)
Browse files Browse the repository at this point in the history
  • Loading branch information
williambohrmann3 authored and arcgis-maps-sdk-bot committed Sep 6, 2024
1 parent 1b725ce commit d690af0
Show file tree
Hide file tree
Showing 15 changed files with 76 additions and 413 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@
IsEnabled="False"
Text="Add Marine" />
</Grid>
<Button x:Name="SyncEditsButton"
Clicked="SynchronizeEdits"
IsEnabled="False"
Text="Sync" />
<Label Text="Require a transaction for edits:" />
<Switch x:Name="RequireTransactionCheckBox"
HorizontalOptions="Start"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,22 @@
using Esri.ArcGISRuntime.Data;
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.Tasks;
using Esri.ArcGISRuntime.Tasks.Offline;
using Esri.ArcGISRuntime.UI.Editing;
using Esri.ArcGISRuntime.Symbology;
using Esri.ArcGISRuntime.UI;
using System.Linq.Expressions;
using ArcGIS.Samples.Managers;

namespace ArcGIS.Samples.GeodatabaseTransactions
{
[ArcGIS.Samples.Shared.Attributes.Sample(
name: "Geodatabase transactions",
category: "Data",
description: "Use transactions to manage how changes are committed to a geodatabase.",
instructions: "When the sample loads, a feature service is taken offline as a geodatabase. When the geodatabase is ready, you can add multiple types of features. To apply edits directly, uncheck the 'Require a transaction for edits' checkbox. When using transactions, use the buttons to start editing and stop editing. When you stop editing, you can choose to commit the changes or roll them back. At any point, you can synchronize the local geodatabase with the feature service.",
instructions: "Tap on the map to add multiple types of features. To apply edits directly, uncheck the \"Requires Transaction\". When using transactions, use the buttons to start editing and stop editing. When you stop editing, you can choose to commit the changes or roll them back.",
tags: new[] { "commit", "database", "geodatabase", "geometry editor", "transact", "transactions" })]
[ArcGIS.Samples.Shared.Attributes.OfflineData("43809fd639f242fd8045ecbafd61a579")]
public partial class GeodatabaseTransactions : ContentPage
{
// URL for the editable feature service.
private const string SyncServiceUrl = "https://sampleserver6.arcgisonline.com/arcgis/rest/services/Sync/SaveTheBaySync/FeatureServer/";

// Work in a small extent south of Galveston, TX.
private readonly Envelope _extent = new Envelope(-95.3035, 29.0100, -95.1053, 29.1298, SpatialReferences.Wgs84);

Expand Down Expand Up @@ -98,7 +94,7 @@ private void ShowExtent()
private async Task GetLocalGeodatabase()
{
// Get the path to the local geodatabase for this platform (temp directory, for example).
string localGeodatabasePath = GetGdbPath();
string localGeodatabasePath = DataManager.GetDataFolder("43809fd639f242fd8045ecbafd61a579", "SaveTheBay.geodatabase");

try
{
Expand All @@ -108,51 +104,11 @@ private async Task GetLocalGeodatabase()
// If the geodatabase is already available, open it, hide the progress control, and update the message.
_localGeodatabase = await Geodatabase.OpenAsync(localGeodatabasePath);
LoadingProgressBar.IsVisible = false;
MessageTextBlock.Text = "Using local geodatabase from '" + _localGeodatabase.Path + "'.";
MessageTextBlock.Text = "Using local geodatabase.";
}
else
{
// Create a new GeodatabaseSyncTask with the uri of the feature server to pull from.
var uri = new Uri(SyncServiceUrl);
GeodatabaseSyncTask gdbTask = await GeodatabaseSyncTask.CreateAsync(uri);

// Create parameters for the task: layers and extent to include, out spatial reference, and sync model.
GenerateGeodatabaseParameters gdbParams = await gdbTask.CreateDefaultGenerateGeodatabaseParametersAsync(_extent);
gdbParams.OutSpatialReference = MyMapView.SpatialReference;
gdbParams.SyncModel = SyncModel.Layer;
gdbParams.LayerOptions.Clear();
gdbParams.LayerOptions.Add(new GenerateLayerOption(0));
gdbParams.LayerOptions.Add(new GenerateLayerOption(1));

// Create a geodatabase job that generates the geodatabase.
GenerateGeodatabaseJob generateGdbJob = gdbTask.GenerateGeodatabase(gdbParams, localGeodatabasePath);

// Handle the job changed event and check the status of the job; store the geodatabase when it's ready.
generateGdbJob.StatusChanged += (s, e) =>
{
// See if the job succeeded.
if (generateGdbJob.Status == JobStatus.Succeeded)
{
Microsoft.Maui.ApplicationModel.MainThread.BeginInvokeOnMainThread(() =>
{
// Hide the progress control and update the message.
LoadingProgressBar.IsVisible = false;
MessageTextBlock.Text = "Created local geodatabase.";
});
}
else if (generateGdbJob.Status == JobStatus.Failed)
{
Microsoft.Maui.ApplicationModel.MainThread.BeginInvokeOnMainThread(() =>
{
// Hide the progress control and report the exception.
LoadingProgressBar.IsVisible = false;
MessageTextBlock.Text = "Unable to create local geodatabase: " + generateGdbJob.Error.Message;
});
}
};

// Start the generate geodatabase job.
_localGeodatabase = await generateGdbJob.GetResultAsync();
MessageTextBlock.Text = "Missing local geodatabase.";
}
}
catch (Exception ex)
Expand Down Expand Up @@ -206,7 +162,6 @@ private async Task LoadLocalGeodatabaseTables()
{
MyMapView.SetViewpoint(new Viewpoint(_marineTable.Extent));
StartEditingButton.IsEnabled = true;
SyncEditsButton.IsEnabled = true;
});
}

Expand All @@ -222,24 +177,10 @@ private void GdbTransactionStatusChanged(object sender, TransactionStatusChanged

// These buttons should be enabled when there is NOT a transaction.
StartEditingButton.IsEnabled = !e.IsInTransaction;
SyncEditsButton.IsEnabled = !e.IsInTransaction;
RequireTransactionCheckBox.IsEnabled = !e.IsInTransaction;
});
}

private string GetGdbPath()
{
// Set the platform-specific path for storing the geodatabase.
string folder = string.Empty;
#if WINDOWS
folder = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
#elif IOS || ANDROID || MACCATALYST
folder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
#endif
// Set the final path.
return Path.Combine(folder, "savethebay.geodatabase");
}

private void BeginTransaction(object sender, EventArgs e)
{
// See if there is a transaction active for the geodatabase.
Expand Down Expand Up @@ -385,65 +326,5 @@ private void RequireTransactionChanged(object sender, EventArgs e)
AddBirdButton.IsEnabled = !mustHaveTransaction;
AddMarineButton.IsEnabled = !mustHaveTransaction;
}

// Synchronize edits in the local geodatabase with the service.
public async void SynchronizeEdits(object sender, EventArgs e)
{
// Don't attempt to sync if there are no local edits.
if (!_localGeodatabase.HasLocalEdits())
{
MessageTextBlock.Text = "No local edits to synchronize.";
return;
}

// Show the progress bar while the sync is working.
LoadingProgressBar.IsVisible = true;

try
{
// Create a sync task with the URL of the feature service to sync.
GeodatabaseSyncTask syncTask = await GeodatabaseSyncTask.CreateAsync(new Uri(SyncServiceUrl));

// Create sync parameters.
SyncGeodatabaseParameters taskParameters = await syncTask.CreateDefaultSyncGeodatabaseParametersAsync(_localGeodatabase);

// Create a synchronize geodatabase job, pass in the parameters and the geodatabase.
SyncGeodatabaseJob job = syncTask.SyncGeodatabase(taskParameters, _localGeodatabase);

// Handle the JobChanged event for the job.
job.StatusChanged += (s, arg) =>
{
// Report changes in the job status.
if (job.Status == JobStatus.Succeeded)
{
// Report success ...
Microsoft.Maui.ApplicationModel.MainThread.BeginInvokeOnMainThread(() => MessageTextBlock.Text = "Synchronization is complete!");
}
else if (job.Status == JobStatus.Failed)
{
// Report failure ...
Microsoft.Maui.ApplicationModel.MainThread.BeginInvokeOnMainThread(() => MessageTextBlock.Text = job.Error.Message);
}
else
{
// Report that the job is in progress ...
Microsoft.Maui.ApplicationModel.MainThread.BeginInvokeOnMainThread(() => MessageTextBlock.Text = "Sync in progress ...");
}
};

// Await the completion of the job.
await job.GetResultAsync();
}
catch (Exception ex)
{
// Show the message if an exception occurred.
MessageTextBlock.Text = "Error when synchronizing: " + ex.Message;
}
finally
{
// Hide the progress bar when the sync job is complete.
LoadingProgressBar.IsVisible = false;
}
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ Transactions allow you to control how changes are added to a database. This is u

## How to use the sample

When the sample loads, a feature service is taken offline as a geodatabase. When the geodatabase is ready, you can add multiple types of features. To apply edits directly, uncheck the 'Require a transaction for edits' checkbox. When using transactions, use the buttons to start editing and stop editing. When you stop editing, you can choose to commit the changes or roll them back. At any point, you can synchronize the local geodatabase with the feature service.
Tap on the map to add multiple types of features. To apply edits directly, uncheck the "Requires Transaction". When using transactions, use the buttons to start editing and stop editing. When you stop editing, you can choose to commit the changes or roll them back.

## How it works

1. Take the feature service offline as a geodatabase and display the local tables from the geodatabase in feature layers.
2. If the checkbox is checked, begin the transaction on the geodatabase.
3. Add one or more features.
4. When ready, either commit the transaction to the geodatabase or roll back the transaction.
5. Use a geodatabase sync task to sync changes to the local geodatabase with the feature service.
1. Create a `Geodatabase` using the mobile geodatabase file location.
2. Display the `Geodatabase.FeatureTables` in feature layers.
3. If a transaction is required, begin one using `Geodatabase.BeginTransaction()`.
4. Add one or more features to the feature table(s).
5. When ready, either commit the transaction to the geodatabase with `Geodatabase.CommitTransaction()` or roll back the transaction with `Geodatabase.RollbackTransaction()`.

## Relevant API

Expand All @@ -29,9 +29,13 @@ When the sample loads, a feature service is taken offline as a geodatabase. When
* Geodatabase.RollbackTransaction
* GeometryEditor

## Offline data

This sample downloads the [Save The Bay Geodatabase](https://www.arcgis.com/home/item.html?id=43809fd639f242fd8045ecbafd61a579) item from ArcGIS Online.

## About the data

The sample uses a publicly-editable, sync-enabled [feature service](https://sampleserver6.arcgisonline.com/arcgis/rest/services/Sync/SaveTheBaySync/FeatureServer) demonstrating a schema for recording wildlife sightings.
The mobile geodatabase contains a collection schema for wildlife sightings around Christmas Bay, TX, USA. It was created using data from the [Save The Bay Feature Service](https://sampleserver6.arcgisonline.com/arcgis/rest/services/Sync/SaveTheBaySync/FeatureServer).

## Tags

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
"transact",
"transactions"
],
"offline_data": [],
"offline_data": [
"43809fd639f242fd8045ecbafd61a579"
],
"redirect_from": [
"/net/latest/maui/sample-code/geodatabase-transactions.htm"
],
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button x:Name="StartEditingButton"
Grid.Column="0"
Margin="0,0,0,5"
Expand All @@ -29,24 +32,15 @@
Click="StopEditTransaction"
Content="Stop Editing"
IsEnabled="False" />
<Button x:Name="SyncEditsButton"
Grid.Column="2"
Click="SynchronizeEdits"
Content="Synchronize"
IsEnabled="True" />
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button x:Name="AddBirdButton"
Grid.Row="1"
Grid.Column="0"
Margin="0,0,0,5"
Click="AddNewFeature"
Content="Add Bird Feature"
IsEnabled="False" />
<Button x:Name="AddMarineButton"
Grid.Row="1"
Grid.Column="1"
Click="AddNewFeature"
Content="Add Marine Feature"
Expand Down
Loading

0 comments on commit d690af0

Please sign in to comment.