Add recursive UpdateWithChildren and GetWithChildren variants (UpdateWithDescendants, GetWithDescendants?)

Issue #5 resolved
Matt Benic created an issue

I expected UpdateWithChildren to also update children's children (and so on). I can see why not having that as the default behaviour is safer, and the name does include the word children and not descendants, which I suppose should be understood as only one layer down. However, a recursive version would be useful :)

Similarly, a GetWithDescendants recursive variant of GetWithChildren would be useful as well.

Comments (12)

  1. Guillermo Gutiérrez

    This is something definitely in the TODO list and it's perfectly doable, the main issue found here are loops and inverse relationships. How would you expect it to work with circular references?

    On the other hand, inverse relationships may force you to load the entire database to memory when performing recursive operations. Maybe we could add another parameter ('IgnoreRecursiveRead' and 'IgnoreRecursiveWrite'?) like the 'ReadOnly' property to avoid this kind of issues.

    If anyone comes with a better idea I'm open to suggestions.

    Thanks for your feedback again.

  2. Matt Benic reporter

    I'll most likely be needing to implement something like this myself, so if I do I'll do it on a Fork and PR it. I hadn't thought of the inverse relationships (I don't know my way around those yet) but I thought of getting around the other issues (recursion and depth) as follows: -(data size): Have a depth limit parameter on the GetWithDescendants call, and only keep fetching data down to that level -(loops) Internally call a version that takes a HashSet parameter and adds objects to the set as it goes. If the object the method is being called on is already in the hashset it early outs.

    Would the HashSet check sort out the inverse relationship issue as well?

  3. Guillermo Gutiérrez

    Yes, the HashSet solves the integral reference issue and loops to some degree. Let me explain the inverse relationship issue with an example:

    Imagine a tree model like this:

    Country -> Province -> City -> Street

    Where all relationships are a 1:N relationship with an inverse property.

    Calling GetChildren on a city to load the streets would also load it's province and will recursively the country too. Then, all the provinces of that country will be loaded and then all the cities of all the provinces and then all the streets of all the cities.

    I'd solve this problem adding a parameter to the relationship attribute to avoid some of them being loaded recursively.

    I'm going to create a branch with some test cases to see how it goes.

  4. Guillermo Gutiérrez

    Already implemented recursive read operations, all tests passing so far. You can take a look at how it goes at the development branch. It seems to works pretty well if you ask me. Going for the write operations. It may take a while.

  5. Matt Benic reporter

    That's great :) I started working on it my side over the weekend as well, but I realized my understanding of child/parent was incorrect which set me back a bit.

  6. Guillermo Gutiérrez

    I don't think that 'UpdateWithChildren' makes sense being recursive. I think it makes much more sense creating 'insert' and 'delete' recursive methods, but updating recursively would be the same that 'InsertOrReplace' and the latter seems clearer. Any thoughts?

  7. Matt Benic reporter

    My current use-case definitely leans more towards recursive insert (setting up some default data in the database, with current relationships up to 4 objects deep). Recursive update would probably be used far less frequently (in most cases a user would be making changes to a single object and maybe children one level down, and can immediately update just those), so it's probably less necessary.

  8. Guillermo Gutiérrez

    InsertWithChildren and InsertOrReplaceWithChildren is now implemented and the tests are passing. Take into account that the API is not released yet and may change and the test suite or documentation is not complete yet. Take a look at the tests for examples on how to use it.

  9. Guillermo Gutiérrez

    InsertAllWithChildren, InsertOrReplaceAllWithChildren, Delete and DeleteAll methods have been created for recursive operations. The created test suite is passing. I'm going to add documentation for all this and it's going to the master branch in a few days.

  10. Matt Benic reporter

    Works a treat, thanks. Building up template data in code is an absolute pleasure now, as is reading data needed for particular areas.

  11. Log in to comment