实现文档管理系统的建议,其中某些文档具有运行时替换字段

时间:2011-12-01 11:21:46

标签: database database-design replace

我的一个应用程序是文档管理系统,其中文档作为blob字段存储到数据库中。这不是一个语言特定的问题,无论如何我把Delphi放在标签中,因为这是我小心翼翼地提出问题的社区(许多使用Delphi的人都面临这些问题)。

我需要添加的一个功能是以编程方式向文档添加一些数据。我做了一个简单的例子来获得这个想法。一个字段是创建文档的日期。为此,用户将键入“a tag”,例如<DOCUMENT_DATE>,当从db中提取docuemnt时,日期将自动替换。

所以我有两个主要问题。 ONe是用作“标签”的东西。最简单的方法是使用文本标签,只需输入docuemnt然后执行搜索&amp;替换文本(使用例如MS Word ActiveX)。我已经为其他目的这样做了。替代方案可能是使用书签或其他技术。

另一个问题与之前的问题严格相关。

如何存储?我的第一个想法是使用“标签”将文档存储在DB中,因此当“签出”时,用户会看到标签,而当用户打开它时(以只读模式),他会看到替换文本。 (所以在第一种情况下他会看到并且在第二次“2011年10月12日”中)。

通过这种方式,我将文件存储一次,但每次打开文件时都会有处理它并执行搜索替换的开销,这也可能相对较慢。所以这就是我要求其他技术的原因。像serach替换书签。越快越好。

另一种方法是将文档存储两次:一次使用“标签”,另一次使用“替换的veresion”。这对性能有好处:没有Searh&amp;替换,但只是当文档在“结帐”模式下打开时,我将打开带有标签的那个,而当我以只读模式打开它时,我将打开替换模式。

这当然需要更多存储空间,对于每个文档版本(revision1,revision2,...),我需要存储2个文件。

我觉得双存储是最好的,因为它根本不会影响性能,我的意思是它会像现在一样快,只是签到过程会慢,因为我需要保存2个文件,而不是一个。此外,默认情况下,如果不在所有文档上启用此自动替换功能,则不会有双倍的db大小。

但无论如何我想听一些评论,因为这是一个非常关键的决定。

2 个答案:

答案 0 :(得分:2)

两次存储相同的数据真的没有意义 事实上,这是一个非常糟糕的主意,主要是从一个整体的角度来看 这样做的方法是将东西存储在不同的表中并在表之间创建链接。

这是一个名为normalization的过程。

这是一个使用MySQL的帖子松散启发的例子:

TABLE document
--------------
id UNSIGNED INTEGER AUTO_INCREMENT PRIMARY KEY,
data BLOB

TABLE tag
------------
id UNSIGNED INTEGER AUTO_INCREMENT PRIMARY KEY,
tag VARCHAR(20)

TABLE tag_link
-------------------
tag_id UNSIGNED INTEGER,
reference_nr UNSIGNED INTEGER,
PRIMARY KEY (tag_id, reference_nr)
FOREIGN KEY (tag_id) REFERENCES tag(id) ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (reference_nr) REFERENCES post(reference_nr) ON DELETE CASCADE ON UPDATE CASCADE,

TABLE post
----------------
reference_nr UNSIGNED INTEGER NOT NULL,
revision UNSIGNED INTEGER NOT NULL DEFAULT 1,
document_id UNSIGNED INTEGER,
title VARCHAR(255),
creation_date TIMESTAMP,
other_fields .....
PRIMARY KEY (reference_nr, revision),
FOREIGN KEY (document_id) REFERENCES document(id) ON DELETE SET NULL ON CASCADE UPDATE

现在您可以为帖子添加标签,帖子的所有修订都会共享相同的标签 帖子的修改可以链接到同一文档,也可以链接到不需要复制数据的不同文档。

如果您想获得包含特定标签的所有最新文档修订版,请使用以下查询:

SELECT p.title, d.data, GROUP_CONCAT(t.tag) AS tags
FROM post p
LEFT JOIN d.data ON (p.document_id = d.id)
INNER JOIN taglink tl ON (tl.reference_nr = p.reference_nr)
INNER JOIN tags t ON (tl.tag_id = t.id)
WHERE t.tag IN ('test','test2')
GROUP BY p.reference_nr  /*only works in MySQL because other db's do not support ANSI SQL 2003*/
HAVING p.revision = MAX(p.revision)
ORDER BY p.creation_date DESC

答案 1 :(得分:1)

我看到另外两种值得考虑的可能性。

<强> 1。使用RTF

如果您的文档模板是Word文档,我宁愿将它们存储为RTF。

RTF只是简单的ASCII,即使它是专有格式,它也有很好的文档记录,并且可以很容易地解析。 Word能够保存其内容并将其作为RTF读取。如果你有图片,它可以增长,但你可以压缩它之前在数据库中存储BLOB(你可以嵌入EMF图片)。

然后,您可以在代码中非常快速地处理这些RTF内容,使用最新版本的日期字段值更改所有<DOCUMENT_DATE>

我在几个应用程序中使用这种技术,它给出了非常好的结果。例如,请参阅我们的SynProject tool如何从纯文本生成Word文档,替换标签,动态设置书签或索引。使用RTF,您可以做的不仅仅是更换标签,还可以轻松创建整个文档。

对于最终用户输入,您可以使用基本TRichEdit或更高级(但不是免费)TRichView代替Word。

您可以考虑使用HTML而不是RTF,但它对打印的帮助要小得多。

<强> 2。使用报告引擎

另一种可能性是使用基于代码的报告引擎,然后创建PDF文件。

我们的开源单元可以在simple reporting class中使用,轻松创建文件内容,在屏幕上预览和/或以PDF格式打印/导出。它比RTF更容易使用,但必须在代码中设置布局,或者将基于文本/类似wiki的模板存储在数据库中。