10

Goal: to be able to relate a ChangeItem from a Changelog to a version of that item.

Issue: I can fetch metadata and version for a List Item. However, I am unable to relate a specific version of that list item to the Change Item, i.e. a specific change which was performed on the item.

For example:

If I have versions 1, 2 and 3 of a Document list item of list item id 3, and I get a change log for version 2, then how to I relate the ChangeItem for list item id 3 to version 2?

enter image description here

What I have done so far

Query the change log

            _cc = new ClientContext(url);
            _cc.AuthenticationMode = ClientAuthenticationMode.Default;
            _cc.Credentials = new SharePointOnlineCredentials(userName, password);

            ListCollection lists = _cc.Web.Lists;
            IEnumerable<List> results = _cc.LoadQuery<List>(lists.Where(lst => lst.Title == listName));
            _cc.ExecuteQuery();
            List list = results.FirstOrDefault();
            if (list == null)
            {

                Console.WriteLine("A list named \"{0}\" does not exist. Press any key to exit...", listName);
                Console.ReadKey();
                return;
            }

            nextRunTime = DateTime.Now;

            ChangeQuery cq = new ChangeQuery(true, true);
            cq.Item = true;
            cq.DeleteObject = true;
            cq.Add = true;
            cq.Update = true;

            // Initially set the ChangeTokenStart to 2 days ago so we don't go off and grab every item from the list since the day it was created.
            // The format of the string is semicolon delimited with the following pieces of information in order
            // Version number 
            // A number indicating the change scope: 0 – Content Database, 1 – site collection, 2 – site, 3 – list. 
            // GUID representing the scope ID of the change token
            // Time (in UTC) when the change occurred
            // Number of the change relative to other changes
            cq.ChangeTokenStart = new ChangeToken();
            cq.ChangeTokenStart.StringValue = string.Format("1;3;{0};{1};-1", list.Id.ToString(),
                DateTime.Now.AddDays(-2).ToUniversalTime().Ticks.ToString());

            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(string.Format("Ctrl+c to terminate. Press \"r\" key to force run without waiting {0} seconds.", WaitSeconds));
            Console.WriteLine();
            Console.ResetColor();
            do
            {
                do
                {
                    if (Console.KeyAvailable && Console.ReadKey(true).KeyChar == 'r') { break; }
                }
                while (nextRunTime > DateTime.Now);

                Console.WriteLine(string.Format("Looking for items modified after {0} UTC", GetDateStringFromChangeToken(cq.ChangeTokenStart)));


                ChangeCollection coll = list.GetChanges(cq);
                _cc.Load(coll);
                _cc.ExecuteQuery();

                DisplayChanges(coll, cq.ChangeTokenStart);
                // if we find any changes to the list take the last change and use the ChangeToken as the start time for our next query.
                // The ChangeToken will contain the Date/time of the last change to any item in the list.
                cq.ChangeTokenStart = coll.Count > 0 ? coll.Last().ChangeToken : cq.ChangeTokenStart;

                nextRunTime = DateTime.Now.AddSeconds(WaitSeconds);

            } while (true);

Query Item Metadata

 private static void DisplayChanges(ChangeCollection coll, ChangeToken ct)
    {
        if (coll.Count == 0)
        {
            // Console.WriteLine(string.Format("No changes to {0} since {1} UTC.", listName, GetDateStringFromChangeToken(ct)));
            return;
        }

        Console.ForegroundColor = ConsoleColor.Green;
        // https://msdn.microsoft.com/en-us/library/office/bb417456(v=office.14).aspx
        foreach (var itm in coll)
        {
            if (itm is ChangeItem)
            {
                // Get the list for this item and determine whether versioning is turned on

                var c_item = itm as ChangeItem;
                GetVersion(c_item.ListId, c_item.ItemId, c_item.Time);
  }

Get version This is where I am unclear about how to relate a ChangeItem back to a specific version of that change. Any ideas ??

 private static void GetVersion(Guid listid, int itemId, DateTime time)
    {
        var list = _cc.Web.Lists.GetById(listid);
        var listItem = list.GetItemById(itemId);

        _cc.Load(listItem, i => i.DisplayName);
        // ExecuteQuery will pull all data from SharePoint
        // which has been staged to Load()
        _cc.ExecuteQuery();

        File fileItem = listItem.File;
        FileVersionCollection fileVersions = fileItem.Versions;
        _cc.Load(fileVersions);
        _cc.ExecuteQuery();

        if (fileItem.Versions.Count > 0)
        {
            foreach (var version in fileItem.Versions)
            {
                // Unclear how to relate the version back to the ChangeItem
                if (version.Created.Equals(time))
                {
                    Console.WriteLine("Item {0} Version {1}", listItem.DisplayName, version.VersionLabel);
                }
            }

            //Console.WriteLine("Item {0} Version {1}", listItem.DisplayName, fileItem.Versions[fileItem.Versions.Count - 1].VersionLabel);
        }

    }
0

If the data is not available in the API, can't you just calculate backwards?

E.g. currently the document is on version 11. You get all change items for that document item and you receive 6 updates. Then you know that the first update to form the change query responds to version 6.

It's just an idea. I have some experience with the change query, but not in the same manner as you would like to use it.

0

I had the same issue but unfortunately, we have not found a solution to this.

In the end, we decided to review our architecture to avoid the need to work with it.

Indeed when you are working with version history all you can operate is a date time of the version. You know it could be the same as in ChangeToken or a bit bigger (I suppose due to delays in processing on a server).

In our case, we are saving last processed ChangeToken and last processed DateTime from the version history. It allows us to use it in comparing process in the future.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.