Update properties safely

View as Markdown

Every change to an object's properties creates a new version. Base the change on the version you read, so that the server refuses it if someone else changed the object in between. There are two ways:

Calls

SetProperties fields:

Field A. checked-in object B. checked-out object
obj_ver The object and the version you read The object and the checked-out version from CheckOut
allow_modifying_checked_in_object true unset
fail_if_newer_version_exists true: refuse if a newer version exists unset
properties The values to add or replace The values to add or replace
remove_unspecified_properties false: keep all other properties false

Code

The recipe creates a test document, sets Keywords (1004) in one call (A), then checks the document out, sets Keywords and Document date (1002) in one SetProperties call, and checks it in (B). If anything fails while the document is checked out, it undoes the check-out. At the end it deletes the document, unless you pass --keep.

Python

# One call: the server checks the object out, sets the values and checks it in.
# Name the version you read; with fail_if_newer_version_exists the call fails instead
# of overwriting a change someone else made after that version.
updated = objects.SetProperties(ops.SetPropertiesRequest(
    obj_ver=obj_ver(object_id.type, object_id.item_id.internal_id, version),
    allow_modifying_checked_in_object=True,
    fail_if_newer_version_exists=True,
    # Other properties stay as they are (remove_unspecified_properties is false).
    properties=[property_value(1004, text("grpc, sample"))]))  # Keywords
version = updated.object_info.latest_version.object_version.version_info \
    .version.internal_version
print(f"Set Keywords: now version {version}")

Source: python/recipes/update_properties.py

def check_out_set_check_in(objects, object_id) -> None:
    """Check out, set, check in: several changes become one new version, and nobody else can
    change the object meanwhile."""
    checked_out = objects.CheckOut(ops.CheckOutRequest(obj_id=object_id))
    working_version = checked_out.object_info.object_version.version_info.version
    print(f"Checked out: working version {working_version.internal_version}")
    working = obj_ver(object_id.type, object_id.item_id.internal_id,
                      working_version.internal_version)
    try:
        objects.SetProperties(ops.SetPropertiesRequest(
            obj_ver=working,
            properties=[
                property_value(1004, text("grpc, sample, checked out")),       # Keywords
                property_value(1002, date(datetime.now(timezone.utc).date())),  # Document date
            ]))
        checked_in = objects.CheckIn(ops.CheckInRequest(obj_ver=working))
    except Exception:
        # Do not leave the object checked out.
        objects.UndoCheckout(ops.UndoCheckoutRequest(obj_ver=working))
        raise
    version = checked_in.object_info.latest_version.object_version.version_info.version
    print(f"Checked in: now version {version.internal_version}")

Source: python/recipes/update_properties.py

C#

// One call: the server checks the object out, sets the values and checks it in.
// Name the version you read; with fail_if_newer_version_exists the call fails instead
// of overwriting a change someone else made after that version.
var updated = await objects.SetPropertiesAsync(new SetPropertiesRequest
{
    ObjVer = ObjVer(objId.Type, objId.ItemId.InternalId, version),
    AllowModifyingCheckedInObject = true,
    FailIfNewerVersionExists = true,
    // Other properties stay as they are (remove_unspecified_properties is false).
    Properties = { Property(1004, Text("grpc, sample")) },  // Keywords
});
version = updated.ObjectInfo.LatestVersion.ObjectVersion.VersionInfo.Version.InternalVersion;
Console.WriteLine($"Set Keywords: now version {version}");

Source: csharp/Recipes/UpdateProperties.cs

// Check out, set, check in: several changes become one new version, and nobody else
// can change the object meanwhile.
var checkedOut = await objects.CheckOutAsync(new CheckOutRequest { ObjId = objId });
var workingVersion = checkedOut.ObjectInfo.ObjectVersion.VersionInfo.Version;
Console.WriteLine($"Checked out: working version {workingVersion.InternalVersion}");
try
{
    var working = ObjVer(objId.Type, objId.ItemId.InternalId, workingVersion.InternalVersion);
    await objects.SetPropertiesAsync(new SetPropertiesRequest
    {
        ObjVer = working,
        Properties =
        {
            Property(1004, Text("grpc, sample, checked out")),             // Keywords
            Property(1002, Date(DateOnly.FromDateTime(DateTime.UtcNow))),  // Document date
        },
    });
    var checkedIn = await objects.CheckInAsync(new CheckInRequest { ObjVer = working });
    version = checkedIn.ObjectInfo.LatestVersion.ObjectVersion.VersionInfo.Version.InternalVersion;
    Console.WriteLine($"Checked in: now version {version}");
}
catch
{
    // Do not leave the object checked out.
    await objects.UndoCheckoutAsync(new UndoCheckoutRequest
    {
        ObjVer = ObjVer(objId.Type, objId.ItemId.InternalId, workingVersion.InternalVersion),
    });
    throw;
}

Source: csharp/Recipes/UpdateProperties.cs

Go

// One call: the server checks the object out, sets the values and checks it in.
// Name the version you read; with fail_if_newer_version_exists the call fails instead of
// overwriting a change someone else made after that version.
updated, err := objects.SetProperties(ctx, &mfiles.SetPropertiesRequest{
	ObjVer:                        mfilesclient.ObjVer(0, id, version),
	AllowModifyingCheckedInObject: true,
	FailIfNewerVersionExists:      true,
	// Other properties stay as they are (remove_unspecified_properties is false).
	Properties: []*mfiles.PropertyValue{
		mfilesclient.PropertyValue(1004, mfilesclient.Text("grpc, sample")), // Keywords
	},
})
if err != nil {
	return err
}
version = updated.GetObjectInfo().GetLatestVersion().GetObjectVersion().GetVersionInfo().
	GetVersion().GetInternalVersion()
fmt.Printf("Set Keywords: now version %d\n", version)

Source: go/recipes/update_properties/main.go


// checkOutSetCheckIn makes several changes into one new version; nobody else can change the
// object meanwhile.
func checkOutSetCheckIn(ctx context.Context, objects mfiles.IRPCObjectOperationsClient,
	objID *mfiles.ObjID) error {
	checkedOut, err := objects.CheckOut(ctx, &mfiles.CheckOutRequest{ObjId: objID})
	if err != nil {
		return err
	}
	workingVersion := checkedOut.GetObjectInfo().GetObjectVersion().GetVersionInfo().GetVersion()
	fmt.Printf("Checked out: working version %d\n", workingVersion.GetInternalVersion())
	working := mfilesclient.ObjVer(objID.GetType(), objID.GetItemId().GetInternalId(),
		workingVersion.GetInternalVersion())

	today := time.Now().UTC()
	_, err = objects.SetProperties(ctx, &mfiles.SetPropertiesRequest{
		ObjVer: working,
		Properties: []*mfiles.PropertyValue{
			mfilesclient.PropertyValue(1004, mfilesclient.Text("grpc, sample, checked out")), // Keywords
			mfilesclient.PropertyValue(1002, // Document date
				mfilesclient.Date(today.Year(), today.Month(), today.Day())),
		},
	})
	var checkedIn *mfiles.CheckInResponse
	if err == nil {
		checkedIn, err = objects.CheckIn(ctx, &mfiles.CheckInRequest{ObjVer: working})
	}
	if err != nil {
		// Do not leave the object checked out.
		_, _ = objects.UndoCheckout(context.WithoutCancel(ctx),
			&mfiles.UndoCheckoutRequest{ObjVer: working})
		return err
	}
	fmt.Printf("Checked in: now version %d\n", checkedIn.GetObjectInfo().GetLatestVersion().
		GetObjectVersion().GetVersionInfo().GetVersion().GetInternalVersion())
	return nil
}

Source: go/recipes/update_properties/main.go

Output:

Created [docs-test] Python update-properties (ID 612, version 1, modified 2026-10-31 14:55:57 UTC)
Set Keywords: now version 2
Checked out: working version 3
Checked in: now version 3
  Property 1002: 2026-10-31
  Property 1004: grpc, sample, checked out
Deleted object 0-612

The checked-out version keeps its number when it is checked in: the changes made while the document was checked out became one version, 3.

Pitfalls

See also