如何在已部署的应用程序中更改数据库设计?

时间:2010-09-30 12:32:46

标签: c# sql-server database deployment

场合

我正在创建一个C#/ WPF 4应用程序,使用SQL Compact Edition数据库作为实体框架的后端并使用ClickOnce进行部署。

我对使用数据库的应用程序相当新,但我不怀疑我在设计和构建原始数据库时会遇到很多问题。但是,我担心将来我需要添加或更改一些功能,这些功能要求我在部署数据库并且用户在数据库中有数据后更改数据库设计。

问题

  1. 是否可以通过clickonce更新将更新的数据库设计推送给用户,就像更改代码一样?

  2. 如果我这样做,用户的数据会受到怎样的影响?

  3. 在实际情况下,这种事情是如何完成的?什么是最佳实践?

  4. 我认为在最坏的情况下,我需要在数据库或程序设置中构建某种“版本”号,并创建一些例程来将用户当前版本的数据库迁移到新版本。

    我很欣赏任何有关我的问题的见解。非常感谢。

6 个答案:

答案 0 :(得分:13)

在设计数据库以允许设计更改时,会使用一些“技巧”。

首先,许多数据库设计者创建代码来反对代码,而不是直接编写表。这允许更改表(拆分或合并等),同时只需要更新视图。您可能需要为此调查database refactoring技术。

其次,您确实可以将版本信息添加到数据库中(通常作为具有单个字段的“版本”表)。可以通过代码或脚本来更新数据库。我工作的一个系统会自动检查数据库版本,然后通过代码中的版本逐步更新模式,直到它与运行时所需的版本匹配。这是一项艰巨的任务。

答案 1 :(得分:2)

我认为你的“最糟糕”案例实际上是一条很好的路线。在数据库中维护数据库版本,并让应用程序根据需要检查并更新数据库。如果正确构建更新程序,它应该能够维护用户的数据。根据更新,这可能涉及创建临时表以保存现有数据并从中重新填充表的新版本。您可以在更新过程中使用新架构include a new SDF file并简单地传输数据。这种方式可能稍微容易一些 - 您可以使用文件命名来区分版本并以这种方式触发更新代码。

答案 2 :(得分:2)

不幸的是,数据库的版本控制和变更管理非常迫切,绝望远离您对其余代码所能做的事情。

如果你有一个仅限内部的环境,有许多工具可以帮助你(DBGhost,Red Gate有一个新的应用程序,一些部署管理应用程序),但它们都不是完整的解决方案imho,但它们是大多数都足够好。

对于客户提供的解决方案,你真的没有比我最害怕的最坏情况更好的东西。只需尝试灵活设计 - 请参阅Dr.Herbie的答案。

这基本上不是一个解决的问题。

答案 3 :(得分:2)

Brian Noyes的“使用ClickOnce进行智能客户端部署”在这个问题上有一个很好的章节。 (第5章) ISBN 978-0-32-119769-6

他建议这样的事情:

if(ApplicationDeployment.CurrentDeployment.IsFirstRun) {
    MigrateData();
}

private void MigrateData() {
    string previousDb = Path.Combine(ApplicationDeployment.CurrentDeployment.DataDirectory, @".\pre\mydb.sdf");

    if(!File.Exists(previousDb))
        return;

    string oldConnString = @"Data Source=|DataDirectory|\.pre\mydb.sdf";
    string newConnString = @"Data Source=|DataDirectory|\mydb.sdf";

    //If you are using datasets perform any migration here, with the old and new table adapters.
    //Otherwise use an .sql data migration script.
    //Store the version of the database in the database, and check that in the beginning of your update script and GOTO the correct line in the SQL script.

}

答案 4 :(得分:2)

常见的解决方案是在数据库的某处包含版本号。如果您有一个包含其他系统数据的表,请将其放在那里,或者创建一个包含一条记录的表以保存数据库版本号。然后,只要程序启动,请检查数据库版本是否小于预期版本。如果是这样,请执行所需的SQL CREATE,ALTER等命令以使其加快速度。为每个版本更改都有一个脚本或函数。因此,如果您看到数据库当前处于版本6且代码需要版本8,请执行6到7更新和7到8更新。

我们在我工作的一个项目中使用的另一种方法是发送一个只有模式,没有带代码的数据库。每次安装新版本时,安装程​​序也会安装此新空白数据库的最新副本。然后,当程序启动时,它会将用户当前的数据库模式与新的数据库模式进行比较,并确定动态需要哪些数据库更改。就像,如果在“参考模式”表中,Foo有一个名为Bar的列,并且用户当前数据库中没有列Bar,我们将生成一个“alter table Foo add Bar ...”并执行它。虽然编写程序的初稿来完成这项工作是相当多的工作,但是一旦我们完成它,几乎没有任何维护来保持数据库架构的最新状态。转换只是即时完成。

请注意,此方案不处理需要更改数据值的数据库更改,例如,如果添加新列,必须通过对来自其他表或其他表的数据执行某些计算来初始填充该列。但是,如果您可以从旧数据生成新数据,那么这必然意味着新数据是冗余的,并且您的数据库未规范化。我认为情况不会出现在我们面前。

答案 5 :(得分:0)

我在Android中的应用程序遇到了同样的问题,其中SQLite数据库添加了一个表。我更改了数据库的名称以包含版本扩展名,例如:theDataBaseV1,删除了上一个版本,应用程序正常工作。

我刚刚更改了数据库的名称和这行代码中的名称

private static final String DATABASE_NAME = "busesBogotaV2.db";
在DBManager打开时

有人知道这个简单的解决方案是否会产生任何意想不到的后果吗?