LuciadCPillar offers support for the editing of feature data in GeoPackage files. Program: Editing GeoPackage data shows you a code example, which is further explained in the remainder of the article.

Code sample

Program: Editing GeoPackage data
const std::string source = "test/resources/Data/GeoPackage/cities125.gpkg";
std::shared_ptr<GeoPackageDataSource> datasource = GeoPackageDataSource::newBuilder().source(source).build();
GeoPackageModelDecoderOptions options = GeoPackageModelDecoderOptions::newBuilder().editable(true).build();
luciad::expected<std::shared_ptr<Model>, ErrorInfo> modelExpected = GeoPackageModelDecoder::decode(datasource, options);
if (modelExpected.has_value()) {
  auto model = std::dynamic_pointer_cast<IFeatureModel>(*modelExpected);
  if (model != nullptr) {
    std::shared_ptr<FeatureModelUpdate> modelUpdate = FeatureModelUpdate::newBuilder().removeFeature(8).build();
    model->getUpdater()->update(modelUpdate);

    if (const std::optional<FeatureSaveErrorInfo>& error = model->getPersistenceManager()->saveChanges()) {
      if (const auto& generalError = error->getGeneralError()) {
        std::cout << "saveChanges failed: " << generalError->getMessage();
      }
      for (const auto& featureId : error->getFeatureIds()) {
        std::cout << "saveChanges failed on feature: " << featureId << ": " << error->getFeatureError(featureId);
      }
    }
  }
} else {
  ErrorInfo errorInfo = modelExpected.error();
  std::cout << "could not be decoded: " << errorInfo.getMessage();
}
const string source = @"test/resources/Data/GeoPackage/cities125.gpkg";
var dataSource = GeoPackageDataSource.NewBuilder().Source(source).Build();
var options = GeoPackageModelDecoderOptions.NewBuilder().Editable(true).Build();
try
{
    var model = GeoPackageModelDecoder.Decode(dataSource, options);
    var featureModel = model as IFeatureModel;

    var modelUpdate = FeatureModelUpdate.NewBuilder().RemoveFeature(8).Build();
    featureModel.GetUpdater().Update(modelUpdate);

    var error = featureModel.GetPersistenceManager().SaveChanges();
    if (error != null)
    {
        if (error.GeneralError != null)
        {
            Console.WriteLine("SaveChanges failed: {0}", error.GeneralError.Message);
        }

        foreach (var featureId in error.FeatureIds)
        {
            var message = error.GetFeatureError(featureId);
            Console.WriteLine("SaveChanges failed on feature: {0}: {1}", featureId, message);
        }
    }

}
catch (IOException e)
{
    Console.WriteLine("could not be decoded: " + e.Message);
}
String source = "resources/Data/GeoPackage/cities125.gpkg";
GeoPackageDataSource dataSource = GeoPackageDataSource.newBuilder().source(source).build();
GeoPackageModelDecoderOptions options = GeoPackageModelDecoderOptions.newBuilder().editable(true).build();
try {
  Model model = GeoPackageModelDecoder.decode(dataSource, options);
  IFeatureModel featureModel = (IFeatureModel) model;

  var modelUpdate = FeatureModelUpdate.newBuilder().removeFeature(8).build();
  featureModel.getUpdater().update(modelUpdate);

  var error = featureModel.getPersistenceManager().saveChanges();
  if (error != null) {
    if (error.getGeneralError() != null) {
      Log.w("gpkg", "saveChanges failed: " + error.getGeneralError().getMessage());
    }

    for (var featureId : error.getFeatureIds()) {
      var message = error.getFeatureError(featureId);
      Log.w("gpkg", "saveChanges failed on feature: " + featureId + ": " + message);
    }
  }
} catch (Exception e) {
  Log.w("gpkg", "could not be decoded: " + e.getMessage());
}

Enabling editing

Saving changes

Changes aren’t immediately written to the GeoPackage file, but kept in memory initially. You need the FeatureModelPersistenceManagerFeatureModelPersistenceManagerFeatureModelPersistenceManager to save pending changes. You can get it using the IFeatureModel::getPersistenceManagerIFeatureModel::getPersistenceManagerIFeatureModel::getPersistenceManager method. To save the changes, call the FeatureModelPersistenceManager::saveChangesFeatureModelPersistenceManager::saveChangesFeatureModelPersistenceManager::saveChanges method. You can also view and discard in-memory changes with that same class.

For more information about saving changes to feature models, see Working with feature models with save support.

Limitations

There are some limitations to the GeoPackage editing functionality. You can encode only features with geometries that can be decoded. For a list of these, see the documentation of the GeoPackageModelDecoderGeoPackageModelDecoderGeoPackageModelDecoder.

In addition, the GeoPackage itself can add extra limitations. When you’re editing, only the feature table changes, and the corresponding RTree tables if they’re used. The table metadata doesn’t change.

Thus, the following constraints may apply:

  • You can only add geometries that require extensions if those extensions are present.

  • The "geometry_type_name" can limit allowed geometry types.

  • If measure values are mandatory, you can’t add or update features.

You can remove these limitations by changing the feature metadata of the GeoPackage. For more information on these limitations, see the GeoPackage specification.