【问题标题】:Repository pattern to query multiple databases用于查询多个数据库的存储库模式
【发布时间】:2012-06-13 10:55:23
【问题描述】:

这是一个非常奇怪的架构。请多多包涵。

我们有一个现有的分层应用程序(数据、逻辑/服务、客户端)。 最新的要求是服务层要访问两个数据源!!! (别无他法) 这两个数据源具有相同的数据库架构。

与大多数分层架构一样,我们有如下读写方法:

IEnumerable<Product> GetAllProducts(),
Product GetProductById(ProductKey id),
IEnumerable<Product> FindProductsByName(string name)

产品 DTO 是:

class Product
{
    public ProductKey Key { get; set;}
    ...
}

class ProductKey
{
    public long ID { get; }
}

我们将其缩小为两种可能的解决方案:

备选方案 1: 在读取方法中添加一个参数,以便服务知道要使用什么数据库,如下所示: 产品 GetProductById(ProductKey id, DataSource dataSource) DataSource 是一个枚举。

备选方案 2(我的解决方案): 将 DataSource 属性添加到键类。这将在检索对象时由实体框架设置。此外,这不会被持久化到数据库中。

class ProductKey
{
    public long ID { get; }
    public DataSource Source { get; } //enum
}

优点是更改对客户的影响很小。

但是,人们不喜欢这种解决方案,因为

  • DataSource 不会增加业务价值。 (我的回答是 ID 也不会增加商业价值。它是一个代理键。它的 目的是跟踪持久性)
  • 对象图中的子节点也将包含DataSource,这是多余的

哪种解决方案更合理?你还有其他选择吗?

注意:这些服务无处不在。

【问题讨论】:

  • 数据库架构是相同的,但 DTO 本身是否有任何信息可以提供有关要转到哪个数据源的线索?从客户端的角度来看,键或数据源会在什么时候设置?
  • 客户端将选择要搜索的数据源(例如:GetAllNewProducts([the datasource]))。然后,返回的产品可以在另一个视图中查看和(如果它来自数据源 A,则可编辑)。请注意,此视图将执行其他查询以获取与产品相关的项目(例如:GetRelatedProducts(ProductKey))。
  • 我扩展了 ObjectContext(或 DbContext)以在从查询创建对象时自动设置 DataSource。
  • DTO 只能转到一个数据源。另一个数据源是只读的。
  • 您可以全局切换连接字符串,而不是按对象选择数据源吗?还是他们可以根据产品或项目进行切换?

标签: c# entity-framework nhibernate architecture n-tier-architecture


【解决方案1】:

我建议的是 3 号门:

[||||||||||||||]
[|||||||||s!   ]
[||||nerics!   ]
[  Generics!   ]

我使用“动态存储库”(或者至少我是这么称呼它的)。它被设置为能够连接到任何数据上下文或数据库集,同时仍处于相同的 using 块中(即无需重新实例化)。

这是我如何使用它的 sn-p:

            using (var dr = new DynamicRepo())
            {
                dr.Add<House>(model.House);
                foreach (var rs in model.Rooms)
                {
                    rs.HouseId = model.House.HouseId;
                    dr.Add<Room>(rs);
                }
            }

这使用定义的“默认”dbcontext。每一个都必须在存储库中定义,但不能实例化。这是我使用的构造函数:

    public DynamicRepo(bool Main = true, bool Archive = false)
    {
        if (Main)
        {
            this.context = new MainDbContext();
        }
        if (Archive)
        {
            this.context = new ArchiveDbContext();
        }
    }

这是一个简化版本,其中只有两个上下文。可以实现更深入的选择方法来选择要使用的上下文。

然后,一旦初始化,这就是 Add 的工作方式:

    public void Add<T>(T te) where T : class
    {
        DbSet<T> dbSet = context.Set<T>();
        dbSet.Add(te);
        context.SaveChanges();
    }

这样做的一个很好的优势是只有一个地方来维护与数据库交互的代码。所有其他逻辑都可以抽象为不同的类。以这种方式使用通用存储库无疑为我节省了很多时间——即使我一开始花了一些时间修改它。

我希望我没有误解您要查找的内容,但如果您尝试为多个数据源创建一个存储库,我相信这是一种好方法。

【讨论】:

  • 问题不在于 DbContext。我们只是为此使用不同的连接字符串。我们当前的存储库接受“Product GetProductById(ProductKey key)”。如何修改以便存储库知道要访问哪个数据库?
  • @LostInComputer - 不修改 GetProductById 签名?
  • 这是我在问题中写的备选方案 1。见上文。
  • @LostInComputer - 我明白了,你可以做什么,虽然如果你已经在你的 ProductKey 类上使用继承,这可能不起作用,是使用 ProductKey 作为基类,然后使用MainProductKey 继承它。因此,class MainProductKey : ProductKey{} 将允许您在存储库中使用反射来确定数据库的来源,同时仍保留GetProductById 的签名。此外,AlternateProductKey : ProductKey{} 将允许使用不同的数据库连接。
  • 这也是个好建议。我将其标记为替代 3!
猜你喜欢
  • 2019-09-22
  • 2013-07-31
  • 2011-02-23
  • 2011-05-17
  • 1970-01-01
  • 1970-01-01
  • 2017-09-19
  • 2019-12-05
  • 2016-12-26
相关资源
最近更新 更多