Efficient tree retrieval

Posts   
 
    
nottinbe
User
Posts: 46
Joined: 15-Mar-2007
# Posted on: 05-Jul-2007 17:53:37   

I've searched through the forums for a definitive answer on this, but I couldn't find anything that seemed to fit.

I have a table that references itself in a parent-child fashion to form a tree. That table also has a foreign-key to other tables that make up essential data for each node in the tree, and so lazyloading doesn't really make sense.

The tables won't be that big, and it would be OK to load every row of each table in a single query, for two total queries. Even if it was necessary to filter this load at some point, I am using SQL 2005 so I would just use a recursive query.

So, what I want, is a way to have the LLBLGen object graph built based on a single query that returns every object that will be in the graph as a single result set. Does this exist?

I am aware of the prefetch paths. However, I believe that they will execute a query per node, to get the all of the direct children for that particular node only. This could result in many queries for a deep and narrow tree.

The direction I am trying so far is to use Context. My first attempt was to load the Context with each of the collections that contain all the objects I'll need. I was then hoping\assuming that the lazyload when I reference the n:1 object property would see that its already in the Context and not go to the database. Instead it first goes to the database, and then if its in the Context uses that instead. This defeats the purpose.

So at this moment, what I am considering doing, is editing the EntityInclude template to have the GetSingle<[MappedFieldNameRelation]> function first look to see if its in Context, and only if its not there go to the database.

After all of that, I have two questions:

1) Is there already a builtin way to do what I want? 2) If not, and this Context route is my best option, would it make sense to add as an option to LLBLGen the ability to check Context first on a lazyload instead of always going to the db?

Thanks, Brian

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 06-Jul-2007 11:51:46   

I am aware of the prefetch paths. However, I believe that they will execute a query per node, to get the all of the direct children for that particular node only. This could result in many queries for a deep and narrow tree.

PrefetchPaths don't execute a query for each node, but a query for each prefetchPath level. The following is copied from the manual:

In the Preface paragraph, the example of an Order selection and their related Customer objects was mentioned. The most efficient way to fetch all that data would be: 2 queries, one for all the Order entities and one for all the Customer entities. By specifying a Prefetch Path together with the fetch action for the Order entities, the logic will fetch these related entities defined by the Prefetch Path as efficient as possible and will merge the two resultsets to the result you're looking for.

For self joined hierarchies, please check the following thread, which in turn have some links to other threads simple_smile http://www.llblgen.com/TinyForum/Messages.aspx?ThreadID=9976

nottinbe
User
Posts: 46
Joined: 15-Mar-2007
# Posted on: 06-Jul-2007 14:44:59   

Thank you for the response. I have read through those links and understand the concepts. If I went the route of prefetch paths, how do I make the lazy-loading mechanism automatically use a prefetch path that I specify?

I don't want to control this per-object but rather per-class. I would like it to be transparent to the consumer of the entity object that when they use the .Children property, if the children need to be lazy-loaded, its automatically done with the necessary prefetch path.

Thanks, Brian

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 06-Jul-2007 15:13:55   

Lazy loading implies that the entities are fetched automatically when accessed or needed. This would be transparent.

how do I make the lazy-loading mechanism automatically use a prefetch path that I specify?

PrefetchPaths are specified to fetch some related entities when fetching their root/main entity. Thus fetching up-front what you meight need or access in the future. Loazy Loading(sometimes called Load on Demand) on the contrary fetches related entities only when they are being accessed.

nottinbe
User
Posts: 46
Joined: 15-Mar-2007
# Posted on: 06-Jul-2007 15:34:52   

OK, then let me ask a different way.

How do I make the .Children property of a parent entity not lazy load, and instead be already loaded by using the appropriate prefetch?

This is what I need:

ParentEntity parent = new ParentEntity(); ChildEntityCollection children = parent.Children;

And to have the ChildEntityCollection to have been loaded by the prefetch path I want to specify.

Thanks, Brian

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 06-Jul-2007 15:58:17   

In SelfServicing, where Lazy Loading is used, you fetch a single entity by specifying its PK in the constructor, now if you also specify the correct prefetchPath to the constructor the related entity would be fetched at the same time.

The following code fetches a Customer of PK "BLONP", and fetches the related Employees entity.

// C#
IPrefetchPath prefetchPath = new PrefetchPath((int)EntityType.CustomerEntity);
prefetchPath.Add(CustomerEntity.PrefetchPathEmployees);
CustomerEntity customer = new CustomerEntity("BLONP", prefetchPath);
nottinbe
User
Posts: 46
Joined: 15-Mar-2007
# Posted on: 06-Jul-2007 16:02:57   

OK, sorry I missed that constructor overload.

Now, will that then pass on that prefetch down the recursive hiearchy?

So if I do:

ParentEntity parent = new ParentEntity(12, myPrefetch); ChildEntityCollection greatGrandChildren = parent.Children[0].Children[0].Children;

When each child is created, will it also be initialized with "myPrefetch"? This is what I really need - for the prefetch to just automatically be used all the way down the recursive hierarchy.

Thanks, Brian

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 06-Jul-2007 16:10:07   

Now, will that then pass on that prefetch down the recursive hiearchy?

So if I do:

ParentEntity parent = new ParentEntity(12, myPrefetch); ChildEntityCollection greatGrandChildren = parent.Children[0].Children[0].Children;

When each child is created, will it also be initialized with "myPrefetch"? This is what I really need - for the prefetch to just automatically be used all the way down the recursive hierarchy.

No, the PrefetchPath is used on the level it has been specified to, otherwise it could lead to severe performance problems.

If you know upfront the number of levels that you want to prefetch, you can specify a prefetchPath with SubPaths to the number of levels you want.