究竟啥是“执着无知”?

Posted

技术标签:

【中文标题】究竟啥是“执着无知”?【英文标题】:What exactly is "persistence ignorance"?究竟什么是“执着无知”? 【发布时间】:2010-12-30 18:59:16 【问题描述】:

持久性无知通常被定义为持久化和检索标准 .NET 对象(或 POCO,如果您真的坚持给它们命名)的能力。 seemingly well accepted definition of a standard .NET object 是:

“...普通课程,您可以专注于手头的业务问题,而不会出于与基础架构相关的原因添加内容...”

然而,我看到人们将 NHibernate 描述为一个允许忽略持久性的框架,但它是一个不能在任何标准 .NET 对象上工作的框架,只能在符合特定要求的标准 .NET 对象上工作。设计要求,例如(source):

所有类必须有一个默认构造函数 除非类未密封且所有成员都是虚拟的,否则某些功能将无法使用 除非您滥用 Equals/GetHashCode,否则对象标识无法正常工作

(旁白:在任何人不高兴之前,我并不是要在这里选择 NHibernate,它只是一个经常被引用的框架示例,据说它允许持久性无知。我相信类似的论点可以应用于其他声称相同的 ORM。)

虽然该类本身没有任何持久性框架特定的属性或基类等,但对我来说它并不是真正的“持久性无知”,因为它必须遵循一套设计指南促进 由所选的持久性框架使用。您必须考虑到持久性框架的要求来设计和实现该类;如果您对它一无所知,则该类可能无法使用它。

我对“持久性无知”/“POCO”的定义有疑问,我不明白从概念上讲,这与添加 [Serializable][DataContract][XmlType] 或任何其他持久性框架特定的注释,促进使用该框架的实体的持久性和检索。

那么,究竟什么是“执着无知”?

很明显,将其定义为能够持久化“普通类”是一个谬误,因为 NHibernate 仅在不引用特定于框架的类方面是普通的,而它们是非凡的,因为它们需要不寻常的设计选择,例如默认构造函数和全虚拟成员以及可变类型上的 Equals/GetHashCode 实现。

因此,当对象促进持久性框架的使用(在设计和结构中或通过使用特定于框架的注释)但本身不执行任何持久性逻辑时,是否可以合理地说“不了解持久性”是真的?

【问题讨论】:

不要与“持久的无知”相混淆——它描述了我认识的一些人;) 没有equals/gethashcode的对象标识应该如何工作?你能举个伪代码的例子吗? 有没有人真的认为 NHibernate(或任何其他 ORM)是 100% 的 PI 解决方案?这个问题的(有趣)核心实际上是“哪个 PI 妥协最能干扰领域模型开发?” @Jeff - 这是一个更有趣的问题 - 你可能应该问它;-)。例如,我可能会争辩说,向域类添加属性比纯粹为了让 ORM 快乐而添加类对 PI 的妥协要小(我不得不与 FNH 做这件事)。 Aee 也:***.com/questions/905498/… 【参考方案1】:

我会声称,就像大多数事情一样,它是一个滑动比例。我们制作的某些东西想要具有持久性。一方面,这个东西具有所有的胆量、依赖关系和代码,这些都是定制的,可以以特定的方式持续存在这个东西。在规模的另一端是神奇地发生的事情,所有这些都不需要我们做更多的事情,而不仅仅是添加一个令牌或在某处设置一个属性,从而导致该事情“持续存在”。为了达到规模神奇的一面,有一些框架、设计指南、约定等来帮助神奇的发生。我认为您可能会争辩说,可以生产一种比 NHibernate 具有更少要求和限制但追求相同目标的工具;这个假设的工具将在我们的规模上更进一步。

我不知道我这么喜欢“坚持无知”这个词;它实际上是关于一个对象不知道实现,后备存储,缓存,诸如此类的事情 - 但是,一个对象通常知道它是否是持久的。但这只是语义。

【讨论】:

【参考方案2】:

我不认为您对“坚持不懈”的理解(或定义)是错误的。

真正的问题是leaky abstractions 的问题。很简单,现有技术使得实施真正的 PI 变得非常困难。

【讨论】:

【参考方案3】:

持久无知类是不依赖于持久性框架的类。

也就是说,该类完全不知道存在持久性框架,它不从该框架定义的类继承,也不实现该持久性框架工作所需的接口。

【讨论】:

@Frederik - 所以按照这个定义,你是说 NHibernate 不支持持久性无知?好像这个类不需要一个默认的构造函数来正常使用,它仍然必须有一个纯粹是因为了解持久性框架的要求? 嗯,NHib 还要求将属性等声明为虚拟。但我不会说这真的会影响无知,因为要求非常小,根本不会影响您的设计。 @Greg:不,我不是这么说的。我的意思是,如果您的班级不需要对该持久性框架进行“引用”,那么持久性无知就是。事实上,您需要一个默认构造函数(可以是私有的)这一事实是一个小故障,但这并不意味着它不是无知的持久性。 @Sosh:错了。 NH 不要求将属性声明为虚拟的。我每天都使用 NH,我讨厌如果语义不需要虚拟属性,我需要虚拟属性,因此,我只在必要时创建虚拟属性。当您指定 NH 不应使用动态代理时,您不需要虚拟道具。 @Frederik - 如果一个类没有对特定持久性框架的“引用”,我会说你认为一个类是持久性无知的,即使它具有重大的设计更改需要使用特定的框架(例如,强制默认构造函数、延迟加载的虚拟成员、用于身份相等的颠覆 Equals/GetHashCode)?如果另一个框架需要 Equals/GetHashCode 的不同用法(例如,对于所有成员相等),那么您的对象无法使用它,因为它是为 NHibernate 编写的;那还是坚持无知吗?【参考方案4】:

我同意 Mikeb 的观点 - “持久性无知”是一个滑动比例,而不是给定 ORM 的真/假属性。

我对真正 100% PI 的定义是,您可以坚持任何可能的 POCO 类,无论其与其他类有多么复杂和链接,而无需以任何方式更改该类。

添加 ID 字段、用属性装饰、从 ORM 类继承、必须设计您的类以便它们很好地映射到 RDB 中的基础表 - 所有这些都会将“PI 分数”降低到 100% 以下。

也就是说,我选择使用 Fluent NHibernate Automapping,因为它似乎在我看过的所有 ORM 选项中具有最高的 PI 分数。

【讨论】:

+1 同意 - 没有 100% 的 PI 解决方案,因此您需要问自己 Jeremy Miller 在他的文章(问题中引用)中提出的问题:“业务逻辑能否独立运行数据库?”、“我可以独立于数据库模型设计我的领域模型吗?”和“我的持久性策略如何影响我的业务逻辑?”【参考方案5】:

我同意你的定义:

因此这样说是否合理 “执着无知”是真的 对象便于使用 持久化框架,但不要 执行任何持久性逻辑 自己?

类中的代码(相对于属性)没有持久性固有的特性。持久性可能需要默认构造函数,但没有实际执行持久性的代码。持久层可以进行相当大的更改,可以使用不同的数据库并且业务逻辑将保持不变。

【讨论】:

@djna - 我更新了我的定义,更清楚地表明我相信用特定于框架的注释装饰的类仍然被认为是持久性无知的,因为我意识到阅读你的回复可能不清楚。听起来您仍然会同意该定义,尽管您只考虑可执行代码,而不考虑元数据? 我同意,假设我们可以在没有元数据“干扰”的情况下运行代码。【参考方案6】:

虽然任何给定的持久性忽略框架都可能需要一些小限制,但持久性忽略仍然存在。

虽然域模型中的一个类(通过 NHibernate 透明地持久化)必须有一个无参数构造函数,以便可以“动态地”构造它,但它不需要具有框架规定的某个基类,也不需要它需要拥有或覆盖某些框架指定的方法。

【讨论】:

@Justice - 好像你刚刚重新陈述了我的问题。您如何看待对象结构和设计中的限制以促进框架的使用与使用注释来促进框架的使用在概念上有所不同? NHibernate 等不了解持久性的 ORM 所施加的约束与序列化和面向方面编程(我们将持久性只是使用序列化的另一个方面)所施加的约束相比略多。 [Serializable][DataContract] 都不能让通用序列化机制工作。这些是来自特定框架的特定类。因为序列化根本需要无参数构造函数而具有无参数构造函数的类仍然可以对序列化无知。但是具有[Serializable] 属性的类不再是序列化无知的,实现ISerializable 的类也不是。 @Justice - [Serializable] 完全有助于通用序列化机制;这只不过是一种约定,表明您允许对类进行序列化。您会注意到 .NET 框架包含使用此属性的不同格式化程序实现(两个二进制和一个 XML)。对我来说,与添加构造函数相比,它对类的行为的改变更少,因为它是元数据,而不是可执行代码。 (另外,序列化根本不需要无参数构造函数。您可以从完全受信任的程序集中调用 FormatterServices.GetUninitializedObject,这正是 IFormatter 类所做的.因此,具有仅用于序列化目的的默认构造函数至少在某种程度上承认存在某种需要它的序列化类型,因为并非所有人都这样做,因此不能说该类是真正的序列化无知,恕我直言。 )【参考方案7】:

在我看来,“持久性无知”是您的模型(域模型、业务模型或您可能称之为的任何东西)的属性。该模型对持久性无知,因为它通过抽象(有时称为存储库)检索它包含的实体的实例。这些抽象可以通过直接使用 ORM 来实现,但正如您自己所说,这有时可能会向不自然属于您的模型的对象添加要求。因此,我不会说遵守特定 ORM 某些要求的模型是 100% 不了解持久性的。

【讨论】:

我不完全同意。您可以拥有一个通过诸如存储库之类的抽象来检索的域类,但这不是 PI。例如,您使用的持久性框架可能要求您的域类继承自持久性框架定义的某个基类。【参考方案8】:

您可以使用域的类或应用程序和持久性中的 POCO 类来实现持久性无知,当您要将域对象映射到持久性类中并使用持久性对象与 nhibernate o 一起存储时其他框架

你的领域类必须忽略信息是如何被持久化的,所以你不能包含任何持久化框架的规则,比如(空构造函数、虚拟属性等)

这些持久性框架规则可以在你的持久性类中。

【讨论】:

以上是关于究竟啥是“执着无知”?的主要内容,如果未能解决你的问题,请参考以下文章

究竟啥是绑定?

究竟啥是 JavaBean?

究竟啥是“WPF 服务”?

究竟啥是“样本”?

究竟啥是 Web 框架?

究竟啥是现场注入以及如何避免它?