5

I am making a tool to migrate/update specific content (list items and documents) from a farm to another. A little bit like the SharePoint Content Deployment Wizard, but with custom specifications from my client.

Using the Content Deployment API seems a good idea.

The site collections in each farm were created using standard process (using a custom site definition provisionning list and elts). I don't think I should use "RetainObjectIdentity" because the Guids are different between the 2 farms.

When I export/import data :

  • Documents are correctly added/updated, but it's not the case for list items :
  • It doesn't update existing list items. It always add new one.

So here is my question : What is the best solution to update existing list items (they don't have same GUIDs between site collections) ? I would like to retain the ListItem.ID (not UniqueID). Is that possible ? Is there a solution to tell the API to restore This Item to this one ? On the worst case, I can delete existing items before importing, but the items would lose their original ListItem.ID (int)...

Or I can forget the Content Deployment API...

Below : the code I am using :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Deployment;
using Microsoft.SharePoint;

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
        Export();
        Import();
    }

    static void Import()
    {
        using (SPSite site = new SPSite("http://localhost:5555/sites/aa/"))
        {
            using (SPWeb web = site.OpenWeb())
            {
                SPImportSettings settings = new SPImportSettings();
                settings.SiteUrl = site.Url;
                settings.FileLocation = @"c:\export";
                settings.BaseFileName = "blop.cmp";
                settings.RetainObjectIdentity = false;
                settings.CommandLineVerbose = true;

                SPImport import = new SPImport(settings);
                import.Run();  
            }
        }
    }


    static void Export()
    {
        using (SPSite site = new SPSite("http://localhost:5555"))
        {
            using (SPWeb web = site.OpenWeb())
            {
                SPList listDocs = web.Lists["Shared Documents"];
                SPListItem item = listDocs.Items[0];
                SPExportObject obj = new SPExportObject();
                obj.Id = item.UniqueId;
                obj.Type = SPDeploymentObjectType.ListItem;

                SPList listTasks = web.Lists["Tasks"];
                SPListItem item2 = listTasks.Items[0];
                SPExportObject obj2 = new SPExportObject();
                obj2.Id = item2.UniqueId;
                obj2.Type = SPDeploymentObjectType.ListItem;


                SPExportSettings settings = new SPExportSettings();
                settings.IncludeVersions = SPIncludeVersions.LastMajor;
                settings.SiteUrl = site.Url;
                settings.IncludeSecurity = SPIncludeSecurity.None;
                settings.FileLocation = "C:\\export";
                settings.BaseFileName = "blop";
                settings.CommandLineVerbose = true;
                settings.ExportObjects.Add(obj);
                settings.ExportObjects.Add(obj2);
                settings.OverwriteExistingDataFile = true;

                SPExport export = new SPExport(settings);
                export.Run();

            }
        }
    }
  }
}
2
  • Is backup/restore using STSADM out of the question? Then they would be EXACTLY the same...
    – Kit Menke
    May 26, 2011 at 17:16
  • Code above was just a proof of concept. For my client, it would be more complex, with business logic. And stsadm backup/restore only work at a site collection level. stsadm export/import has exactly the same problem. May 26, 2011 at 17:40

2 Answers 2

2

I found one solution :

Microsoft let us modify the XML files used to import data :

Screenshot temp folder

So what I did :

  • Set the import settings.RetainObjectIdentity to true.
  • Modify the xml files to change the Guids of existing content

Right now, there's a lot of hardcoded things, but I think, I will be able to make it more generic.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Deployment;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using System.IO;

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
        Export();
        Import();
    }

    static void Import()
    {
        using (SPSite site = new SPSite("http://localhost:5555/sites/aa"))
        {
            using (SPWeb web = site.OpenWeb())
            {
                SPImportSettings settings = new SPImportSettings();
                settings.SiteUrl = site.Url;
                settings.FileLocation = @"c:\export";
                settings.BaseFileName = "blop.cmp";
                settings.RetainObjectIdentity = true;

                settings.CommandLineVerbose = true;

                SPImport import = new SPImport(settings);
                import.Started += new EventHandler<SPDeploymentEventArgs>(import_Started);
                import.Run();  
            }
        }
    }

    static void import_Started(object sender, SPDeploymentEventArgs e)
    {
        Guid IDListOld = Guid.Empty;
        Guid IDItemOld = Guid.Empty;
        Guid IDWebOld = Guid.Empty;
        Guid IDRootFolderOld = Guid.Empty;
        Guid IDFolderTaskOld = Guid.Empty;
        string IDCtypeOld = "";

        Guid IDListNew = Guid.Empty;
        Guid IDItemNew = Guid.Empty;
        Guid IDWebNew = Guid.Empty;
        Guid IDRootFolderNew = Guid.Empty;
        Guid IDFolderTaskNew = Guid.Empty;
        string IDCtypeNew = "";

        using (SPSite site = new SPSite("http://localhost:5555"))
        {
            using (SPWeb web = site.OpenWeb())
            {
                SPList list = web.Lists["Tasks"];
                IDWebOld = web.ID;
                IDListOld = list.ID;
                IDItemOld = list.Items[0].UniqueId;
                IDCtypeOld = list.Items[0].ContentType.Id.ToString();
                IDRootFolderOld = list.RootFolder.UniqueId;
                IDFolderTaskOld = web.GetFolder("Lists/Tasks/Task").UniqueId;
            }
        }

        using (SPSite site = new SPSite("http://localhost:5555/sites/aa/"))
        {
            using (SPWeb web = site.OpenWeb())
            {
                SPList list = web.Lists["Tasks"];
                IDWebNew = web.ID;
                IDListNew = list.ID;
                IDItemNew= list.Items[0].UniqueId;
                IDCtypeNew = list.Items[0].ContentType.Id.ToString();
                IDRootFolderNew = list.RootFolder.UniqueId;
                IDFolderTaskNew = web.GetFolder("Lists/Tasks/Task").UniqueId;
            }
        }

        DirectoryInfo d = new DirectoryInfo(e.TempDirectoryPath);
        foreach (FileInfo info in d.GetFiles())
        {
            string content = "";
            using (TextReader reader = File.OpenText(info.FullName))
            {
                content = reader.ReadToEnd();
                content = content.Replace(IDItemOld.ToString(), IDItemNew.ToString());
                content = content.Replace(IDWebOld.ToString(), IDWebNew.ToString());
                content = content.Replace(IDListOld.ToString(), IDListNew.ToString());
                content = content.Replace(IDCtypeOld.ToString(), IDCtypeNew.ToString());
                content = content.Replace(IDRootFolderOld.ToString(), IDRootFolderNew.ToString());
                content = content.Replace(IDFolderTaskOld.ToString(), IDFolderTaskNew.ToString());
            }
            File.WriteAllText(info.FullName, content);

        }
    }


    static void Export()
    {
        using (SPSite site = new SPSite("http://localhost:5555"))
        {
            using (SPWeb web = site.OpenWeb())
            {
                SPList listTasks = web.Lists["Tasks"];
                SPListItem item2 = listTasks.Items[0];
                SPExportObject obj2 = new SPExportObject();
                obj2.Id = item2.UniqueId;
                obj2.Type = SPDeploymentObjectType.ListItem;

                SPExportSettings settings = new SPExportSettings();
                settings.IncludeVersions = SPIncludeVersions.LastMajor;
                settings.SiteUrl = site.Url;
                settings.IncludeSecurity = SPIncludeSecurity.None;
                settings.FileLocation = "C:\\export";
                settings.BaseFileName = "blop";
                settings.CommandLineVerbose = true;
                settings.ExportObjects.Add(obj2);
                settings.OverwriteExistingDataFile = true;

                SPExport export = new SPExport(settings);
                export.Run();
            }
        }
    }
   }
}

[By the way, I don't know if I should have edited my question instead]

1
  • 1
    Answering your own questions is acceptable, but you might need to wait a day before you can accept it. There is a badge designed for such users. May 27, 2011 at 13:59
0

The reason for this is the way the SharePoint API itself handles versions. When you call SPFolder.Add() with a duplicated filename and versioning is enabled, then a new version is added (rather than a new file added).

One thing you may want to try is enabling versioning on the List before the import - this may allow updates (with versions saved).

If not, I'm afraid, as you have identified, the only way will be to clear the list before running the import.

1
  • Thx for your answer, but enabling versioning doesn't help :( May 24, 2011 at 17:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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