如何控制急切加载数据映射器的获取深度?
我有一个 datamapper 类,它将立即加载任何没有附加 Lazy 属性的属性。 我有两个实体,州和国家/地区,国家/地区与州有反向关系,因为它包含该国家/地区所有州的列表,而州与国家/地区有正向关系,因为它有一个属性国家/地区,该属性急切地加载该国家/地区它被分配给。 但是,如果我尝试检索这些对象之一,假设有一个 State,则会发生以下情况:
- State 由映射器加载
- Mapper 到达急切属性 Country
- Mapper 检索该州的国家
- Mapper 加载国家
- Mapper 到达 States 的急切集合属性
- 映射器加载状态列表,并开始使用可以使用的缓存来映射每个单独的状态。
- 对于在国家/地区加载的每个州,GOTO 1
我不知道如何避免这种循环。 所以我主要是在寻找想法。 我会发布任何人询问的任何代码,但是这个过程包含很多代码行,所以我不想用代码淹没这个问题。
提前致谢!
编辑:
好吧,在遵循 Matt Howells 的建议并深入研究数据映射器模式之后,Martin Fowler 确实在第 169 和 170 页谈到了循环引用。他的建议是使用一个空对象并将其加载到恒等映射中并返回它,从而停止递归加载。 我已经读了这一段大约 1000 遍了,但我仍然不明白这是如何停止加载的,除此之外,我不知道何时或如何知道何时将这个空对象加载到我的身份映射中。 我很抱歉在这里太密集了,但这似乎就在我的头上。
再次感谢。
I have a datamapper class that will eager load any property that does not have a Lazy attribute attached to it. I have two entities, State and Country, Country has an inverse relationship to state in that it contains a list of all the states of that country and State has a forward relationship to Country in that it has a property Country that eager loads the country that it is assigned to. However if I try and retrieve one of these objects, lets say a State this is what happens:
- State is loaded by mapper
- Mapper reaches an eager property Country
- Mapper retrieves the country for that state
- Mapper loads the country
- Mapper reaches an eager collection property of States
- Mapper loads a list of states and begins mapping each individual one using the cache where it can.
- GOTO 1 for each state loaded in country
I am at a loss as to how I can avoid this loop. So mainly I am looking for ideas. I will post any code anyone asks, but this process encompasses A LOT of lines of code so I didn't want to flood the question with code.
Thanks in advance!
Edit:
Alright after following Matt Howells advice and investigating deeper into the datamapper pattern Martin Fowler does indeed speak about a cyclic reference on page 169 and 170. His suggestion is to use an empty object and load it into an identity map and return it thus stopping the recursive loading. I've read this paragraph about 1000 times now and I still don't understand how this stops the load and beyond that I am lost as to when or how I would know when to load this empty object into my identity map. I apologize for being dense here, but this just seems to be flying right over my head.
Thanks again.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
考虑通过存储库加载对象,该存储库跟踪已加载的对象。
编辑:如果您正在做自己的 ORM(即使您没有),我强烈推荐 Martin Fowler 的书《企业应用程序架构模式》。 我依稀记得他在书中谈到了这种循环情况,所以它可能对你有帮助。
编辑2:
在循环的第 4 步和第 5 步,如果您已经加载了国家/地区,则无需急切地加载其州,因为它们应该已经加载。 这打破了无限循环。
Consider loading objects through a Repository that keeps track of which objects have been loaded.
Edit: If you are doing your own ORM (and even if you are not) I highly recommend Martin Fowler's book Patterns of Enterprise Application Architecture. I vaguely recall him talking about this loop situation in the book so it might help you.
Edit 2:
At steps 4 and 5 of your loop if you have already loaded the country then there is no need to eagerly load its states because they should already be loaded. This breaks the infinite loop.
数据映射器应该捕获循环引用。 它是国产的数据映射器吗?
The datamapper should catch circular references. Is it a homegrown datamapper?
我只是想发布我想出的解决方案,但我相信有很多方法可以给这只猫剥皮。
这是我创建的 FetchDepthCounterClass:
IncrementCounter 返回一个布尔值,说明是否已达到最大提取深度。 在设置属性值之前,我将增量计数器称为映射过程的一部分。 首先,我确定必须加载的是另一个 DTO 对象或 DTO 集合,然后传递父类型并在该类型上递增。 这就是我的数据映射器中的 SetValue 方法中的一小段代码:
就是这样,似乎就可以做到这一点。 我所有的单元测试都通过了。 感谢大家的帮助。 我希望这对以后的人有帮助。 再一次,这可能会更容易将其包装在工作单元模式中,最终我可能会这样做,但这暂时完成了工作。
I just wanted to post the solution that I came up with, however I believe there are many ways to skin this cat.
Here is my FetchDepthCounterClass I created:
IncrementCounter returns a bool stating whether the max fetch depth has been reached or not. I call increment counter as part of my mapping process right before I set the value of the property. First I determine that what I am having to load is another DTO object or a collection of DTOs and I pass the parent type and increment on that type. So this is the small little bit of code inside my SetValue method in my datamapper:
That is it, that seems to do it. All of my unit tests are passing. Thanks for everyone's help. I hope this helps someone later on. Once again, this probably would have been much easier wrapping it in a unit of work pattern, and eventually I may do that, but this gets the job done for now.