你能以关系数据库可以理解的方式表示应用程序对象吗?

Posted

技术标签:

【中文标题】你能以关系数据库可以理解的方式表示应用程序对象吗?【英文标题】:Can you represent an application object in a way that a relational database can understand? 【发布时间】:2009-08-26 22:07:08 【问题描述】:

Bill Karwin 有一篇名为“Why Should You Use An ORM?”的博文。 Reddit 上正在讨论这个问题,我对几点感到困惑。

他在 cmets 部分说:

OODBMS 和 ORM 仅适用于对象 我们已经在 应用层。 IE。不可能 进行这样的查询:

更新错误 SET status = 'CLOSED' WHERE 状态 = 'OPEN';

要在 ORM 或 OODBMS 中执行此操作,您必须获取所有错误 匹配条件并实例化 对象。 然后你可以设置 属性并保存对象 一一回到数据库。这 很贵,当然需要 比等效 SQL 更多的代码 操作如上所示。

这说明了一个优势 像 SQL 这样的语言,将集合视为 一流的数据类型。面向对象 范式不能代替 所有情况下的关系范式。 还有一些普通的操作 SQL 可以做得更好。

我将他说当你使用 ORM 时必须为这些错误实例化对象的部分加粗,因为这是我感到困惑的部分。

我的问题是为什么你必须这样做?好的,面向对象是一回事,关系是另一回事。 但真的是它们如此不同以至于没有办法表示一个对象以便关系数据库可以理解吗?例如,我在想你是如何可以序列化一个对象,然后将其写入文件可存储格式。您不能使用这样的格式将对象传输到关系数据库吗?

【问题讨论】:

仅供参考,我的博文是基于一个 SO 问题 ***.com/questions/448684/why-should-you-use-an-orm,所以我们已经完成了一个完整的循环! :-) 【参考方案1】:

[有]没有办法表示一个对象以便关系数据库可以理解它?

你错过了我陈述的重点。我并不是说不能将对象存储在关系数据库中。我的意思是 OO 范式假设您在应用程序空间中拥有该对象的实例。也就是说,您可以调用对象的方法和访问属性:

$bug->status = 'CLOSED';
$bug->save();

但是在我见过的任何 ORM* 中,如果不先从数据库中获取对象实例,就无法对它进行操作。您也不能像使用 SQL 那样一次对整组行进行操作。

看到一个对象类型映射到集合数据的 ORM 包会很有趣。然后,当您更改属性时,它会应用于该集中的所有行。我还没有看到任何 ORM 尝试这样做。

由于并发问题,这将非常具有挑战性。该集合是否包括实例化对象、执行更改或保存更改时该集合中的行?如果它支持所有这些排列作为选项,那么使用起来就会变得如此复杂,以至于人们可能会正确地认为它与直接使用 SQL 相比没有任何实际改进。

关于您的评论:并不是集合和对象不兼容。一个集合可以是一个对象(Java 甚至有 Collection 和 Set 的类)。但是 OO 范式假定操作适用于 one 对象实例,而关系运算符始终适用于集合(一行的集合仍然是集合)。实际上,今天存在的 ORM 包做出了相同的假设,即一次只能更改一行的一个实例,并且您必须先获取该行才能更改它。

理论上,扩展 ORM 的功能以处理集合可能是可行的——但 AFAIK 没有人尝试过这样做。我的主张是,一个可以完成所有关系运算符可以完成的操作的 ORM 会比 SQL 更糟糕。

* 我排除了类似 SQL 的伪语言,如 HQL,它们恰好是 ORM 包的一部分(HQL 的情况下为 Hibernate),但该伪语言本身不符合 ORM 的条件。

【讨论】:

感谢您的回复,比尔。我对 HQL 不熟悉。也许这是一种跨越对象空间和关系空间之间鸿沟的语言的例子。但我想我的问题更多是关于为什么格式如此不兼容,即设置与对象。这就像你有一把钥匙,但它不适合锁。我想我只是不明白为什么它不适合这种程度。这就是为什么我没有在您的博文中提问的原因——我认为我的问题确实比您认为的更基本。 “看到一个 ORM 包有一个对象类型映射到一组数据会很有趣。然后当你改变一个属性时,它会应用到那个集合中的所有行”-> 没错!您继续解释为什么这会因为并发而变得困难,但是基于每个对象的乐观锁定不是一个简单的解决方案吗? 重新乐观锁定,好吧,如果您要更改的集合中的一行已经被锁定并拒绝操作,这会阻止集合中所有其他行的更改吗?或者它是可配置的?可以为每个应用程序、每个事务、每行配置吗?关键是,一般解决不是一个简单的问题。 LinqToSql 允许您完全做到这一点(尽管您可能会声称它不是真正的 ORM)-weblogs.asp.net/scottgu/archive/2007/05/19/… 我不知道将其应用于集合是否比将其应用于对象更难或更难。这确实是问题的来源。【参考方案2】:

ORM 将对象的状态映射到数据库中的等效状态。因此,如果您想使用 ORM 更改数据库中某物的状态,您可以使用的唯一机制是首先操作由数据库表示的对象,然后保存它们的状态。

我不确定你的意思:

我在想你怎么做 序列化一个对象,然后它得到 写入文件可存储的格式。 你不能用这样的格式来 将对象转移到关系 数据库?

你的意思是把一个对象序列化成一个结构,你可以主要存储在一个平面文件中(例如 XML 格式),然后将该数据存储在数据库中吗?如果是这样,是的,你可以。挑战在于您何时想要搜索该信息。假设您想查找所有“已关闭”的错误,则必须阅读每个错误,对其进行反序列化并检查其状态以查看是否应将其包含在列表中。

【讨论】:

但是除了使用 O/R 映射器之外没有其他方法可以在对象状态和关系状态之间进行转换,这真的是真的吗?我只是不明白为什么会这样。 我猜你可以说这是定义 O/R 映射器的关键部分。可以在对象状态和关系状态之间转换的东西是将一种状态“映射”到另一种状态,根据定义使其成为 O/R 映射器。 对,我只是想了解这两种格式如此不兼容以至于需要在两者之间进行翻译的原因。就是画不出来这就是我提到序列化示例的原因——似乎应该有一种方法可以更直接地在两者之间进行翻译。 序列化是将数据映射到长期存储的另一种方式。对于某些应用程序,将对象的 XML 表示形式写入文件并完成处理是非常好的。但是,如果您使用文件,则没有一个好的方法来根据标准查找单个对象(如果您使用 XML 文件,您将如何找到所有“关闭”的错误),而且您没有好的方法在各个对象/XML 文件之间创建关系的方法。这些是关系数据库擅长的事情,以及为什么将对象持久化到它们而不是 XML 中通常是有意义的。【参考方案3】:

ORM 的基本目的是将数据从一种表示形式转换为另一种表示形式;您引用的语气是 SQL 更适合批处理工作,这是真的——因为 ORM 会将关系数据表转换为对象图,然后再转换回表。

一个(非常松散的)类比是有一桶你想染成红色的纸浆。如果大桶代表 SQL 数据库,您只需将染料倒入并搅拌一下即可。使用 ORM 就像将纸浆转化为纸张,将单张纸染色,然后将(现在彩色的)纸重新制浆以放回大桶中。

【讨论】:

谢谢,我想我明白了这个比喻。我只是不明白为什么这是真的。我只是不明白为什么这两种格式 - set + object - 如此不兼容,以至于您需要在对它们进行操作之前将关系数据加载到对象中。 因为在 OO 范式中,我们可以 only 在对象实例上调用方法(或在类上调用静态方法,但我认为 update() 的静态方法不是大部分是 ORM)。

以上是关于你能以关系数据库可以理解的方式表示应用程序对象吗?的主要内容,如果未能解决你的问题,请参考以下文章

你能以编程方式修改 UICollectionView 滚动方向吗?

你能以编程方式访问当前的 Heroku dyno id/name 吗?

你能以编程方式在iOS 8(w / Swift)中切换“请勿打扰”模式吗?

你能以编程方式知道 GPU 中每个块的最大块数和线程数吗?

ER模型就和Access里面的关系视图一样吗?

libgdx- pixmap:我能以某种方式改变线条的宽度吗?