來源於: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>