数据映射器和关系:实施策略?
我几乎完成了我的数据映射器,但现在我处于关系关系的阶段。
我会试着在这里说明我的想法。 我无法找到关于这个主题的好文章/信息,所以也许我正在重新发明轮子(当然,我可以使用一个大框架 - 但我想通过这样做来学习)。
1:1关系
首先,让我们看看1:1的关系。 一般来说,当我们有一个名为“Company”的域类和一个名为“Address”的域类时,我们的公司类将具有类似address_id的内容。 可以说,在大多数情况下,我们只显示一个公司名单,只有当有人查看细节时才需要地址。 在这种情况下,我的Data Mapper(CompanyDataMapper)只是简单地加载,意味着它只会从数据库中获取address_id,但不会进行连接以获取地址数据。
一般来说,我为每个关系都有一个getter方法。 所以在这种情况下,有一个getAddress(公司companyObject)方法。 它需要一个公司对象,查找它的地址属性,如果它是NULL,则从数据库中获取相应的Address对象,使用该Address对象的Mapper类(AddressDataMapper),并将该地址对象分配给指定的地址属性公司对象。
重要提示:数据映射器是否允许使用其他数据映射器?
可以说在大多数情况下,你需要公司对象和地址对象,因为你总是一起显示它在一个列表中。 在这种情况下,CompanyDataMapper不仅获取公司对象,而且通过JOIN执行SQL查询以获取地址对象的所有字段。 最后,它遍历记录集并为新对象提供相应的值,并将地址对象分配给公司对象。
听起来很简单,到目前为止。
1:n关系
这些怎么样? 与1:1唯一的区别是,公司可能有多个地址对象。 让我们看看:当我们大多数时间只对公司感兴趣时,Data Mapper会将公司对象的地址属性设置为NULL。 地址属性是可以引用无,一个或多个地址的数组。 但是我们还不知道,因为我们懒洋洋地加载,所以它只是NULL。 但是,如果我们在大多数情况下也需要所有的地址,那又如何呢? 如果我们将所有公司的大名单连同他们的所有地址一起显示? 在这种情况下,事情变得非常难看。 首先,我们不能为每个地址对象加入地址表五十次(我坚信这是不可能的,如果是的话,性能会低于零)。 所以,当我们进一步思考这个问题时,在这种情况下不可能不加载。
重要:这是真的吗? 我必须发送100个查询来获得100个地址对象,如果我有10家公司,每个地址有10个地址?
m:n关系
可以说一个地址对象只包含国家,州,城市,道路和门牌号码。 但是,一间房子可能是一个大型商业大厦,其中有很多公司。 就像那些现代化的办公大楼之一一样,任何人都可以租用一个小型的ROM来炫耀它的网站上的塔。 所以:许多公司可以共享相同的地址。
我还没有计划处理这种问题。
重要:可能它不是比1:n关系更大的问题?
如果有人知道解决/实施这个问题的详细资料,我会很高兴看到一个链接!
我期待着您就这个话题得到任何答案,但同时为什么不直接跳到亚马逊(或您的本地图书经销商),最后购买
这些书包含您在各种问题中指出的原始模式,并被视为设计模式和软件体系结构中的参考工作。
在我开始之前,我会假设你从头到尾阅读了福勒的PoEAA书。 =)另外,我会考虑你已经想到了在处理ORM时你遇到的第一个初始问题。 我可以强调一个简单的方法,例如使用相同的标识符多次调用DataMapper,并始终返回相同的对象(读取为IdentityMap)。
重要提示:数据映射器是否允许使用其他数据映射器?
如果第二个DataMapper是第二个弱引用,那么只能有一个DataMapper访问另一个DataMapper。
可以说在大多数情况下,你需要公司对象和地址对象,因为你总是一起显示它在一个列表中。 在这种情况下,CompanyDataMapper不仅获取公司对象,而且通过JOIN执行SQL查询以获取地址对象的所有字段。 最后,它遍历记录集并为新对象提供相应的值,并将地址对象分配给公司对象。
你在这里讨论的问题在实践中听起来很简单,但在幕后有点复杂。
首先,你不应该有一个getAddress(公司),而是有代理对象的好处。 代理是给定实例的非初始化表示。 在这种情况下,代理包含对您要查找的条目的引用。 它必须从原始对象扩展,并且需要提供一个初始化方法,以及一个相关的DataMapper来加载它。
关于加入多个对象的第二部分被称为Hydrator。 Hydrators接收线和列的平面结构并转换为对象图。 但它真的进入了一个单独的问题:如果你纯粹处理对象,你为什么抓取表? 尝试采用对象提取方法会导致您实现一种OQL(对象查询语言)。
重要:这是真的吗? 我必须发送100个查询来获得100个地址对象,如果我有10家公司,每个地址有10个地址?
处理一组对象是PHP中的噩梦。 是的,这种语言由于缺乏强大的集合实现而吸引很多。 基本上,你需要在这里处理不同的情况: - 新实例和元素列表中的所有元素都是新的 - 新元素和元素列表中的所有元素都是预先存在的 - 元素列表中的新实例和元素在新的和预先存在的实例之间混合,并且不触及元素列表上的任何事物 - 预先存在的实例和操作列表上的项目
我在这里非常简单,但我想强调的一点是需要一个Collection对象。 其中有两个:一个处理新列表和一个处理现有列表。 处理现有列表的应用程序需要能够在您尝试访问内部任何内容时加载收集。 这是没有n + 1问题的唯一方法。
这里还强调了你必须处理的下一个大问题。 关联可以是单向的或双向的。 这意味着公司知道地址但地址不知道公司是单向的,而用户是许多组和组的一部分,组包含许多用户是双向关联。 事情很容易变成这里的噩梦,这就是为什么你需要映射模式来正确理解发生了什么。
处理多对多就像处理一般收藏一样。
还有一个你尚未考虑过的重要部分。 如果我构建了我的整个对象图(公司和地址)并决定坚持它们,那么它需要坚持这两个对象图表,还是必须手动说出我想要坚持的内容? 两种方式都有不同的问题。 假设你想要第一种方法。 你刚刚进入了我认为是最复杂的设计模式之一:UnitOfWork。 然后,你必须处理排序实体的顺序,以不产生约束问题(阅读拓扑排序如何解决这个问题)。 如果采取第二种方法,您可能很容易进入感觉工具被破坏的情况,主要是因为很容易让对象图形处于不一致的状态。
最后......你打算做什么支持继承? 如果是积极的,你的整个计划就进入了一个全新的水平。 =(试图解释会带我一本书,但我可以指出一些设计模式,你可以看看:具体表继承(1类,1表),单表继承(N类,1表)和类表继承(N班级,M表)。
我可以在这里深入探讨许多不同的观点,但是ORM通常会导致头部爆炸。 我现在就停下来。
PS:我是Doctrine ORM的核心开发人员之一。 除非你是为了学习目的而这样做,否则不要费心去创建另一个。 这是一个非常复杂,耗时的事情,在你编写第一行代码之前,需要对事情的工作方式进行大量的计划。 事实上,我们计划了2年的Doctrine ORM,花了1年时间来可靠地实现核心功能。 我并不沮丧你,但正如福勒在他的ORM讨厌文章中所说的,对于一个复杂的问题来说,这是一个复杂的解决方案。
我也正在解决这个问题。 首先,我调整了Matt Zandstra的PHP Objects,Patterns,and Practice(2d Ed)中的Data Mapper模式。 我现在看到新版本出来了
也许设置最巧妙的部分是“收藏”对象。 我不确定你使用的是什么语言,所以我会告诉你细节。 只要说PHP有一个Iterator接口,它就可以首先加载一个数组(地图,用其他语言),并在循环的同时将原始数据转换为对象(水合物?)。
像你一样,我正在努力如何加载关系。 到目前为止我发现的是,我可以在Mapper类中编写我的大量JOIN查询,并同时为目标对象创建一个脱水集合并潜入相关对象的数据。
我真的不喜欢“懒加载”,因为它会导致这么多的数据库查询。 它冒犯了我完美主义的敏感性,知道我使用数十或数百个查询来完成任务,可以一次完成。
我也期待着更多的答案。
链接地址: http://www.djcxy.com/p/9609.html上一篇: Data Mapper and Relationships: Implementation strategies?