On Apr 11, 2012, at 3:34 AM, lars van gemerden wrote:

> Hi all,
> 
> I am looking for a way to append a child to a tree like structure. I
> am using adjacency to represent the tree.
> 
> Let's say I have a relationship configured with:
> 
> children = relationship(TreeNode,
>                                 primaryjoin = "TreeNode.id ==
> TreeNode.parent_id",
>                                 backref = backref( "parent",
> remote_side=[TreeNode.id]),
>                                 cascade = "all, delete-orphan",
>                                 use_list = True)
> 
> and I do:
> 
>   t1 = TreeNode()
>   t2 = TreeNode(parent = t1)
>   t3 = TreeNode(parent = t2)
> 
> then i can set:
> 
>   t1.parent = t3,
> 
> without problem, but:
> 
>   t3.children.append(t1)
> 
> gives a CircularDependencyError, while i would like this to give the
> same result as t1.parent = t3, perhaps by altering the behaviour of
> Treenode.children.append.
> 
> Am I missing something?
> Is there some way to arrange for this?

t1.parent = t3 means you aren't persisting a tree anymore - it's no longer a 
hierarchy, since t3 is a descendant of t1 already via t2.   It's a cycle.

The exception on the "children" side is probably because mutating "children" 
has the effect of both t3 and t1 being considered in the flush (due to 
t3.children as well as t1.parent_id changing), whereas t1.parent = t3 does not 
actually consider "t3" to modified.   You'd still get a cycle if you created 
everything via "x.parent=y" at once (below I just put it into the 
adjacency_list.py example - boom):

    node = TreeNode('rootnode')
    n1 = TreeNode('node1', parent=node)
    n2 = TreeNode('node2', parent=n1)
    node.parent = n2
    session.add(node)
    session.flush()

sqlalchemy.exc.CircularDependencyError: Circular dependency detected. Cycles:  
...

though I wasn't able to reproduce the behavior being different by mutating 
children vs. the parent....I'm sure with more digging I could figure that out.  
 But in any case, you aren't safe from cycles if you're building them, the 
usual way to insert rows with cycles to themselves is to use the post_update 
feature described at 
http://docs.sqlalchemy.org/en/latest/orm/relationships.html#rows-that-point-to-themselves-mutually-dependent-rows
 .    You probably need to put it on both sides in this case as the unit of 
work code will consider one or both of the "children" or "parent" relationships 
in a particular flush depending on where it sees changes.



-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

Reply via email to