1. 阿里云解决方案网首页
  2. 经验技巧

ERP通用附件管理功能设计与实现

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。

image

注意工具栏最后一个按钮上面有个数字8,表示此客户有附带8个附件文件,点击该按钮,弹出附件管理窗口

image

工具栏中有新增,删除按钮,可对附件数据进行操作。

当附件的数量相当多的时候,还需要写一个通用的附件浏览工具,以查看附件内容。

执行功能SAMFAB或SQAPTR,打开附件浏览器程序。

image

找到客户编号001,可以从图中看到,它有8个附件,在这里以附件类型进行了分组呈现。

双击一个附件图标文件,File Explorer可为您打开它的内容,进行在线浏览。如果想把附件保存到本地,可以选中附件,点工具栏中的Export按钮,弹出另存为对话框,为您保存附件文档。

左边的树是从一个配置文件中读取的,它保存数据表的分类以供加载到不同的模块组别中。

image

读取这个文件的方式是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),还是保存附件的内容(字节流)。

image

如图所示,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,电影里面讲到人与人的雇佣关系时,常用这个句子,用完了就抛弃。

原创文章,作者:admin,如若转载,请注明出处:https://www.aliyunsolution.com/2057.html

发表评论

电子邮件地址不会被公开。 必填项已用*标注