大型系統具有一個通用的附件管理功能,對於單據中沒法清晰表達的字段,用一個附件圖片或附件文檔表示是最好的方法了。好比物料清單附加一張CAD圖紙,銷售訂單評審功能中附加客戶的各類表格,通用附件功能對系統起到畫龍點睛的做用。一圖解千言,先來看一下界面設計模式,看起來和通常的數據輸入功能相同。html
首先是設計附件表,它的定義參考下面的代碼。數據庫
CREATE TABLE [dbo].[Attachment] ( [Index] [int] NOT NULL, [MasterTable] [nvarchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL CONSTRAINT [DF__Attachmen__Maste__5165187F] DEFAULT (''), [MasterKey] [decimal] (10, 0) NOT NULL CONSTRAINT [DF__Attachmen__Maste__52593CB8] DEFAULT ((0)), [FileType] [nvarchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL CONSTRAINT [DF__Attachmen__FileT__534D60F1] DEFAULT (''), [FilePath] [nvarchar] (250) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, [CreatedDate] [datetime] NULL, [CreatedBy] [nvarchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, [RevisedDate] [datetime] NULL, [RevisedBy] [nvarchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, [Description] [nvarchar] (60) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, [KeySegment1] [nvarchar] (30) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, [KeySegment2] [nvarchar] (30) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, [KeySegment3] [nvarchar] (30) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, [KeySegment4] [nvarchar] (30) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, [KeySegment5] [nvarchar] (30) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, [Size] [decimal] (18, 0) NULL, [File] [image] NULL, [UploadedBy] [nvarchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, [UploadedDate] [datetime] NULL, [Md5Hash] [nvarchar] (32) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO ALTER TABLE [dbo].[Attachment] ADD CONSTRAINT [PK_Attachment] PRIMARY KEY CLUSTERED ([Index], [MasterTable], [MasterKey]) ON [PRIMARY] GO EXEC sp_addextendedproperty N'MS_Description', N'附件', 'SCHEMA', N'dbo', 'TABLE', N'Attachment', NULL, NULL GO EXEC sp_addextendedproperty N'MS_Description', N'索引', 'SCHEMA', N'dbo', 'TABLE', N'Attachment', 'COLUMN', N'Index' GO EXEC sp_addextendedproperty N'MS_Description', N'附件所附加的主表', 'SCHEMA', N'dbo', 'TABLE', N'Attachment', 'COLUMN', N'MasterTable' GO EXEC sp_addextendedproperty N'MS_Description', N'主鍵', 'SCHEMA', N'dbo', 'TABLE', N'Attachment', 'COLUMN', N'MasterKey' GO EXEC sp_addextendedproperty N'MS_Description', N'文件類型', 'SCHEMA', N'dbo', 'TABLE', N'Attachment', 'COLUMN', N'FileType' GO EXEC sp_addextendedproperty N'MS_Description', N'文件路徑', 'SCHEMA', N'dbo', 'TABLE', N'Attachment', 'COLUMN', N'FilePath' GO EXEC sp_addextendedproperty N'MS_Description', N'建立日期', 'SCHEMA', N'dbo', 'TABLE', N'Attachment', 'COLUMN', N'CreatedDate' GO EXEC sp_addextendedproperty N'MS_Description', N'創建人', 'SCHEMA', N'dbo', 'TABLE', N'Attachment', 'COLUMN', N'CreatedBy' GO EXEC sp_addextendedproperty N'MS_Description', N'修改日期', 'SCHEMA', N'dbo', 'TABLE', N'Attachment', 'COLUMN', N'RevisedDate' GO EXEC sp_addextendedproperty N'MS_Description', N'修改人', 'SCHEMA', N'dbo', 'TABLE', N'Attachment', 'COLUMN', N'RevisedBy' GO EXEC sp_addextendedproperty N'MS_Description', N'名稱', 'SCHEMA', N'dbo', 'TABLE', N'Attachment', 'COLUMN', N'Description' GO EXEC sp_addextendedproperty N'MS_Description', N'關鍵詞', 'SCHEMA', N'dbo', 'TABLE', N'Attachment', 'COLUMN', N'KeySegment1' GO EXEC sp_addextendedproperty N'MS_Description', N'關鍵詞', 'SCHEMA', N'dbo', 'TABLE', N'Attachment', 'COLUMN', N'KeySegment2' GO EXEC sp_addextendedproperty N'MS_Description', N'關鍵詞', 'SCHEMA', N'dbo', 'TABLE', N'Attachment', 'COLUMN', N'KeySegment3' GO EXEC sp_addextendedproperty N'MS_Description', N'關鍵詞', 'SCHEMA', N'dbo', 'TABLE', N'Attachment', 'COLUMN', N'KeySegment4' GO EXEC sp_addextendedproperty N'MS_Description', N'關鍵詞', 'SCHEMA', N'dbo', 'TABLE', N'Attachment', 'COLUMN', N'KeySegment5' GO EXEC sp_addextendedproperty N'MS_Description', N'附件大小', 'SCHEMA', N'dbo', 'TABLE', N'Attachment', 'COLUMN', N'Size' GO EXEC sp_addextendedproperty N'MS_Description', N'附件內容', 'SCHEMA', N'dbo', 'TABLE', N'Attachment', 'COLUMN', N'File' GO EXEC sp_addextendedproperty N'MS_Description', N'上傳人', 'SCHEMA', N'dbo', 'TABLE', N'Attachment', 'COLUMN', N'UploadedBy' GO EXEC sp_addextendedproperty N'MS_Description', N'上傳日期', 'SCHEMA', N'dbo', 'TABLE', N'Attachment', 'COLUMN', N'UploadedDate' GO EXEC sp_addextendedproperty N'MS_Description', N'哈希值', 'SCHEMA', N'dbo', 'TABLE', N'Attachment', 'COLUMN', N'Md5Hash' GO
在之前的一篇文章中解釋過,爲何須要給每一個數據庫表增長一個Recnum(記錄編號)的數字值字段,咱們在這裏要記錄下的業務功能表中要使用附件的功能,也就是要記下表中的Recnum的值。設計模式
MasterTable用於程序分組顯示附件,當上傳的附件比較多而又不容易到每一個獨立的功能中去查找,須要設計一個附件瀏覽器功能,用於查看系統中的全部附件。瀏覽器
有了以上兩個基礎,附件功能基本上完成。再來增長附件文件存儲或下載查看功能。服務器
先來看一下附件的存儲方法。能夠直接將附件存放在數據庫中,也能夠考慮增長一個FTP服務器,將附件傳送到文件服務器中。當附件文件過大時,存在數據庫中會影響數據庫性能,優勢是便於遷移。存放在FTP服務器中,優勢是性能會好,缺點是要考慮文件系統的相關事項。好比用戶A上傳一個附件文件DOC20150718.pdf,用戶B也上傳了一份一樣的文件DOC20150718.pdf,後上傳的文件名不能覆蓋前面已經上傳的文件名。解決方法是用GUID表示文件名,數據庫中記錄下文件的GUID,這樣能夠解決文件重複性問題,但不能解決文件可讀性問題。在FTP目錄中打開文件夾結構,看到都是GUID做文件名的文件,不利於搜索。因而須要考慮文件名可讀性的問題,好比按照用戶和時間的組合來命名。仍是之前面的文件名DOC20150718.pdf爲例子,當前登錄用戶名是A,我能夠將此文件重命名爲用戶+年+月+日+小時分鐘+ 文件名+ 流水號的文件編碼方案給文件命名,因而上面的文件名變成A-201507182110-DOC20150718-0012.pdf,文件名中的時間部分已經精確到分鐘,重複的可能性大大下降,增長了可讀性。我按照這個規則再寫一個文件重命名工具,萬一這些文件與ERP系統脫離關係,用軟件工具簡單的重命名,也能夠恢復到當初用戶上傳時使用的文件名。ide
再來看閱讀器編碼。PDF閱讀器和DOCX閱讀器來自於RadControls_WinForms_2013,它內置了這兩種文檔的閱讀器控件,調用起來簡潔。PDF閱讀器代碼調用以下:工具
private Telerik.WinControls.UI.RadPdfViewer readerPDF; this.readerPDF.Visible = true; if (attachment != null && attachment.Length > 0) { MemoryStream stream = new MemoryStream(attachment); this.readerPDF.LoadDocument(stream); }
DOCX文檔閱讀器代碼調用參考以下:性能
IDocumentFormatProvider provider = GetProviderByExtension(extension); if (provider == null) { throw new FileLoadException("Unable to find format provider for extension " + extension); } using (Stream stream = File.OpenRead(file)) { RadDocument document = provider.Import(stream); this.readerWord.Document = document; document.LayoutMode = DocumentLayoutMode.Paged; readerWord.ChangeSectionPageOrientation(PageOrientation.Rotate270); readerWord.Focus(); }
.NET有功能強大的文件API Aspose 軟件包,包含市面上幾乎全部文件的轉換接口,這是.NET的File API。對於不可直接閱讀的文件,如Excel,PowerPoint等常見文件格式,可考慮調用Aspose 文件接口轉化爲PDF,再調用PDF閱讀器顯示。Aspose 在文件處理方面應用至關普遍,與文件轉化相關的功能推薦用此接口。this
總結一下通用附件管理功能的三個要點:編碼
1 如何關聯業務功能表,主要保存Recnum記錄編號。
2 如何存儲附件, FTP文件服務器或數據庫image二進制字段。
3 如何查看文檔, PDF和DOCX文檔閱讀器,其它常見文檔轉化爲PDF。