ERP系統中要管理用戶為單據上傳的一些附件,比如增值稅發票,退貨發票,ROHS檢測報告,這時,需要設計一個通用的附件管理模塊來管理用戶上傳的附件。
數據表設計
IF OBJECT_ID ('dbo.Attachment') IS NOT NULL DROP TABLE dbo.Attachment GO CREATE TABLE dbo.Attachment ( Index INT NOT NULL, MasterTable NVARCHAR (50) DEFAULT ('') NOT NULL, MasterKey DECIMAL (10) DEFAULT ((0)) NOT NULL, FileType NVARCHAR (10) DEFAULT ('') NOT NULL, FilePath NVARCHAR (250) NULL, CreatedDate DATETIME NULL, CreatedBy NVARCHAR (10) NULL, RevisedDate DATETIME NULL, RevisedBy NVARCHAR (10) NULL, Description NVARCHAR (60) NULL, KeySegment1 NVARCHAR (30) NULL, KeySegment2 NVARCHAR (30) NULL, KeySegment3 NVARCHAR (30) NULL, KeySegment4 NVARCHAR (30) NULL, KeySegment5 NVARCHAR (30) NULL, Size DECIMAL (18) NULL, File IMAGE NULL, UploadedBy NVARCHAR (10) NULL, UploadedDate DATETIME NULL, Md5Hash NVARCHAR (32) NULL, CONSTRAINT PK_Attachment PRIMARY KEY (Index,MasterTable,MasterKey) ) GO
5個Key Segment是用來查找附件用的,相當於文章的關鍵字,用來標記此附件的大致內容。這里不提供附件內容的實際搜索功能,而只對設置的Key Segment進行查找與比較。我的另一個項目Data Solution對搜索存儲於SQL Server中的文件字節流進行搜索,進行了探索和嘗試。
4個必須要有的字段,Created By, Created Date, Revised By ,Revised Date用來記錄創建和修改附件的用戶,對IT審計有作用。ERP系統中的日記帳表基本上都有這4個字段供分析審計。
FileType 是自定義的可上傳的文件類型,比如傳真文件tif,圖片文件jpg/bmp/gif,Office 辦公文件Word/Excel/PPT
還有跨平台的通用文件格式PDF。
注意工具欄最后一個按鈕上面有個數字8,表示此客戶有附帶8個附件文件,點擊該按鈕,彈出附件管理窗口
工具欄中有新增,刪除按鈕,可對附件數據進行操作。
當附件的數量相當多的時候,還需要寫一個通用的附件瀏覽工具,以查看附件內容。
執行功能SAMFAB或SQAPTR,打開附件瀏覽器程序。
找到客戶編號001,可以從圖中看到,它有8個附件,在這里以附件類型進行了分組呈現。
雙擊一個附件圖標文件,File Explorer可為您打開它的內容,進行在線瀏覽。如果想把附件保存到本地,可以選中附件,點工具欄中的Export按鈕,彈出另存為對話框,為您保存附件文檔。
左邊的樹是從一個配置文件中讀取的,它保存數據表的分類以供加載到不同的模塊組別中。
讀取這個文件的方式是Linq to xml技術,自從掌握了Linq技術之后,簡單的幾句話完成復雜的讀取和寫入功能,代碼簡潔,容易維護。
string sql = Kingston.SystemAdminstration.Properties.Resources.LibraryExplorer; byte[] array = Encoding.ASCII.GetBytes(sql); MemoryStream stream = new MemoryStream(array); XDocument doc = XDocument.Load(stream); string library = doc.Root.Name.ToString(); treeView.BeginUpdate(); treeView.Nodes.Clear(); UltraTreeNode root=new UltraTreeNode(library,library); root.Tag = "Library"; root.LeftImages.Add(imgList.Images[0]); foreach(XElement node in doc.Root.Elements()) { UltraTreeNode module = new UltraTreeNode(node.Name.ToString(), node.Name.ToString()); module.Tag = "Module"; module.LeftImages.Add(imgList.Images[1]); foreach (XElement table in node.Elements()) { UltraTreeNode tableNode = new UltraTreeNode(table.Attribute("Name").Value, table.Attribute("Name").Value); tableNode.Tag = "Table"; tableNode.LeftImages.Add(imgList.Images[2]); module.Nodes.Add(tableNode); } root.Nodes.Add(module); } treeView.Nodes.Add(root); treeView.EndUpdate();
以資源文件嵌入到程序集中,讀取時它是個字符串,XDocument可接受一個文件名,或是一個字節流,所以開頭幾句我把它轉化為流來供Linq解析。
在系統設置中,有一個參數是控制附件的保存方式。系統是保存附件的路徑(File Path),還是保存附件的內容(字節流)。
如圖所示,Control Checklist的最后一項設定 Attachment Save into Database,即把附件的字節流保存到數據(Image)字段中,此選項會影響數據庫大小,但也有好的移植性。
以文件保存在本地為例,它只是對文件進行一個簡單的Copy動作,代碼如下所示
AttachmentEntity attachment = item.Tag as AttachmentEntity; SaveFileDialog saveDialog = new SaveFileDialog(); saveDialog.Filter = "Excel 97-2003|*.xls|Microsoft Word|*.doc|Adobe PDF|*.pdf|All File|*.*"; saveDialog.FileName = attachment.FilePath; if (saveDialog.ShowDialog() == DialogResult.OK) { string fileName = saveDialog.FileName; if (!string.IsNullOrWhiteSpace(attachment.FilePath)) { File.Copy(attachment.FilePath, saveDialog.FileName); } }
VB或DELPHI程序的習慣,會拖動一個SaveFileDialog 組件(component)到界面中,然后在這里直接引用。我傾向於在這里直接創建一個SaveFileDialog ,用完了讓它Dispose。use it and burn it,電影里面講到人與人的雇佣關系時,常用這個句子,用完了就拋棄。