首页 > 解决方案 > 使用多年后更新数据库

问题描述

编辑 1:最后的故事示例


几年前,我们创建了表格来计算我们的盒子里有多少产品。
有两个简单的表:

product (
    code VARCHAR(16) PK,
    length INT,
    width INT,
    height INT
)

box (
    pkid INT IDENTITY(1,1),
    barcode varchar(18),
    product_code VARCHAR(16) FK,
    quantity INT
)

还有两个相关的类:

public struct Product
{
    public string Code { get; set; }
    public int Length { get; set; }
    public int Width { get; set; }
    public int Heigth { get; set; }
}

public struct Box
{
    public int Id { get; set; }
    public string BarCode { get; set; }
    public Product Product { get; set; }
    public int Quantity { get; set; }
}

多年以后,我们需要将多个不同的产品放在同一个盒子里,所以我们现在需要这个:

product (
    code VARCHAR(16) PK,
    length INT,
    width INT,
    height INT
)

-- box changed
box (
    pkid INT IDENTITY(1,1),
    barcode varchar(18)
)

-- stock created
stock (
    box_pkid INT M-PK FK,
    product_code VARCHAR(16) M-PK FK,
    quantity INT
)

还有这个:

public struct Product
{
    public string Code { get; set; }
    public int Length { get; set; }
    public int Width { get; set; }
    public int Heigth { get; set; }
}

public struct Box
{
    public int Id { get; set; }
    public string BarCode { get; set; }
    public Dictionary<Product, int> Content { get; set; } // <-- this changed
    public int Quantity { get; set; }
}

但多年后,我们有很多代码,可能在一些黑暗的地方重复,是离开合作者留下的。我是一名实习生,所以我要求我将来的经历,以避免以后发生这种情况。

有什么解决方案可以更新我们的架构并保持数据完整性安全?即使数据库中有数百万行?


示例: 2014 年,我们需要在一个盒子里存放 10 本书罗密欧与朱丽叶。如果我们有一些哈姆雷特的书,那么我们就把它们放在另一个盒子里。罗密欧与朱丽叶的所有 10本书都是“相同”的产品(相同的封面、相同的内容、相同的参考文献)。

今天,我们想在同一个盒子里存储不同的莎士比亚书籍。或者也许是不同的爱情书。甚至是罗密欧与朱丽叶的书籍和小雕像?所以不同的产品在一起:我们应该改变box tableand Box class,不是吗?

标签: c#sql

解决方案


你有很多挑战;我将他们分成两个高级组。

首先,如何在代码级别更改应用程序,其次,如何将数据从旧模式迁移到新模式。

你如何改变你的代码?

第一个问题是:您能否 100% 确定您列出的类是访问和修改数据的唯一方式?是否有任何触发器、存储过程、批处理作业或其他应用程序?除了通过浏览数据库架构工件和代码库之外,我不知道有任何方法可以找到这一点。

在您“自己的”应用程序中,您可以选择。扩展通常比修改界面更好。实际上,这意味着您无需更改公共Product Product { get; set; }签名来处理字典,而是保留它并添加public Dictionary<Product, int> Content { get; set; }- 如果您可以保证旧方法仍然有效。这意味着有限地重写你的类的所有依赖项——你只需要担心需要了解一个盒子里可能有超过 1 个产品的客户。

这允许您遵循“很多小改动,但现有代码继续工作”的模型;您可以通过功能切换等来管理它。风险要低得多 - 所以这里的课程是“设计您的解决方案以对扩展开放,但对更改关闭”。

在这种情况下,这似乎是不可能的——“set”方法可能没问题(您可以将其默认为“一个产品在一个盒子里”的解决方案),但是“get”方法没有优雅的方式来处理一个盒子里有超过 1 个产品的情况。如果这是真的,您更改类,并查找您的代码无法编译的所有实例,并遵循依赖链。

例如,在典型的 MVC 框架中,在这种情况下,您将更改模型;这应该会导致控制器报告编译错误。在解决该错误时,您几乎肯定会修改控制器方法的签名。这反过来又会打破这种看法。所以你跟随那个链条;这样做意味着您的架构更改成为“大爆炸,全有或全无”版本。这通常会给所有相关人员带来压力......

你如何释放你的变化?

这在很大程度上取决于您选择了两个选项中的哪一个。@gburton 的回答涵盖了数据库步骤;这些在两个代码选项中都是必需的。

第二个挑战是发布软件的新版本;例如,如果它是桌面客户端,则必须确保所有客户端都在数据库更改的同时更新。这(通常)是可怕的。如果它是一个 Web 应用程序,它通常会更容易一些 - 需要担心的客户端机器更少。


推荐阅读