Question

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:

  1. State is loaded by mapper
  2. Mapper reaches an eager property Country
  3. Mapper retrieves the country for that state
  4. Mapper loads the country
  5. Mapper reaches an eager collection property of States
  6. Mapper loads a list of states and begins mapping each individual one using the cache where it can.
  7. 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.

Was it helpful?

Solution

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.

OTHER TIPS

The datamapper should catch circular references. Is it a homegrown datamapper?

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:

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 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:

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

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top