SharePoint發(fā)行版本有SharePoint2003、SharePoint2007、Sharepoint 2010、SharePoint2013和SharePoint2016。SharePoint提供了功能強(qiáng)大的團(tuán)隊(duì)協(xié)作環(huán)境,使得組織能夠在整個(gè)組織內(nèi)部實(shí)現(xiàn)整合、組織、查找和提供 SharePoint站點(diǎn)。 思路:由于SharePoint的架構(gòu)和Net有著不一樣的特點(diǎn),而且SharePoint的數(shù)據(jù)庫設(shè)計(jì)是不為人所知的(當(dāng)然我們可以了解一些,但不完全),雖然也是基于Net架構(gòu)的,但是我們很難做到Sql To Sql的方式。所以,只能考慮服務(wù)器端對(duì)象模型,插入到數(shù)據(jù)庫中的方式,其間,經(jīng)理給的建議非常合理,就是將SharePoint的數(shù)據(jù)整理好插入中間庫,然后統(tǒng)一插入到新網(wǎng)站數(shù)據(jù)庫中。在后來的實(shí)踐中,發(fā)現(xiàn)這一方法對(duì)數(shù)據(jù)遷移和檢查,都有著非常好的幫助,避免了很多SharePoint對(duì)象模型中出錯(cuò),但是不好更正的現(xiàn)象。 中間庫設(shè)計(jì): 考慮到原內(nèi)網(wǎng)門戶有列表、文檔庫、圖片庫三種主要類型(特殊列表特殊對(duì)待),所以創(chuàng)建了兩個(gè)數(shù)據(jù)庫表,分別用來存List和DocLib,同時(shí)再創(chuàng)建兩個(gè)表Image和Attachment用來存列表正文中的圖片和列表附件(文檔庫文檔當(dāng)做列表附件)。 一、用來存儲(chǔ)列表內(nèi)容的表 -- ?TABLE [dbo].[List] + View Code? 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,--所在網(wǎng)站的Guid [ListID] [nvarchar](max) NULL,--所在列表的Guid [ListName] [nvarchar](max) NULL,--列表名稱 [ContentType] [nvarchar](max) NULL,--所屬內(nèi)容類型 [ItemID] [nvarchar](max) NULL,-- 列表里面的ID [ApprovalState] [ int ] NULL,--審批狀態(tài) [Title] [nvarchar](max) NULL,--標(biāo)題 [SubTitle] [nchar](10) NULL,--副標(biāo)題 [ItemContent] [nvarchar](max) NULL,--內(nèi)容 [Creator] [nvarchar](max) NULL,--創(chuàng)建者LoginName [CreatorID] [nvarchar](max) NULL,--創(chuàng)建者UserID [DispCreator] [nvarchar](max) NULL,--創(chuàng)建者UserName [Modifier] [nvarchar](max) NULL,--修改者LoginName [ModifierID] [nvarchar](max) NULL,--修改者UserID [DispModifier] [nvarchar](max) NULL,--修改者UserName [CreatTime] [datetime] NULL,--創(chuàng)建時(shí)間 [ModifyTime] [datetime] NULL,--修改時(shí)間 [TransferDate] [datetime] NULL,--數(shù)據(jù)遷移時(shí)間 | 二、用來存儲(chǔ)文檔庫/圖片庫的表 --?TABLE [dbo].[DocLib] + View Code? 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,--所在網(wǎng)站的Guid [ListID] [nvarchar](max) NULL,--所在列表的Guid [ListName] [nvarchar](max) NULL,--列表名稱 [ListType] [nvarchar](max) NULL,--列表類型(文檔庫/圖片庫) [ItemID] [nvarchar](max) NULL,-- 列表里面的ID [ApprovalState] [ int ] NULL,--審批狀態(tài) [Title] [nvarchar](max) NULL,--標(biāo)題 [Creator] [nvarchar](max) NULL,--創(chuàng)建者LoginName [CreatorID] [nvarchar](max) NULL,--創(chuàng)建者UserID [DispCreator] [nvarchar](max) NULL,--創(chuàng)建者UserName [Modifier] [nvarchar](max) NULL,--修改者LoginName [ModifierID] [nvarchar](max) NULL,--修改者UserID [DispModifier] [nvarchar](max) NULL,--修改者UserName [CreatTime] [datetime] NULL,--創(chuàng)建時(shí)間 [ModifyTime] [datetime] NULL,--修改時(shí)間 [Url] [nvarchar](max) NULL,--文檔的Url [TransferDate] [datetime] NULL,--數(shù)據(jù)遷移時(shí)間 | ? 三、用來存儲(chǔ)正文圖片的表 -- TABLE [dbo].[Image] + View Code? 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的相對(duì)WebUrl [ListID] [nvarchar](max) NULL,--所在列表的Guid [ListName] [nvarchar](max) NULL,--列表名稱 [ItemID] [nvarchar](max) NULL,-- 列表里面的ID [ImageUrl] [nvarchar](max) NULL,--內(nèi)容圖片的Url,多張圖片,逗號(hào)分隔 | ? 四、用來存儲(chǔ)附件集的表 -- TABLE [dbo].[Attachment] + View Code? 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的相對(duì)WebUrl [ListID] [nvarchar](max) NULL,--所在列表的Guid [ListName] [nvarchar](max) NULL--列表名稱 [ItemID] [nvarchar](max) NULL,-- 列表里面的ID [AttachUrl] [nvarchar](max) NULL,--附件的Url,多個(gè)的時(shí)候,逗號(hào)分隔 | 代碼方法段: 首先就是對(duì)象模型讀取列表插入List表,然后是對(duì)象模型讀取文檔庫/圖片庫插入DocLib表,讀取字段的代碼比較簡(jiǎn)單,我們就不過多介紹,就介紹下其間遇到的幾個(gè)問題,也避免代碼太多太繁雜。 問題一:正文亂碼 這是一個(gè)比較操心的問題,插入數(shù)據(jù)沒有問題,但是到新系統(tǒng)顯示,發(fā)現(xiàn)好多正文帶有雷系”?“之類的東西,這樣子肯定不行,首先想到RePlace,然后想想不太靠譜,因?yàn)檎睦锖苡锌赡苡姓5膯柼?hào),這樣會(huì)被替換掉。后來想到可能是編碼問題,后來證實(shí)確實(shí)是編碼問題,將特別的空格處理替換為即可,處理如下: ? 1 2 3 4 5 6 | 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( "'" , "''" ); | 問題二 處理中途報(bào)錯(cuò) 插入過程中,我們會(huì)出現(xiàn)一些操作異常的情況,可能整個(gè)程序要運(yùn)行4-5個(gè)小時(shí),但是4個(gè)小時(shí)的時(shí)候,出現(xiàn)異常了,我們很惱火,調(diào)試也很困難,因?yàn)楹茈y去調(diào)試問題,即使把斷點(diǎn)打在Catch里面,調(diào)試也是力不從心的,所以,我們必須一次成功,不容許中間出差錯(cuò)。這樣,我采取了空跑程序(只走對(duì)象模型,不插入數(shù)據(jù)庫,因?yàn)镮nsert很慢,而且?guī)缀醪粓?bào)錯(cuò),錯(cuò)誤多數(shù)出現(xiàn)在對(duì)象模型調(diào)用上,各種字段沒有、對(duì)象為空)和記錄錯(cuò)誤補(bǔ)錄兩個(gè)方式,來避免這樣的問題。 ? 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); } | 問題三 處理中間的小錯(cuò)誤 操作過程中,對(duì)于代碼編寫的可靠性,要求很好,就像上面所說,一個(gè)要跑4-5個(gè)小時(shí)的程序,4個(gè)小時(shí)的時(shí)候報(bào)錯(cuò),我們基本就屬于前功盡棄,因?yàn)槔^續(xù)插入是很困難的。所以中間的小問題,對(duì)于代碼段的可靠性要求,就非常高了。必要的時(shí)候,多加一些Try...Catch...可能會(huì)對(duì)于效率有一點(diǎn)點(diǎn)影響,但是對(duì)于整個(gè)程序來說,是非常必要的。 ? 1 2 3 4 5 6 | if (!web.Exists){} list = web.Lists[ListName]; if (list.BaseTemplate == SPListTemplateType.Announcements) if (list.Fields.ContainsField( "SubTitle" )) SubTitle = (item[ "SubTitle" ] == null ) ? string .Empty : item[ "SubTitle" ].ToString(); | 問題四 提取正文中的圖片URL 我們數(shù)據(jù)遷移過程,正文中會(huì)帶有圖片,這就要求我們把圖片保存下來,遷移過去,然后還要插入到相同的位置。這是個(gè)比較讓人頭疼的問題,首先說下邏輯,讀取正文的時(shí)候,用正則表達(dá)式獲取所有的圖片(不是絕對(duì)路徑的要拼成絕對(duì)路徑),然后插入到Image中間庫中,將原來圖片的位置,替換為一個(gè)圖片標(biāo)志,因?yàn)橹笪覀冞要把圖片插入到這里。 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /// /// 取得HTML中所有圖片的 URL。 /// /// HTML代碼 /// 圖片的URL列表 public static string [] GetHtmlImageUrlList( string sHtmlText) { ???? ???? Regex regImg = new Regex( @"<><>]*?\bsrc[\s\t\r\n]*=[\s\t\r\n]*[""']?[\s\t\r\n]*(?[^\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換為標(biāo)識(shí) 同樣使用正則表達(dá)式,將圖片標(biāo)簽替換為我們特定的標(biāo)識(shí),為將來replace回來做準(zhǔn)備,代碼附下: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /// /// 去處HTML中所有圖片的img標(biāo)簽。 /// /// HTML代碼 /// 去除img標(biāo)簽后的Html public static string DeleteHtmlImgTag( string sHtmlText) { ???? string result = Regex.Replace(sHtmlText, @"<>[^'"" ]+)(?=\1)[^>]*>" , delegate (Match m) ???? { return "" ; ???? }); ???? if (result.IndexOf( "" ) > 0) ???? { result = result.Replace( "" , "" ); ???? } ???? if (result.IndexOf( "" ) > 0) ???? { result = result.Replace( "" , "" ); ???? } ???? return result; } | 中間庫到新系統(tǒng): 經(jīng)過將SharePoint中數(shù)據(jù),整理插入到中間庫的過程,我們等于已經(jīng)完成80%的工作,因?yàn)槭O碌膬?nèi)容,就是Sql To Sql的問題了,對(duì)于net開發(fā)人員,甚至不需要設(shè)計(jì),你只需要了解新系統(tǒng)的數(shù)據(jù)庫結(jié)構(gòu),相應(yīng)字段插入就可以了。唯一要提到的就是附件/圖片處理的問題,下面我說下我的處理方式: 附件/圖片處理 這也是一個(gè)比較棘手的問題,因?yàn)楸娝苤脑颍琒harePoint的附件/圖片是BLOB的形式,存儲(chǔ)在數(shù)據(jù)庫中的(我嘗試去數(shù)據(jù)庫中找這個(gè)字段,沒找到);所以我們只能用對(duì)象模型,當(dāng)然SPFile是我們第一時(shí)間想到的,但是效率可想而知(效率太慢放棄);所以考慮先將附件/圖片的Url地址拼接好,插入到Images/Attachment的中間庫中,然后采取WebClient的對(duì)象去下載為Byte[],然后直接上傳,測(cè)試結(jié)果還是很客觀的,100個(gè)附件1分鐘左右(與附件大小有關(guān))。 ? 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; } | 總結(jié):數(shù)據(jù)遷移過程比較繁雜,需要考慮的東西比較多,前期的規(guī)劃很重要,因?yàn)閿?shù)據(jù)一旦遷移過去,修修補(bǔ)補(bǔ)會(huì)很讓人郁悶,所以對(duì)應(yīng)關(guān)系一定一定要先做好,避免后期修改。而且,兩邊系統(tǒng)的開發(fā)人員對(duì)接非常重要,避免出現(xiàn)少插入字段等現(xiàn)象,造成新系統(tǒng)出問題�;旧暇褪且陨线@些,寫出來給有需要的人們參考下,就這樣了。
Sharepoint 可以幫助企業(yè)用戶輕松完成日常工作。
|