使用存储库模式抽象出数据库特定的id:s?

时间:2011-08-11 16:14:53

标签: c# database domain-driven-design repository

我正在学习DDD(域驱动设计)和存储库模式(在C#中)。我希望能够使用存储库模式来持久化实体,而不关心实际使用哪个数据库(Oracle,MySQL,MongoDB,RavenDB等)。但是,我不知道如何处理数据库特定的id:s大多数(所有?)数据库使用。例如,RavenDB要求它应存储的每个实体都具有string类型的id属性。其他可能需要int类型的id属性。由于不同的数据库对此进行了不同的处理,因此我无法将数据库ID作为实体类的一部分。但它必须存在于某个时刻,至少在我存储实际实体时。我的问题是关于这个问题的最佳做法是什么?

我目前追求的想法是,对于我想支持的每个数据库,为每个业务对象类型实现特定于数据库的“值对象”。这些值对象将具有数据库特定的id属性,并且我将在读取和写入时在两者之间进行映射。这看起来是个好主意吗?

4 个答案:

答案 0 :(得分:3)

这是泄漏抽象的经典案例。您不可能在存储库接口下抽象出数据库的类型,除非您想要丢失每个数据库附带的所有好东西。 ID类型(字符串,Guid或其他)的要求只是巨大冰山的最高峰,其大部分质量都在泥泞的水域之下。

考虑事务处理,并发性和其他东西。我理解你对持久性无知的看法。确保不依赖于域模型中的特定数据库技术是一件好事。但是你也无法摆脱对任何持久性技术的依赖。

使用任何RDBMS使您的域模型运行良好相对容易。其中大多数都有标准化的数据类型。使用像NHibernate这样的ORM会对你有很大的帮助。在NoSQL数据库中实现相同的功能要困难得多,因为它们往往差别很大(实际上非​​常好)。

所以我的建议是对你将要处理的可能的持久性技术集合进行一些研究,然后为持久性子系统选择适当的抽象级别。

如果这对您不起作用,请考虑事件采购。事件存储是最不需要的持久性技术之一。使用Jonathan Oliver的EventStore等库可以使用几乎任何存储技术,包括文件系统。

答案 1 :(得分:1)

我会继续在实体中创建一个int Id字段,然后将其转换为存储库中的字符串,其中Id必须是字符串。我认为抽象持久性的努力非常值得,而且实际上可以简化维护。

答案 2 :(得分:1)

  1. 你正在做正确的事情!摘要自己远离数据库主键类型的约束!

  2. 不要尝试翻译类型,只需使用其他字段。

  3. 具体来说:除数据访问逻辑外,不要尝试使用数据库的主键。如果您需要对象的友好ID,只需创建一个您喜欢的任何类型的附加字段,并要求您的数据库存储它。只有在您的数据访问层中才需要找到&根据对象的友好ID更新DB记录。容易。

    然后,您对哪些数据库可以持久保存对象的约束已从“必须能够拥有xxxx类型的主键”更改为“必须能够存储类型xxxx”。我想你会发现你在世界上使用任何数据库。快乐的编码! DDD是最棒的!

答案 3 :(得分:0)

您可以在实体中拥有ID,但不能将其作为实体公共接口的一部分公开。 NHibernate可以实现这一点,因为它允许您将表列映射到私有字段。

所以你可能会有像

这样的东西
class Customer {
        private readonly Int32? _relationalId;
        private readonly String? _documentId;
        ...

这并不理想,因为您的持久性逻辑会“渗透”业务逻辑,但考虑到需求,它可能比在实体外部维护实体及其ID之间的映射更容易,更健壮。我还强烈建议您评估“数据库不可知”方法,如果您只想支持关系数据库,这将更加现实。在这种情况下,您至少可以重用像NHibernate这样的ORM来实现存储库。并且大多数关系数据库支持相同的id类型。在您的场景中,您不仅需要ORM,还需要“Object-Document-Mapper”之类的东西。我可以看到你必须编写大量的基础设施代码。我强烈建议您重新评估您的要求,并在关系数据库和文档数据库之间进行选择。阅读:Pros/cons of document-based databases vs. relational databases