具有两个数据库的单类
Posted
技术标签:
【中文标题】具有两个数据库的单类【英文标题】:Single class with two databases 【发布时间】:2011-05-24 21:35:26 【问题描述】:我有一个两部分的应用程序。一部分是一个 Web 应用程序 (C# 4.0),它在具有托管 MSSQL 数据库的托管计算机上运行。这很好,也很标准。另一部分是在我们的网络上本地运行并访问我们的主数据库(Advantage)和 Web 数据库的 Windows 应用程序。该网站无法访问 Advantage 数据库。
目前此设置运行良好(前提是网络正常),但我们现在正在重建网站并将其从 Web Forms /.NET 2.0 / VB 站点升级到 MVC3 / .NET 4.0 /C# 站点。作为重建的一部分,我们将添加许多新表,其中内部数据库包含所有数据,而 Web 数据库包含其中的一个子集。
在内部应用程序中,数据库中的表由类表示,这些类使用反射和属性标志来填充自己。例如:
[AdvantageTable("warranty")]
public class Warranty : AdvantageTable
[Advantage("id", IsKey = true)]
public int programID;
[Advantage("w_cost")]
public decimal cost;
[Advantage("w_price")]
public decimal price;
public Warranty(int id)
this.programID = id;
Initialize();
AdvantageTable 类的 Initialize() 方法使用反射基于所有键及其值构建查询,然后根据指定的数据库列填充每个字段。更新的工作方式类似——我们在任何对象上调用 AdvantageTable.Update(),它处理所有数据库写入。它工作得很好,隐藏了所有标准的 CRUD,并让我们在添加新表时快速创建新类。我们宁愿不改变它,但如果有需要它的解决方案,我不会完全排除它。
网络数据库需要有这个表,但不需要成本数据。我可以创建一个由 Web 数据库支持的单独类(通过存储过程、反射、LINQ-TO-SQL、ADO 数据对象等),但保修对象中可能还有其他功能,我希望以相同的方式运行无论是从网站调用还是从内部应用调用,都不需要维护两套代码。例如,我们可能会更改决定产品适用于何种保修的逻辑 - 我希望只需要在一个地方而不是两个地方创建和测试它。
所以我的问题是:谁能想到一个好方法,让这个类有时从 Advantage 数据库中填充,有时从 Web 数据库中填充? 这不仅仅是连接字符串的问题,因为他们有两种非常不同的访问方法(甚至除了反射)。我考虑将[Web("id")]
类型标签添加到Advantage标签中,并且只将它们放在Web数据库中存在的字段上以指定其列,然后使用某种开关来控制用于读取/写入的逻辑集,但我觉得那会很痛苦(这种方法对网络安全吗?如何在实例化之前设置标志?)。所以我没有我喜欢的想法,并怀疑有一个我什至不知道存在的解决方案。有什么意见吗?
【问题讨论】:
【参考方案1】:我认为根本问题是您希望将业务逻辑放在 Warranty 对象中,这是一个数据层对象。您真正想要做的是拥有一个两个数据源都支持的通用数据契约(在这种情况下可能是一个接口),其逻辑封装在一个单独的类/层中,可以与任一数据源一起操作。通过建立您的业务层可以使用的通用数据契约,无论数据是如何提取的,这都避免了让单个数据类尝试使用两个不同的数据源进行操作的问题。
因此,在您的示例中,您可能有 AdvantageWarranty 和 WebWarranty,两者都实现了 IWarranty。您有一个单独的 WarrantyValidator 类,它可以对任何 IWarranty 进行操作,以告诉您保修在给定条件下是否仍然有效。顺便说一句,如果您想在 WarrantyValidator 类中对业务逻辑进行单元测试,这为您提供了一种很好的方法来存根数据。
【讨论】:
所以 IWarranty 会有 programID 和 price,AdvantageWarranty 会添加成本字段,而 WebWarranty 不会,我会根据该部分代码创建一个或另一个?或者成本会成为 IWarranty 的一部分,而只是在 WebWarranty 中未填充?我该如何处理涉及成本字段的业务逻辑 - 会在 WarrantyValidator 还是 AdvantageWarranty 上进行? @Bobson,我没有注意到您的数据不是两个来源之间的一对一映射。在这种情况下,事情变得更加复杂,因为现在您的业务逻辑分为仅适用于 Advantage 的、仅适用于 Web 的(可能)以及适用于两者的。我仍然认为将它放在数据层对象本身是一个坏主意,但除此之外,在这种情况下还有很多设计权衡;我没有足够的上下文来推荐一个而不是另一个。【参考方案2】:我最终想出的解决方案有两个。首先,我使用 Linq-to-sql 为每个 web 表生成对象。然后,我从 AdvantageTable 派生了一个名为 AdvantageWebTable<TABLEOBJECT>
的新类,其中包含特定于 Web 的代码,并添加了特定于 Web 的属性。所以现在这个类看起来像这样:
[AdvantageTable("保修")]
public class Warranty : AdvantageWebTable<WebObjs.Warranty>
[Advantage("id", IsKey = true)][Web("ID", IsKey = true)]
public int programID;
[Advantage("w_cost")][Web("Cost")]
public decimal cost;
[Advantage("w_price")][Web("Price")]
public decimal price;
public Warranty(int id)
this.programID = id;
Initialize();
还有用于在保存到 Web 数据库之前填充纯 Web 字段的钩子,并且会有(但还没有,因为我不需要它)LoadFromWeb()
函数使用反射来填充字段.
【讨论】:
以上是关于具有两个数据库的单类的主要内容,如果未能解决你的问题,请参考以下文章