public function sync()
    {
        // Only sync open changesets
        if ($this->State !== static::STATE_OPEN) {
            return;
        }

        // Start a transaction (if we can)
        DB::get_conn()->withTransaction(function () {

            // Get the implicitly included items for this ChangeSet
            $implicit = $this->calculateImplicit();

            // Adjust the existing implicit ChangeSetItems for this ChangeSet
            /** @var ChangeSetItem $item */
            foreach ($this->Changes()->filter(['Added' => ChangeSetItem::IMPLICITLY]) as $item) {
                $objectKey = $this->implicitKey($item);

                // If a ChangeSetItem exists, but isn't in $implicit, it's no longer required, so delete it
                if (!array_key_exists($objectKey, $implicit)) {
                    $item->delete();
                } else {
                    // Otherwise it is required, so update ReferencedBy and remove from $implicit
                    $item->ReferencedBy()->setByIDList($implicit[$objectKey]['ReferencedBy']);
                    unset($implicit[$objectKey]);
                }
            }

            // Now $implicit is all those items that are implicitly included, but don't currently have a ChangeSetItem.
            // So create new ChangeSetItems to match

            foreach ($implicit as $key => $props) {
                $item = new ChangeSetItem($props);
                $item->Added = ChangeSetItem::IMPLICITLY;
                $item->ChangeSetID = $this->ID;
                $item->ReferencedBy()->setByIDList($props['ReferencedBy']);
                $item->write();
            }

            // Mark last synced
            $this->LastSynced = DBDatetime::now()->getValue();
            $this->write();
        });
    }