recursive IsDirty

Posts   
 
    
Banane avatar
Banane
User
Posts: 67
Joined: 01-Sep-2004
# Posted on: 05-May-2005 21:58:10   

Is there a way to do a recursive isDirty (parent/children).

parent.isDirty returns false event if a child is dirty.

how can I do that check?

tx

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39863
Joined: 17-Aug-2003
# Posted on: 06-May-2005 10:17:42   

Banane wrote:

Is there a way to do a recursive isDirty (parent/children).

parent.isDirty returns false event if a child is dirty.

That's true, because child entities aren't considered 'part of' a parent.

how can I do that check?

In which scenario do you want to use this?

Frans Bouma | Lead developer LLBLGen Pro
Banane avatar
Banane
User
Posts: 67
Joined: 01-Sep-2004
# Posted on: 06-May-2005 16:20:34   

I have the objects (parent/children) loaded in memory...I want to check if the objects are dirty to prompt the user to save before going away! sunglasses

tx

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39863
Joined: 17-Aug-2003
# Posted on: 06-May-2005 18:32:39   

Banane wrote:

I have the objects (parent/children) loaded in memory...I want to check if the objects are dirty to prompt the user to save before going away! sunglasses tx

aha simple_smile

Well, you can traverse the entities referenced by an entity, like the Save routine does too, by using the following routines: - entity.GetDependentRelatedEntities(), which gets a collection of entity objects which 'entity' depends on (e.g. a loaded Customer entity for an order entity). m:1/1:1 relations - entity.GetDependingRelatedEntities(), which gets a collection of entity objects which depend on 'entity'. (1:1 relations) - entity.GetMemberEntityCollections(), which gets a collection of collections (1:n relations). See the reference manual for details on these methods. With the contents of these methods you can check further, for example recursively in there to go deeper into the graph.

Frans Bouma | Lead developer LLBLGen Pro
RobertPhoenix avatar
Posts: 20
Joined: 14-Aug-2006
# Posted on: 24-Nov-2009 02:07:34   

I don't know if there is anything more recent about this issue (I searched and couldn't find it) - but after I implemented the suggestion I found that there was a danger of an infinite recursion - and you can guess how I found out.

So I decided to implement some protection against this and came up with the following code. It now appears to work without a problem, but I'd welcome any input about what I might have done wrong implementing the original idea, or any comments about why this might not be a good idea.



    public class llbUtil
    {
        public static bool RecursiveIsDirty(IEntity argEntity)
        {
            List<IEntityCollection> visitedCollections = new List<IEntityCollection>();
            List<IEntity> visitedEntities = new List<IEntity>();
            return RecursiveIsDirty(argEntity, visitedCollections, visitedEntities);
        }

        private static bool RecursiveIsDirty(IEntity argEntity, List<IEntityCollection> visitedCollections, List<IEntity> visitedEntities)
        {
            //Prevent infinite recursion

            if (visitedEntities.Contains(argEntity))
            {
                return false;
            }
            else
            {
                visitedEntities.Add(argEntity);
            }
            //Answer from Otis in LLBLgen forum
            //
            //Well, you can traverse the entities referenced by an entity, like the Save routine does too, by using the following routines:
            //- entity.GetDependentRelatedEntities(), which gets a collection of entity objects which 'entity' depends on 
            //   (e.g. a loaded Customer entity for an order entity). m:1/1:1 relations
            //- entity.GetDependingRelatedEntities(), which gets a collection of entity objects which depend on 'entity'. (1:1 relations)
            //- entity.GetMemberEntityCollections(), which gets a collection of collections (1:n relations). 
            //  See the reference manual for details on these methods. With the contents of these methods you can check further, 
            //  for example recursively in there to go deeper into the graph. 


            //Entity Dirty?
            if (argEntity.IsDirty) return true;

            //- entity.GetDependentRelatedEntities(), which gets a collection of entity objects which 'entity' depends on 
            foreach (IEntity entity in argEntity.GetDependentRelatedEntities())
            {
                if (entity != null)
                {
                    if (RecursiveIsDirty(entity,visitedCollections, visitedEntities))
                    {
                        return true;
                    }
                }
            }

            //- entity.GetDependingRelatedEntities(), which gets a collection of entity objects which depend on 'entity'. (1:1 relations)
            foreach (IEntity entity in argEntity.GetDependingRelatedEntities())
            {
                if (entity != null)
                {
                    if (RecursiveIsDirty(entity, visitedCollections, visitedEntities))
                    {
                        return true;
                    }
                }
            }

            //- entity.GetMemberEntityCollections(), which gets a collection of collections (1:n relations). 

            foreach (IEntityCollection entityCollection in argEntity.GetMemberEntityCollections())
            {
                if (entityCollection != null)
                {
                    if (RecursiveIsDirty(entityCollection, visitedCollections, visitedEntities))
                    {
                        return true;
                    }
                }

            }

            return false;
        }
        public static bool RecursiveIsDirty(IEntityCollection argCollection)
        {
            List<IEntityCollection> visitedCollections = new List<IEntityCollection>();
            List<IEntity> visitedEntities = new List<IEntity>();
            return RecursiveIsDirty(argCollection, visitedCollections, visitedEntities);
        }


        private static bool RecursiveIsDirty(IEntityCollection argCollection, List<IEntityCollection> visitedCollections, List<IEntity> visitedEntities)
        {
            //Prevent infinite recursion

            if (visitedCollections.Contains(argCollection))
            {
                return false;
            }
            else
            {
                visitedCollections.Add(argCollection);
            }

            //default RecursiveIsDirtyMode.RecursiveChildrenAndSiblings
            //Check for Entities in DeleteTracker
            if (argCollection.RemovedEntitiesTracker != null)
            {
                if (argCollection.RemovedEntitiesTracker.Count > 0)
                    return true;
            }

            //Loop through Collection
            foreach (IEntity myEntity in argCollection)
            {
                if (myEntity != null)
                {
                    if (RecursiveIsDirty(myEntity, visitedCollections, visitedEntities))
                        return true;
                }
            }
            return false;
        }

    }


daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 24-Nov-2009 07:01:54   

Here is another option, cloning the entity with binary serialization, produce a topology ordered list and then loop through it: http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=7568

David Elizondo | LLBLGen Support Team
rdhatch
User
Posts: 198
Joined: 03-Nov-2007
# Posted on: 24-Nov-2009 08:58:36   

Hi Robert & David -

Good job, Robert. You can use recursion or flattened topology, as David has mentioned. I see you are checking the RemovedEntitiesTracker collection - which it looks like you are using to track entities marked for delete.

The flattened topology method prevents you from visiting any entity twice. For each entity in the graph, you could look at it's entity collections & check for a .RemovedEntitiesTracker. That way, you wouldn't need to keep a list of visited entities & collections.

Graph stuff is fun to work with. Keep up the good work.

Ryan