数据库结构略有不同的多客户项目的架构设计(针对每个客户)

发布于 2024-10-22 04:09:03 字数 598 浏览 1 评论 0原文

我正在维护一个为每个新客户复制粘贴的应用程序(...是的,我知道)。如果一个新客户想要一些其他人不需要的新功能,则只需更改他的代码部分即可。该解决方案还包括一种“common.dll”,其中放置的所有代码对于所有客户都是相同的。

每个客户的底层 MSSQL 数据库略有不同。所有表都或多或少具有相同的表,但有些客户具有用于自定义特定功能的附加列或新表等。

由于每个客户的 Visual Studio 解决方案中都使用“类型化数据集”(ADO.NET C# 2.0),因此始终有一个特定的解决方案(文件)以及其中的特定类型数据集(例如“XyDataSet.xsd”)。在解决方案中,我有辅助类,例如。用于处理订单。此类中的方法之一可以是“GetOrder(string orderId)”,它使用客户特定的数据集来检索订单(如键入的 DataRow)。

正如您所看到的,我在每个客户的每个解决方案中都有“GetOrder”方法,因为订单表中可能会有一些差异,例如可能有附加列。因此,如果需要对一般的“GetOrder”功能进行更改,我必须在所有项目中更改它,这当然是维护的噩梦。

你们中有人看到可以改进这种“架构”的方法吗?或者也许当前底层的不同数据库方案在更高的应用程序级别上没有太多需要改进的地方?

I'm maintaining an application that was copy-pasted for each new customer (...yeah, I know). If a new customer wanted some new functions which the others didn't need, only his code part was changed. The Solution also includes a sort of "common.dll" where all code is put that is the same for all customers.

The underlying MSSQL database for each customer is slightly different. All have more or less the same tables but some customers have for example additional columns or new tables for the custom specific functions.

As "typed datasets" (ADO.NET C# 2.0) are used in the Visual Studio solution for each customer there is always a specific solution (file) and in it a specific typed dataset (eg. "XyDataSet.xsd"). In the solutions I have helper classes eg. for handling orders. One of the methods in this class could be "GetOrder(string orderId)" which uses the customer specific DataSet to retrive an order (as typed DataRow).

As you see I have "GetOrder" methods in each solution for each customer as there might be little differences in the order table like maybe additional columns. So if a change is needed to the general "GetOrder" functionality I have to change it in all projects which is of course a maintenance nightmare.

Do anybody of you see a way in which this "architecture" could be improved? Or maybe with the currently underlying different DB schemes there isn't much to improve in the higher application level?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

杀手六號 2024-10-29 04:09:03

完全回答这个问题非常困难,但我会开始这样思考:

数据库级别:

  • 找到常见的内容并将其作为数据库模式。
  • 找到什么是加法,并将其放在单独的表中,指示该表中哪个(来自公共模式)是该行及其相应值的所有者。例如

    订单 {OrderID、CustomerID 等}(这是所有者表)
    OrderExtensions {ExtensionID, ExtensionName, ExtensionValue}(这是订单的扩展表)
    OrderExtensionsToCustomers {CustomerID, ExtensionID}(这显示哪个扩展可用于哪个客户)

数据访问层级别:

  • 应在此处实现数据库级别设计。

领域模型层级别:

  • 一些具有功能的操作(针对 UI 层)应移至此处。

UI层级别:

  • 从这里应该将一些东西移动到数据库层,例如仅针对某些客户出现的UI元素,将它们视为仅针对特定客户激活的“功能”(扩展),因此它们仅对他们可见。
  • 就我个人而言,我会进一步抽象“功能”术语,使其可动态加载。如果您习惯使用反射,那么这是可以轻松实现的。如果可以实现这一点,那么它将赋予您在域层中拥有少量代码的特权 - 并非所有客户的所有代码都放在一起,而是在需要时根据特定客户的请求动态加载。

最终图:

  • 客户访问UI界面,其实就是具体的页面。
  • 查询数据库以获取当前客户可用的 UI 功能(例如附加按钮等)。
  • 数据库为客户返回每个功能的定义。
  • 每个功能都会动态加载并添加到页面(例如功能的特殊占位符)。
  • 当功能需要执行时,它将请求传递到域层,域层又加载该功能的“处理器”部分,也可能是动态加载,或者只是查找功能需要调用的实现。
  • 呼叫被路由到数据库,公共信息被保存到公共(所有者)表,而附加(分机)信息被保存到其他(分机)表。

我知道这是一个很长的答案,但我希望这是有道理的:-)

It is very difficult to answer this question completely, but I would start thinking this way:

Database level:

  • Find what is common and have that as a database schema.
  • Find what is addition and have that in separate tables, indicating in that table which (from common schema) is the owner of the row and its corresponding value. e.g.

    Orders {OrderID, CustomerID, etc.} (this is owner table)
    OrderExtensions {ExtensionID, ExtensionName, ExtensionValue} (this is extension table for Orders)
    OrderExtensionsToCustomers {CustomerID, ExtensionID} (this shows which extension is available for which customer)

Data-access-layer level:

  • Database level design should be implemented here.

Domain-model layer level:

  • Some manipulations with features (for UI layer) should move to here.

UI layer level:

  • From here something should be moved to database layer, e.g. UI elements which appear only for some customers, think of them as a "feature" (extension) activated for specific customers only, so they are visible only for them.
  • Personally I would go farther by abstracting the "feature" term, making it loadable dynamically. This is achievable easily if you are comfortable with using reflection. If this can be achieved, then it will give you the privilege of having a little code in domain layer - not all the code for all customers put together, but loaded dynamically for specific customer upon request when needed.

Final picture:

  • Customer accesses the UI interface, in fact the specific page.
  • Database queried for UI features available for the current customer (e.g. additional buttons, etc.).
  • Database returns definitions of each feature for the customer.
  • Each feature is loaded dynamically and added to the page (e.g. to the special placeholders for features).
  • When feature needs to act, it passes the request to the domain layer, which in turn loads the "processor" part for the feature, maybe also dynamically, or just finds the implementation which feature needs to call.
  • Call is routed to the database and the common information gets saved to common (owner) tables, while additional (extension) information is saved to other (extension) tables.

I know it is a long answer, but I hope this makes sense :-)

就此别过 2024-10-29 04:09:03

使用一种返回非类型化数据集的通用方法(在共享程序集中或在服务中)怎么样?然后,您可以在每个解决方案中使用方法,将该方法返回的数据放入类型化数据集中。这样您就可以将与数据库交互的逻辑保留在一个地方。

What about using one common method (in a shared assembly or in a service) that is returning untyped dataset? Then you can have methods in each solution that puts the data returned from this method into typed datasets. That way you can keep the logic for interacting with the database in one place.

月寒剑心 2024-10-29 04:09:03

首先,哎哟。艰难的演出。

您可以做很多事情来迁移到更好的架构 - 这有点取决于您可以花多少时间在上面。我建议阅读 Kerievsky 的“重构模式”以获取想法。

为了回答您的具体问题 - 我会考虑“模板方法”模式。一般来说,您将 getOrder 定义为一系列步骤,并允许子类根据需要覆盖这些步骤。
http://www.dofactory.com/Patterns/PatternTemplate.aspx

我同意 Ole您需要做的事情之一就是整理返回类型 - 这将使重构时变得更加容易。

如果您还没有这样做,我还建议您投资单元测试。

Firstly, ouch. Tough gig.

There are lots of things you could do to move to a better architecture - it kinda depends on how much time you are allowed to spend on it. I'd suggest reading "Refactoring to Patterns" by Kerievsky for ideas.

To answer your specific question - I'd consider the "template method" pattern. Broadly speaking, you define getOrder as a series of steps, and allow subclasses to override those steps as required.
http://www.dofactory.com/Patterns/PatternTemplate.aspx

I agree with Ole that one of the things you will need to do is sort out the return types - that will make life a lot easier when it comes to refactoring.

I'd also suggest investing in unit tests if you haven't already done so.

愁以何悠 2024-10-29 04:09:03

创建一个类型化数据集,其中包含表的所有公共列,但不包含专用列。在每个表的相应 xsd 文件中添加一个

  <xs:anyAttribute />

这将允许将未在 xsd 数据集中定义的列加载到数据表中。

可以通过类型化数据集访问公共列,可以通过其名称访问客户特定列,或者您可以创建
自定义特定的扩展方法来获取附加列。

我不确定 vs2008/vs2010 数据集编辑器是否可以处理这个问题,甚至破坏 anyAttribute 信息。但 dotnet xsd.exe 代码生成器支持 anyAttribute 自 dotnet 1.0 以来,包括当前的 dotnet 4.0

Create a typed dataset that contains all common colums of the tables but not the specialised ones. In the corresponding xsd-file for each table addd a

  <xs:anyAttribute />

This will allow to load columns into a datatable that are not defined in the xsd-dataset.

The common colums can be accessed via the typed dataset, the customer specific colums can be accessed through their name or you can create
custom specific extension-methods to get the additional colums.

I am not shure if vs2008/vs2010 dataset-editor can handle this or even destroys the anyAttribute information. But the dotnet xsd.exe codegenerator supports anyAttribute since dotnet 1.0 including current dotnet 4.0

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文