Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用存储库模式抽象出特定于数据库的id:s?_C#_Database_Domain Driven Design_Repository - Fatal编程技术网

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

C# 使用存储库模式抽象出特定于数据库的id:s?,c#,database,domain-driven-design,repository,C#,Database,Domain Driven Design,Repository,我正在学习DDD(域驱动设计)和存储库模式(C#)。我希望能够使用repository模式来持久化实体,而不关心实际使用的是哪个数据库(Oracle、MySQL、MongoDB、RavenDB等)。但是,我不确定如何处理数据库使用的特定于数据库的id:s most(all?)数据库。例如,RavenDB要求它应该存储的每个实体都有一个string类型的id属性。其他可能需要int类型的id属性。由于不同的数据库对其处理方式不同,因此我无法将数据库id作为实体类的一部分。但它必须存在于某个时刻,至

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


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

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

所以你可能会有

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

这并不理想,因为您的持久性逻辑会在业务逻辑上“出血”,但考虑到需求,它可能比在实体外部某处维护实体与其id之间的映射更容易、更健壮。我还强烈建议您评估“数据库不可知”方法,如果您只想支持关系数据库,这种方法会更现实。在这种情况下,您至少可以在存储库实现中重用类似NHibernate的ORM。大多数关系数据库支持相同的id类型。在您的场景中,您不仅需要ORM,还需要类似“对象文档映射器”的东西。我可以看出,您将不得不编写大量的基础架构代码。我强烈建议您重新评估您的需求,并在关系数据库和文档数据库之间进行选择。阅读此文:

这是泄漏抽象的典型案例。您不可能在存储库接口下抽象出数据库的类型,除非您想去掉每个数据库附带的所有优点。对ID类型(字符串、Guid或其他)的要求只是巨大冰山的最顶端,其大部分质量都在浑水下

考虑事务处理、并发性和其他方面。我理解你关于坚持和无知的观点。当然,在域模型中不依赖于特定的数据库技术是一件好事。但是您也无法摆脱对任何持久性技术的依赖

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

因此,我的建议是,对您必须处理的一组可能的持久性技术进行一些研究,然后为持久性子系统选择适当的抽象级别


如果这对您不起作用,请考虑活动来源。事件存储是要求最低的持久性技术之一。使用Jonathan Oliver之类的库将允许您使用几乎任何存储技术,包括文件系统。

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

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

  • 不要尝试转换类型,只需使用不同的字段

  • 特别是:除非在数据访问逻辑中,否则不要尝试使用数据库的主键。如果您需要一个对象的友好ID,只需创建一个额外的字段,可以是您喜欢的任何类型,并要求您的数据库存储该字段。只有在数据访问层中,您才需要根据对象的友好ID查找和更新DB记录。简单


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

    你真的需要它吗?对我来说似乎不是个好主意,因为你会遇到维护地狱。我也面临同样的问题。不幸的是,这里提到的所有解决方案都没有让我觉得是“完美的解决方案”(如果有的话…)。我还考虑在数据抽象层中强制转换到特定的实现类型。我的意思是,虽然
    DTO
    s和
    DAO
    s是所有数据库类型的通用接口,但任何特定的
    DAO
    实现都会将其方法中的
    DTO
    强制转换为相同的特定实现类型(我假设一次只使用一种数据库类型)。通过这种方式,它将能够使用特定的ID。它看起来很脏,但这是迄今为止我想到的最好的。我刚刚发现了另一个关于类似问题的问题,有一个答案似乎在这里也适用。看一看:不,这是相反的-一个避免泄漏抽象的经典案例。使用商店的ID类型作为对象的全局“友好”引用是有漏洞的。让商店坚持使用ID很好&通常是必要的。通常这两件事会很好地吻合。这家伙想把两者分开,所以他必须解决这个问题。@Chalky,我同意你的看法