2011-08-11 35 views
4

我正在学习DDD(域驱动设计)和存储库模式(在C#中)。我希望能够使用存储库模式来坚持一个实体,而不关心实际使用哪个数据库(Oracle,MySQL,MongoDB,RavenDB等)。但是,我不确定如何处理数据库特定的ID:大多数(所有?)数据库使用的数据库。例如,RavenDB要求它应该存储的每个实体都有一个字符串类型的id属性。其他可能需要一个int类型的id属性。由于这是由不同的数据库处理不同,我不能使数据库ID成为实体类的一部分。但是至少当我存储实际的实体时,它必须在某个时刻存在。我的问题是关于这方面的最佳做法是什么?使用存储库模式抽取数据库特定的id:s?

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

+1

你真的需要它吗?对于我来说这似乎不是个好主意,因为你会遇到维护地狱。 – xelibrion

+0

我同意xelibrion在这里。 – NotMe

+0

我正面临同样的问题。不幸的是,这里提到的解决方案中没有一个将我描述为“完美的解决方案”(如果有的话......)。我也考虑过转换为数据抽象层中的特定实现类型。我的意思是,虽然'DTO'和'DAO'是所有DB类型通用的接口,但任何特定的'DAO'实现都会将方法内的'DTO'转换为相同的特定实现类型假设一次只使用一种数据库类型)。这样,它将能够使用特定的ID。这看起来很肮脏,但这是我迄今为止最好的。 – eitanfar

回答

0

您可能在实体中拥有该ID,但不会将其作为实体公共接口的一部分公开。这对NHibernate来说是可能的,因为它允许你将表格列映射到一个专用字段。

所以,你都可能有类似

class Customer { 
     private readonly Int32? _relationalId; 
     private readonly String? _documentId; 
     ... 

这不是理想的,因为你的持久逻辑“流血”的业务逻辑,但给出的要求很可能是比实体之间保持映射更简单,更健壮的实体之外的某处。我还强烈建议您评估“数据库不可知”方法,如果您只想支持关系数据库,那么这种方法更为实际。在这种情况下,您至少可以重复使用像NHibernate这样的ORM来存储库实现。而大多数关系数据库都支持相同的id类型。在你的场景中,你不仅需要ORM,还需要诸如“Object-Document-Mapper”之类的东西。我可以看到你将不得不编写大量的基础设施代码。我强烈建议您重新评估您的要求,并在关系数据库和文档数据库之间进行选择。阅读原文:Pros/cons of document-based databases vs. relational databases

3

这是泄漏抽象的经典案例。除非你想放弃每个数据库带来的所有好处,否则你不可能在存储库接口下抽象出数据库的类型。关于身份证类型(字符串,Guid或其他)的要求只是在浑水中拥有大部分质量的巨大冰山的顶部。

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

让你的领域模型适用于任何RDBMS是相对容易的。他们大多数都有标准化的数据类型。使用像NHibernate这样的ORM将会帮助你很多。在NoSQL数据库中实现这一点很难,因为它们往往有很大差异(实际上这非常好)。

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

如果这不适合您,请考虑事件采购。事件存储是最不苛刻的持久性技术之一。使用Jonathan Oliver的等库可以让您几乎使用任何存储技术,包括文件系统。

+2

不,这是相反的 - 避免泄漏抽象的经典案例。使用商店的ID类型作为对对象的全局“友好”参考是有漏洞的。让商店坚持认为ID是好的,通常是必要的。通常情况下,这两件事情是一致的。本章试图将两者分开,因此他必须解决这个问题。 – Chalky

+0

@Chalky我同意你的观点,当涉及到主要的API提供者(比如数据库)时,(几乎总是)没有太多的抽象。如果您非常依赖数据库类型,以至于您在代码中的任何地方都使用特定的ID类型,那么您将无法将数据库更改为...以及几乎永远不会!一旦数据库充满数据,公司不愿意替换他们正在使用的数据库,这在很大程度上也是因为大部分时间,这也意味着提供了一个全新的软件实现,这是由于假设一个特定的ID类型。 – eitanfar

1

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

1
  1. 你正在做正确的事情!将自己从数据库主键类型的约束中抽象出来!

  2. 不要尝试翻译类型,只是使用不同的字段。

特别是:不要尝试使用数据库的主键,除了在您的数据访问逻辑。如果你需要一个友好的对象ID,只需创建一个你喜欢的任何类型的附加字段,并且需要你的数据库来存储它。只有在你的数据访问层,你需要找到&根据你的对象的友好ID更新数据库记录。简单。

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

+0

我在问题中也遇到同样的问题。你的建议是我想到的第一件事。唯一让我感到困惑的是,它可能会在数据库中的任何对象中创建两个不同的ID类型字段。 – eitanfar