代码之家  ›  专栏  ›  技术社区  ›  joshlrogers

如何控制急切加载的数据映射器的获取深度?

  •  2
  • joshlrogers  · 技术社区  · 15 年前

    我有一个DataMapper类,它将急切地加载没有惰性属性的任何属性。我有两个实体,国家和国家,国家与国家的关系是相反的,因为它包含了该国所有国家的列表,而且国家与国家有一个正向关系,因为它有一个财产国,渴望装载它被分配到的国家。但是,如果我尝试检索其中一个对象,让我们假设一个状态,这就是发生的情况:

    1. 状态由映射器加载
    2. 地图绘制者到达了一个渴望拥有地产的国家
    3. 映射器为该州检索国家
    4. 映射器加载国家
    5. 映射器到达状态的一个热切的集合属性
    6. 映射器加载一个状态列表,并开始使用缓存映射每个状态。
    7. 在国家/地区加载的每个州转到1

    我不知道该如何避免这个循环。所以我主要是在寻找想法。我会发布任何人要求的代码,但是这个过程包含了大量的代码行,所以我不想用代码来淹没这个问题。

    事先谢谢!

    编辑:

    好吧,在遵循MattHowells的建议并深入研究数据映射器模式之后,MartinFowler确实在第169页和第170页提到了循环引用。他的建议是使用一个空对象并将其加载到一个标识映射中,然后返回它,从而停止递归加载。我已经读了1000遍这段了,但我仍然不明白这是如何阻止负载的,超过了这一点,我就不知道何时或如何知道何时将这个空对象加载到我的身份图中。我为这里的拥挤感到抱歉,但这似乎在我的头上飞过。

    再次感谢。

    3 回复  |  直到 15 年前
        1
  •  2
  •   Matt Howells    15 年前

    考虑通过存储库加载对象,该存储库跟踪已加载的对象。

    编辑:如果你正在做你自己的ORM(即使你没有),我强烈推荐MartinFowler的《企业应用程序体系结构模式》。我隐约记得他在书中谈到了这种循环的情况,所以这可能会对你有所帮助。

    编辑2: 在循环的第4步和第5步中,如果已经加载了国家/地区,则无需急于加载其状态,因为它们应该已经加载。这打破了无限循环。

        2
  •  1
  •   EricSchaefer    15 年前

    数据映射器应捕获循环引用。它是国产的数据映射器吗?

        3
  •  0
  •   joshlrogers    15 年前

    我只是想贴出我想出的解决方案,但是我相信有很多方法可以帮这只猫剥皮。

    这是我创建的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;
        }
    
    }
    

    递增计数器返回一个bool,说明是否已达到最大提取深度。在设置属性值之前,我调用增量计数器作为映射过程的一部分。首先,我确定要加载的是另一个DTO对象或DTO集合,然后传递 起源 在该类型上键入并递增。这是我的DataMapper中setValue方法中的一小段代码:

    if(isDto)
    {
        if (!FetchDepthCounter.IncrementCounter(property.ComponentType))
            return;
    }
    

    就是这样,似乎就是这样。我所有的单元测试都通过了。谢谢大家的帮助。我希望以后这能帮助别人。再一次,将它包装成一个工作模式单元可能会容易得多,并且最终我可能会这样做,但现在这就完成了工作。