SharePoint 数据迁移解决方案

  前言:说来惭愧,我们的SharePoint内网门户跑了2年,不堪重负,数据量也不是很大,库有60GB左右,数据量几万条,总之由于各种原因吧,网站速度非常慢,具体问题研究了很久,也无从解决,所有考虑用Net重新搭网站,进行数据迁移,也就带来了数据迁移这个问题。

  思路:由于SharePoint的架构和Net有着不一样的特点,而且SharePoint的数据库设计是不为人所知的(当然我们可以了解一些,但不完全),虽然也是基于Net架构的,但是我们很难做到Sql To Sql的方式。所以,只能考虑服务器端对象模型,插入到数据库中的方式,其间,经理给的建议非常合理,就是将SharePoint的数据整理好插入中间库,然后统一插入到新网站数据库中。在后来的实践中,发现这一方法对数据迁移和检查,都有着非常好的帮助,避免了很多SharePoint对象模型中出错,但是不好更正的现象。

  中间库设计

  考虑到原内网门户有列表、文档库、图片库三种主要类型(特殊列表特殊对待),所以创建了两个数据库表,分别用来存List和DocLib,同时再创建两个表Image和Attachment用来存列表正文中的图片和列表附件(文档库文档当做列表附件)。

  一、用来存储列表内容的表 --  TABLE [dbo].[List]

[ID] [int] IDENTITY(1,1) NOT NULL,--主键ID
[WebID] [nvarchar](max) NULL,--所在网站的Guid
[ListID] [nvarchar](max) NULL,--所在列表的Guid
[ListName] [nvarchar](max) NULL,--列表名称
[ContentType] [nvarchar](max) NULL,--所属内容类型
[ItemID] [nvarchar](max) NULL,-- 列表里面的ID
[ApprovalState] [int] NULL,--审批状态
[Title] [nvarchar](max) NULL,--标题
[SubTitle] [nchar](10) NULL,--副标题
[ItemContent] [nvarchar](max) NULL,--内容
[Creator] [nvarchar](max) NULL,--创建者LoginName
[CreatorID] [nvarchar](max) NULL,--创建者UserID
[DispCreator] [nvarchar](max) NULL,--创建者UserName
[Modifier] [nvarchar](max) NULL,--修改者LoginName
[ModifierID] [nvarchar](max) NULL,--修改者UserID
[DispModifier] [nvarchar](max) NULL,--修改者UserName
[CreatTime] [datetime] NULL,--创建时间
[ModifyTime] [datetime] NULL,--修改时间
[TransferDate] [datetime] NULL,--数据迁移时间

  二、用来存储文档库/图片库的表 -- TABLE [dbo].[DocLib]

[ID] [int] IDENTITY(1,1) NOT NULL,--主键ID
[WebID] [nvarchar](max) NULL,--所在网站的Guid
[ListID] [nvarchar](max) NULL,--所在列表的Guid
[ListName] [nvarchar](max) NULL,--列表名称
[ListType] [nvarchar](max) NULL,--列表类型(文档库/图片库)
[ItemID] [nvarchar](max) NULL,-- 列表里面的ID
[ApprovalState] [int] NULL,--审批状态
[Title] [nvarchar](max) NULL,--标题
[Creator] [nvarchar](max) NULL,--创建者LoginName
[CreatorID] [nvarchar](max) NULL,--创建者UserID
[DispCreator] [nvarchar](max) NULL,--创建者UserName
[Modifier] [nvarchar](max) NULL,--修改者LoginName
[ModifierID] [nvarchar](max) NULL,--修改者UserID
[DispModifier] [nvarchar](max) NULL,--修改者UserName
[CreatTime] [datetime] NULL,--创建时间
[ModifyTime] [datetime] NULL,--修改时间
[Url] [nvarchar](max) NULL,--文档的Url
[TransferDate] [datetime] NULL,--数据迁移时间

   三、用来存储正文图片的表 -- TABLE [dbo].[Image]

[ID] [int] IDENTITY(1,1) NOT NULL,--主键ID
[WebID] [nvarchar](max) NULL,--所在Web的Guid
[WebSubUrl] [nvarchar](max) NULL,--所在Web的相对WebUrl
[ListID] [nvarchar](max) NULL,--所在列表的Guid
[ListName] [nvarchar](max) NULL,--列表名称
[ItemID] [nvarchar](max) NULL,-- 列表里面的ID
[ImageUrl] [nvarchar](max) NULL,--内容图片的Url,多张图片,逗号分隔

   四、用来存储附件集的表 -- TABLE [dbo].[Attachment]

[ID] [int] IDENTITY(1,1) NOT NULL,--主键ID
[WebID] [nvarchar](max) NULL,--所在Web的Guid
[WebSubUrl] [nvarchar](max) NULL,--所在Web的相对WebUrl
[ListID] [nvarchar](max) NULL,--所在列表的Guid
[ListName] [nvarchar](max) NULL--列表名称
[ItemID] [nvarchar](max) NULL,-- 列表里面的ID
[AttachUrl] [nvarchar](max) NULL,--附件的Url,多个的时候,逗号分隔

  代码方法段:

  首先就是对象模型读取列表插入List表,然后是对象模型读取文档库/图片库插入DocLib表,读取字段的代码比较简单,我们就不过多介绍,就介绍下其间遇到的几个问题,也避免代码太多太繁杂。

  问题一:正文乱码

  这是一个比较操心的问题,插入数据没有问题,但是到新系统显示,发现好多正文带有雷系”?“之类的东西,这样子肯定不行,首先想到RePlace,然后想想不太靠谱,因为正文里很有可能有正常的问号,这样会被替换掉。后来想到可能是编码问题,后来证实确实是编码问题,将特别的空格处理替换为 即可,处理如下:

//Content替换空格为  
byte[] space = new byte[] { 0xc2, 0xa0 };
string UTFSpace = System.Text.Encoding.GetEncoding("UTF-8").GetString(space);
Content = Content.Replace(UTFSpace, " ");
Content = DeleteHtmlImgTag(Content);
Content = Content.Replace("'", "''");

  问题二 处理中途报错

  插入过程中,我们会出现一些操作异常的情况,可能整个程序要运行4-5个小时,但是4个小时的时候,出现异常了,我们很恼火,调试也很困难,因为很难去调试问题,即使把断点打在Catch里面,调试也是力不从心的,所以,我们必须一次成功,不容许中间出差错。这样,我采取了空跑程序(只走对象模型,不插入数据库,因为Insert很慢,而且几乎不报错,错误多数出现在对象模型调用上,各种字段没有、对象为空)和记录错误补录两个方式,来避免这样的问题。

public static void WriteErrorLog(string ErrorMessage)
{
    try
    {
    using (StreamWriter sw = File.AppendText(@"log_error " + InsertTime.ToString("yyyy-MM-dd HHmmss") + ".txt"))
    {
        sw.WriteLine(ErrorMessage);
        sw.Dispose();
    }
    }
    catch{
    }
    Console.WriteLine(ErrorMessage);
}

  问题三 处理中间的小错误

  操作过程中,对于代码编写的可靠性,要求很好,就像上面所说,一个要跑4-5个小时的程序,4个小时的时候报错,我们基本就属于前功尽弃,因为继续插入是很困难的。所以中间的小问题,对于代码段的可靠性要求,就非常高了。必要的时候,多加一些Try...Catch...可能会对于效率有一点点影响,但是对于整个程序来说,是非常必要的。

if (!web.Exists){}//判断web是否存在
list = web.Lists[ListName];//打开的时候Try一下,避免不存在,ListName最好Trim一下
if (list.BaseTemplate == SPListTemplateType.Announcements)//判断list类型
if (list.Fields.ContainsField("SubTitle"))//判断是否有SubTitle这个字段
//副标题对象不为空,才赋值,否则赋值为空字符串(下面那行的注释…)
SubTitle = (item["SubTitle"] == null) ? string.Empty : item["SubTitle"].ToString();

  问题四 提取正文中的图片URL

  我们数据迁移过程,正文中会带有图片,这就要求我们把图片保存下来,迁移过去,然后还要插入到相同的位置。这是个比较让人头疼的问题,首先说下逻辑,读取正文的时候,用正则表达式获取所有的图片(不是绝对路径的要拼成绝对路径),然后插入到Image中间库中,将原来图片的位置,替换为一个图片标志,因为之后我们还要把图片插入到这里。

/// <summary>
/// 取得HTML中所有图片的 URL。
/// </summary>
/// <param name="sHtmlText">HTML代码</param>
/// <returns>图片的URL列表</returns>
public static string[] GetHtmlImageUrlList(string sHtmlText)
{
    // 定义正则表达式用来匹配 img 标签
    Regex regImg = new Regex(@"<img\b[^<>]*?\bsrc[\s\t\r\n]*=[\s\t\r\n]*[""']?[\s\t\r\n]*(?<imgUrl>[^\s\t\r\n""'<>]*)[^<>]*?/?[\s\t\r\n]*>", RegexOptions.IgnoreCase);

    // 搜索匹配的字符串
    MatchCollection matches = regImg.Matches(sHtmlText);
    int i = 0;
    string[] sUrlList = new string[matches.Count];

    // 取得匹配项列表
    foreach (Match match in matches)
    sUrlList[i++] = match.Groups["imgUrl"].Value;
    return sUrlList;
}

  问题五 将正文中的图片Url换为标识<ImgType>

  同样使用正则表达式,将图片标签<img.../>替换为我们特定的标识,为将来replace回来做准备,代码附下:

/// <summary>
/// 去处HTML中所有图片的img标签。
/// </summary>
/// <param name="sHtmlText">HTML代码</param>
/// <returns>去除img标签后的Html</returns>
public static string DeleteHtmlImgTag(string sHtmlText)
{
    string result = Regex.Replace(sHtmlText, @"<img.*?src=(['""]?)(?<url>[^'"" ]+)(?=\1)[^>]*>", delegate(Match m)
    {
return "<ImgType>";
    });
    if (result.IndexOf("</img>") > 0)
    {
result = result.Replace("</img>", "");
    }
    if (result.IndexOf("</IMG>") > 0)
    {
result = result.Replace("</IMG>", "");
    }
    return result;
}

  中间库到新系统:

  经过将SharePoint中数据,整理插入到中间库的过程,我们等于已经完成80%的工作,因为剩下的内容,就是Sql To Sql的问题了,对于net开发人员,甚至不需要设计,你只需要了解新系统的数据库结构,相应字段插入就可以了。唯一要提到的就是附件/图片处理的问题,下面我说下我的处理方式:

  附件/图片处理

  这也是一个比较棘手的问题,因为众所周知的原因,SharePoint的附件/图片是BLOB的形式,存储在数据库中的(我尝试去数据库中找这个字段,没找到);所以我们只能用对象模型,当然SPFile是我们第一时间想到的,但是效率可想而知(效率太慢放弃);所以考虑先将附件/图片的Url地址拼接好,插入到Images/Attachment的中间库中,然后采取WebClient的对象去下载为Byte[],然后直接上传,测试结果还是很客观的,100个附件1分钟左右(与附件大小有关)。

using (WebClient wc = new WebClient())
{
    NetworkCredential networkCredential = new NetworkCredential("用户名", "密码", "域");
    wc.Credentials = networkCredential;
    byte[] ss = wc.DownloadData(url);
    return ss;
}

  总结:数据迁移过程比较繁杂,需要考虑的东西比较多,前期的规划很重要,因为数据一旦迁移过去,修修补补会很让人郁闷,所以对应关系一定一定要先做好,避免后期修改。而且,两边系统的开发人员对接非常重要,避免出现少插入字段等现象,造成新系统出问题。基本上就是以上这些,写出来给有需要的人们参考下,就这样了。

时间: 2024-10-03 15:12:39

SharePoint 数据迁移解决方案的相关文章

SharePoint数据迁移解决方案详解

说来惭愧,我们的SharePoint内网门户跑了2年,不堪重负,数据量也不是很大,库有60GB左右,数据量几万条,总之由于各种原因吧,网站速度非常慢,具体问题研究了很久,也无从解决,所有考虑用Net重新搭网站,进行数据迁移,也就带来了数据迁移这个问题. 思路:由于SharePoint的架构和Net有着不一样的特点,而且SharePoint的数据库设计是不为人所知的(当然我们可以了解一些,但不完全),虽然也是基于Net架构的,但是我们很难做到Sql To Sql的方式.所以,只能考虑服务器端对象模

一个完美数据迁移解决方案诞生记

随着数据正在逐渐成为企业的核心资产,数据的存储.迁移成为企业时刻关注的问题.据Gartner统计数据表明,95%的受访企业都 认为数据迁移是个"硬骨头",让人头痛却又不得不面对.根据华为对业界的用户数据迁移行为的深入分析也发现,有接近38%的数据迁移需求源自于用户对IT系统服务器或是存储阵列的设备更新升级;超过11%的数据迁移需求源自于用户不得不对 长时间超负荷运营的IT设备进行维护操作;与此相当的是,也有超过11%的用户为了应对业务激增所面临的压力,必须对IT系统进行性能调优,从而导

科讯数码数据迁移解决方案

近几年来,企业http://www.aliyun.com/zixun/aggregation/14054.html">信息技术更新速度加快,应用系统经常需要更换平台以提供更好的性能并满足业务系统的需要,数据集中化成为一种趋势,因而数据迁移的需求大增.由于企业应用系统复杂,数据迁移经常需要设计到主机.存储.网络.数据库.中间件.应用系统等环节,技术要求较高.采用传统方法进行数据迁移,因为涉及环节多,很容易造成数据丢失或者业务系统中断时间过长. 科讯数码数据迁移解决方案采用虚拟存储技术,在存储

oracle 数据库数据迁移解决方案_oracle

去年年底做了不少系统的数据迁移,大部分系统由于平台和版本的原因,做的是逻辑迁移,少部分做的是物理迁移,有一些心得体会,与大家分享. 首先说说迁移流程,在迁移之前,写好方案,特别是实施的方案步骤一定要写清楚,然后进行完整的测试.我们在迁移时,有的系统测试了四五次,通过测试来完善方案和流程. 针对物理迁移,也即通过RMAN备份来进行还原并应用归档的方式(这里不讨论通过dd方式进行的冷迁移),虽然注意的是要将数据库设为force logging的方式,在用RMAN做全备之前,一定要执行: 否则可能会产

IBM数据迁移服务-Softek zDMF

提供无中断的数据迁移解决方案,帮助降低整体存储成本,而无需考虑供应商和磁盘容量 许多IT 组织都希望在当今更经济实惠的高性能存储子系统上利用大容量卷,但却面临着复杂且会造成中断的数据迁移,这会对其业务应用程序带来负面影响.由于将数据转换到大容量卷上非常耗时并且会造成长时间的应用程序中断,因此组织中的IT 专家认识到需要使用一些工具帮助他们以较低的成本.更灵活.有效且可靠地移动数据,同时还能够更好地应对不断变化的市场环境. IBM 数据迁移服务-Softek z/OS® Dataset Mobil

SQL Server数据迁移至PostgreSQL出错的解释以及解决方案_PostgreSQL

问题重现: 1.PG客户端: postgres=# create table text_test (id int,info text); CREATE TABLE postgres=# insert into text_test values (1,E'\0x00'); ERROR: invalid byte sequence for encoding "UTF8": 0x00 2.SQL Server产生数据 create table test_varchar(id int,name

使用Kettle数据迁移添加主键和索引

Kettle是一款国外开源的etl工具,纯java编写,绿色无需安装,主要用于数据抽取.转换.装载.kettle兼容了市面上几十种数据库,故用kettle来做数据库的迁移视乎是个不错的选择. kettle的数据抽取主要在于抽取数据,而没有考虑数据库的函数.存储过程.视图.表结构以及索引.约束等等,而这些东西恰恰都是数据迁移需要考虑的事情.当然,如果在不考虑数据库中的函数.存储过程.视图的情况下,使用kettle进行数据的迁移还算是一个可行的方案. 这篇文章主要是讲述在使用kettle进行数据库的

SharePoint 2010工作流解决方案之向工作流中添加应用程序页

向工作流中添加应用程序页 修改工作流代码 首先,向工作流中添加一行代码,以将"Outcome"(结果)列的值设置为零报销单上显示的金额. 以后会在报销单汇总计算中用到此值. 设置工作流中的"Outcome"(结果)列的值 1.将在SharePoint 2010 工作流解决方案:创建带有关联窗体和启动窗体的工作流 主题中完成的项目加载到 Visual Studio. 2.打开 Workflow1.cs 代码 3.将以下代码添加到 createTask1_MethodI

MaxCompute跨Region数据迁移指导手册

概述 大数据计算服务(MaxCompute,原名ODPS)是一种快速.完全托管的 GB/TB/PB 级数据仓库解决方案.MaxCompute 为用户提供了完善的数据导入导出方案以及多种经典的分布式计算模型,能够更快速的解决海量数据计算问题,有效降低企业成本,并保障数据安全. 随着MaxCompute的多Region部署,一些用户可能需要把MaxCompute的应用从老的Region上迁移到和自己的业务系统相同的Region上来,从而在数据传输上获得更好的性能并减少数据传输费用.本指导手册主要聚焦