如何控制急切加载数据映射器的获取深度?
-
05-07-2019 - |
题
我有一个datamapper类,它会急切加载任何没有附加Lazy属性的属性。我有两个实体,州和国家,国家与州有反向关系,因为它包含该国家所有州的清单,国家与国家有前向关系,因为它有一个属性国家,渴望加载国家它被分配给。但是,如果我尝试检索其中一个对象,让我们说一个状态就是这样:
- 状态由mapper加载
- Mapper到达一个急切的财产国家
- Mapper检索该州的国家/地区
- Mapper加载国家/地区
- Mapper达到州的急切收藏属性
- Mapper加载一个状态列表,并开始使用缓存来映射每个状态。
- 国家/地区加载的每个州的GOTO 1 醇>
我对如何避免这种循环感到茫然。所以主要是我在寻找想法。我会发布任何人要求的任何代码,但是这个过程包含很多代码行,所以我不想用代码充斥问题。
提前致谢!
编辑:
在听完Matt Howells的建议并深入研究数据传输模式之后,好吧,马丁福勒确实在第169页和第170页讨论了循环引用。他的建议是使用一个空对象并将其加载到身份图中并返回它停止递归加载。我现在已经阅读了这个段落大约1000次,我仍然不明白这是如何阻止负载的,除此之外我还不知道何时或如何知道何时将这个空对象加载到我的身份地图中。我为这里的密集而道歉,但这似乎只是飞过我的脑袋。
再次感谢。
解决方案
考虑通过存储库加载对象,该存储库跟踪已加载的对象。
编辑:如果你正在做自己的ORM(即使你不是),我强烈推荐Martin Fowler的书“企业应用程序架构模式”。我隐约记得他在书中谈到这种循环情况,所以它可能对你有帮助。
编辑2: 在你的循环的第4步和第5步,如果你已经加载了国家,那么就不需要急切地加载它们的状态,因为它们应该已经被加载了。这打破了无限循环。
其他提示
datamapper应该捕获循环引用。它是自制的数据映射器吗?
我只是想发布我想出的解决方案,但我相信有很多方法可以让这只猫皮肤。
这是我创建的FetchDepthCounterClass:
public static class FetchDepthCounter
{
private static Dictionary<Type, int> _DepthCounter;
private static int _MaxDepth = 3;
static FetchDepthCounter()
{
_DepthCounter = new Dictionary<Type, int>();
}
public static void SetDepth(int depth)
{
_MaxDepth = depth;
}
public static void ResetCounter()
{
_DepthCounter.Clear();
}
public static bool IncrementCounter(Type entityType)
{
if(!_DepthCounter.ContainsKey(entityType))
{
_DepthCounter.Add(entityType, 0);
return true;
}
if(_DepthCounter[entityType] < _MaxDepth)
{
++_DepthCounter[entityType];
return true;
}
return false;
}
}
IncrementCounter返回一个bool,说明是否已达到最大提取深度。在我设置属性的值之前,我将增量计数器作为映射过程的一部分。首先,我确定我需要加载的是另一个DTO对象或DTO集合,我传递父类型并在该类型上递增。所以这是我的数据映射器中的SetValue方法中的一小段代码:
if(isDto)
{
if (!FetchDepthCounter.IncrementCounter(property.ComponentType))
return;
}
就是这样,它似乎就是这么做的。我的所有单元测试都在通过。谢谢大家的帮助。我希望以后可以帮助别人。再一次,这可能会更容易将它包装在一个单元的工作模式中,最终我可能会这样做,但这现在可以完成工作。