SharePoint 數據遷移解決方案

來源於:http://www.cnblogs.com/jianyus/p/3262613.htmlhtml

前言說來慚愧,咱們的SharePoint內網門戶跑了2年,不堪重負,數據量也不是很大,庫有60GB左右,數據量幾萬條,總之因爲各類緣由吧,網站速度很是慢,具體問題研究了好久,也無從解決,全部考慮用Net從新搭網站,進行數據遷移,也就帶來了數據遷移這個問題。web

  思路因爲SharePoint的架構和Net有着不同的特色,並且SharePoint的數據庫設計是不爲人所知的(固然咱們能夠了解一些,但不徹底),雖然也是基於Net架構的,可是咱們很難作到Sql To Sql的方式。因此,只能考慮服務器端對象模型,插入到數據庫中的方式,其間,經理給的建議很是合理,就是將SharePoint的數據整理好插入中間庫,而後統一插入到新網站數據庫中。在後來的實踐中,發現這一方法對數據遷移和檢查,都有着很是好的幫助,避免了不少SharePoint對象模型中出錯,可是很差更正的現象。正則表達式

  中間庫設計數據庫

  考慮到原內網門戶有列表、文檔庫、圖片庫三種主要類型(特殊列表特殊對待),因此建立了兩個數據庫表,分別用來存List和DocLib,同時再建立兩個表Image和Attachment用來存列表正文中的圖片和列表附件(文檔庫文檔當作列表附件)。服務器

  1、用來存儲列表內容的表 --  TABLE [dbo].[List]架構

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[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,--數據遷移時間

  2、用來存儲文檔庫/圖片庫的表 -- TABLE [dbo].[DocLib]數據庫設計

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[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,--數據遷移時間

   3、用來存儲正文圖片的表 -- TABLE [dbo].[Image]測試

1
2
3
4
5
6
7
[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,多張圖片,逗號分隔

   4、用來存儲附件集的表 -- TABLE [dbo].[Attachment]網站

1
2
3
4
5
6
7
[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,多個的時候,逗號分隔

  代碼方法段:ui

  首先就是對象模型讀取列表插入List表,而後是對象模型讀取文檔庫/圖片庫插入DocLib表,讀取字段的代碼比較簡單,咱們就不過多介紹,就介紹下其間遇到的幾個問題,也避免代碼太多太繁雜。

  問題一:正文亂碼

  這是一個比較操心的問題,插入數據沒有問題,可是到新系統顯示,發現好多正文帶有雷系」?「之類的東西,這樣子確定不行,首先想到RePlace,而後想一想不太靠譜,由於正文裏頗有可能有正常的問號,這樣會被替換掉。後來想到多是編碼問題,後來證明確實是編碼問題,將特別的空格處理替換爲 便可,處理以下:

1
2
3
4
5
6
//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很慢,並且幾乎不報錯,錯誤多數出如今對象模型調用上,各類字段沒有、對象爲空)和記錄錯誤補錄兩個方式,來避免這樣的問題。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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...可能會對於效率有一點點影響,可是對於整個程序來講,是很是必要的。

1
2
3
4
5
6
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中間庫中,將原來圖片的位置,替換爲一個圖片標誌,由於以後咱們還要把圖片插入到這裏。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/// <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回來作準備,代碼附下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/// <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分鐘左右(與附件大小有關)。

1
2
3
4
5
6
7
using  (WebClient wc = new  WebClient())
{
     NetworkCredential networkCredential = new  NetworkCredential( "用戶名" , "密碼" , "域" );
     wc.Credentials = networkCredential;
     byte [] ss = wc.DownloadData(url);
     return  ss;
}

  總結:數據遷移過程比較繁雜,須要考慮的東西比較多,前期的規劃很重要,由於數據一旦遷移過去,修修補補會很讓人鬱悶,因此對應關係必定必定要先作好,避免後期修改。並且,兩邊系統的開發人員對接很是重要,避免出現少插入字段等現象,形成新系統出問題。基本上就是以上這些,寫出來給有須要的人們參考下,就這樣了。

 

 

每天想你紅棗,您的健康,‘棗‘的承諾 <a href="http://shop109102900.taobao.com" target="_blank" style="color:red">每天想你紅棗淘寶店</a>

相關文章
相關標籤/搜索