使用 SOA、UoW、Repository、DataContext 和 DataContext 设计多租户应用程序多个数据库

发布于 2024-10-05 16:08:35 字数 1995 浏览 8 评论 0原文

首先,我对这篇文章的篇幅表示歉意,但我想提供尽可能多的细节,以增加得到答案的机会。提前致谢。

我正在向集成来自多个数据库的数据的现有应用程序添加新功能。简而言之,它允许客户和/或其会计师访问和更新有关其位置的财务信息。该应用程序有 3 层,其中包括 Web 客户端(我希望很快将其替换为 Silverlight 客户端)、在应用程序服务器上运行的服务层和数据库层。

当我获得所有权时,该应用程序尽管有 3 层,但非常简单。它使用 ADO.NET 来处理所有事情,并且 Web 服务只是对其中一个数据库进行动态(字符串)SQL 查询的传递。我的第一个任务是“清理”现有代码。该应用程序没有任何面向对象的内容,一切都是扁平的。我已经开始重构应用程序以利用 LINQ-to-SQL,实现存储库模式以使业务逻辑可测试(更不用说随着我们将数据访问技术从 ADO.NET 发展到 L2S,并希望进一步发展到更易于维护) Entity Framework)并重新编写代码以实际使用 .NET 的功能。

在大多数情况下,Web 应用程序是小菜一碟,因为每个页面都是对数据库中的表或视图的简单查询(通过 Web 服务)。在应用程序服务器端,我最终为每个数据库提供了一个 DataContext,为每个实体提供了一个存储库(或使用 DDD 术语的聚合根)。我使用构造函数注入(Castle Windsor)为我的服务类以及存储库使用的 DataContext 设置正确的存储库实例。

这一切都很好,只是现在我必须将编辑功能添加到需要跨越 4 个数据库的逻辑的应用程序中,并且我不知道正确的方法。应用程序的流程和架构必须一致且可由初级开发人员维护,这一点至关重要。 (除了我之外,团队基本上都是 VB6 开发人员,他们认为自己正在编程 .NET,因为他们使用 VS 和 BCL – 他们对模式、实践、单元测试、模拟等知之甚少)

让我演练使编辑视图正常工作所需的内容:

  1. 首次加载页面时,我会生成“可编辑”会计期间的列表。
    1. 此列表基于 SQL Server 数据库(称为“元数据”数据库)中包含的一组规则。表中的每一行都按名称标识会计期间以及可以编辑的时间范围。
    2. 这些规则用于查询 DB2 财务数据库中的表,该数据库将期间名称和年份映射到实际日期。此查询将返回结束日期在过去且结束日期(结束日期加上上面的编辑长度)在今天之后的所有条目。
  2. 该页面将默认选择的时间段为最近的时间段。选择一个时间段后,我会触发另一个请求来填充当前用户在所选时间段内可以编辑的位置列表。
    1. 首先,我必须从“安全”数据库中查询用户的安全信息,并确定他们是否属于会计师角色。如果是这样,那么我必须查询元数据数据库以检索当前用户的客户端列表。如果没有,那么我使用当前用户的 clientID。
    2. 接下来,我查询 DB2 财务数据库以获取位置列表,并根据选定的时间段和用户可以访问的 clientID 列表进行过滤。我还根据状态进行过滤,因此只返回该期间处于活动状态的位置。
  3. 与句点一样,页面会将所选位置默认为列表中的第一个位置。选择位置后,我会再次请求该位置在选定时间段内的实际财务数据。
    1. 此请求是向“Staging”数据库发出的,非常简单。
  4. 如果用户选择不同的时间段或地点,所有这些都会重复。

因此,让我们以#2 为例,演练一下我应该如何使用工作单元和存储库模式在我的服务应用程序中实现这一点,并且……哦,有一个问题 – 没有 LINQ-to-DB2,而且公司不会提供跳转到 EF,所以我在使用该数据库时只能使用 ADO.NET。但不要让这阻碍你,因为我想要一个尽可能与数据访问技术无关的解决方案,因为他们随时可能改变主意。事实上,就我目前所知,他们可以改变范式并转向 NHibernate。我更关心从服务外观到 DataContext,而不是如何实现 DataContext(或 ObjectContext)。

您能否引导我完成使用当前用户的凭据和选定的会计期间调用我的 Web 服务方法、执行上面 #2 中概述的步骤并返回适当的位置列表的实施过程?

哇……有很多需要考虑的内容。我很感谢您帮助解决这个问题。

Let me start by apologizing for the length of this post but I wanted to provide as much detail as possible to increase the chance of an answer. Thanks in advance.

I’m adding new features to an existing application that integrates data from several databases. In short, it allows clients and/or their accountants to access and update financial information about their locations. The application has 3 tiers with a web client (I’m looking to replace this will a Silverlight client very soon), a service layer running on an app server and the database tier.

When I took ownership, the application, despite having 3-tiers, was very simplistic. It is using ADO.NET for everything and the web service is simply a pass-through for dynamic (string) SQL queries on one of the databases. My first task was to “clean-up” the existing code. There was nothing object-oriented about the app and everything was flat. I’ve begun refactoring the application to leverage LINQ-to-SQL, implemented the Repository pattern to make the business logic testable (not to mention more maintainable as we evolve the data access technology from ADO.NET to L2S and, hopefully, on to Entity Framework) and reworked the code to actually use the features of .NET.

For the most part, the web app is a piece of cake as every page is a simple query on a table or view in the database (via the web service). On the app server side, I ended up with a DataContext for each database and a Repository for each entity (or Aggregate Root using DDD terms). I use constructor injection (Castle Windsor) to set the proper repository instance for my service class and likewise for the DataContext used by the repository.

This is all well and good except now I have to add edit capability into the application that requires logic spanning 4 databases and I’m at a loss for the right approach. It is critical that the flow and architecture of the app is consistent and maintainable by junior-grade developers. (Aside from me, the team is basically VB6 devs who think they are programming .NET because they are using VS and the BCL – they know very little about patterns, practices, unit testing, mocking, etc, etc, etc) 

Let me walk through what is needed to make the edit view work:


  1. When the page is first loaded, I generate a list of “editable” fiscal periods.

    1. This list is based on a set of rules contained in a SQL Server database (call it the “Metadata” db). Each row in the table identifies the fiscal period by name along with the timeframe it may be edited.

    2. These rules are used to query a table in the DB2 financial database that maps the period name and year to the actual dates. This query will return all entries with an end date in the past and a close date (end date plus edit length from above) after today.
  2. The page will default the selected period to the most recent. When a period is selected, I fire another request to populate a list of locations that the current user may edit during the selected period.

    1. First I have to interrogate the user’s security information from the “Security” database and determine if they are in the Accountants role. If so, then I have to query the Metadata database to retrieve a list of clients for the current user. If not, then I use the clientID of the current user.
    2. Next I query the DB2 financial database to obtain the list of locations, filtering based on the selected period and list of clientIDs that the user may access. I also filter based on the status so I only return locations that were active during that period.
  3. As with the period, the page will default the selected location to the first one in the list. When the location is selected, I make another request for the actual financial data for that location during the selected period.

    1. This request is made to the “Staging” database and is pretty straight-forward.
  4. All of this repeats if the user selects a different period or location.

So, let’s take #2 and walk through how I should be implementing this in my service application using the Unit Of Work and Repository patterns and… Oh, one problem – there is no LINQ-to-DB2 and the company won’t make the jump to EF yet so I am left with using ADO.NET when working with that database. But don’t let that hold you up as I’d like a solution that is as data access tech-agnostic as possible because they could change their minds any day. In fact, they could shift paradigms and go to NHibernate for all I know at this point. I’m more concerned with getting from the service façade to the DataContext and not so much about how the DataContext (or ObjectContext) is implemented.

Can you walk me through the implementation of calling my web service method with the current user’s credentials and selected fiscal period, performing the steps outlined in #2 above and returning the appropriate list of locations?

Whew… That was a lot to take in. I appreciate the help sorting it out.

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

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

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文