Prefetch path "looping" result in duplicates

Posts   
 
   
 
Anonymous
User
Posts: 0
Joined: 11-Nov-2006
# Posted on: 20-Apr-2009 14:02:30   

Here's my case.

Cake - Fruit <- Basket

Adapter scenario. I'm loading a Cake. I need to prefetch the Fruit of my Cake, and the Basket of that Fruit. (works fine) Now I add Basket.Fruit as a subpath because I also need other fruits of the same basket to do some processing. As a result, the Fruit of my Cake ends up being twice in the collection. That's not what I want. I want one instance of each fruit of the basket in the Cake.Fruit.Basket.Fruit collection.

What's the correct way to do this ?

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 20-Apr-2009 15:00:21   

Runtime library verison and code snippet please.

Anonymous
User
Posts: 0
Joined: 11-Nov-2006
# Posted on: 20-Apr-2009 15:14:16   

Runtime version 2.6.8.804 / v2.0.50727

Snippet

    FruitEntity Fruit = new FruitEntity(FruitId);
            // add prefetch paths as needed to load related entities
            IPrefetchPath2 prefetch = new PrefetchPath2((int)EntityType.FruitEntity);
            prefetch.Add(FruitEntity.PrefetchPathBasket).
                SubPath.Add(BasketEntity.PrefetchPathFruit);
            Adapter.FetchEntity(Fruit, prefetch);
Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 20-Apr-2009 15:19:20   

v2.0.50727

That's not a correct one. Please check this: http://www.llblgen.com/TinyForum/Messages.aspx?ThreadID=7722

What's the relation of CampaignEntity to the required graph?

Anonymous
User
Posts: 0
Joined: 11-Nov-2006
# Posted on: 20-Apr-2009 15:24:30   

Info corrected on previous post.

CampaignEntity was a mistake when replacing my example from real code.

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 20-Apr-2009 15:36:15   

I'd recommend upgrading to the latest build as you are using a relatively old one, although I'm not sure this would fix your problem.

One thing you need to try is to fetch the related entities into separate temp collection. And then add the fetched entities to the related collection after setting it's DoNotPerformAddIfPresent property to true.

The wrote:

When set to true, an entity passed to Add() or Insert() will be tested if it's already present. If so, the index is returned and the object is not added again. If set to false (default: true) this check is not performed. Setting this property to true can slow down fetch logic. DataAccessAdapter's fetch logic sets this property to false during a multi-entity fetch.

Anonymous
User
Posts: 0
Joined: 11-Nov-2006
# Posted on: 20-Apr-2009 15:43:15   

Wouldn't that result in going to the database several times instead of doing a join ?

My goal is to load the data in as few calls to database as possible.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39862
Joined: 17-Aug-2003
# Posted on: 20-Apr-2009 17:23:35   

It's been added twice because when you do: myFruit.Basket = myBasket; it also will under the hood do: myBasket.Fruits.Add(myFruit);

So Cake - Fruit - Basket will place the fetched Fruit in the Fruits collection of the Basket. Specifying Basket.Fruit in the path to fetch will fetch the fruit again and add it again to the fruits collection.

There's a flag in the collection as specified above by Walaa, to refuse additions of the same entity. This flag costs performance and in general you don't need checking for duplicates when doing prefetch path fetches so we switched it off by default.

How to switch it on for Basket.Fruits. By default, and entity in adapter doesn't get its containing entity collections yet, they're created on the fly.

So what you could do is the following: add a partial class to the generated db generic project for BasketEntity. In that class, override OnInitClassMembersComplete(). In there do: this.Fruits.DoNotPerformAddIfPresent = true;

now, when fetching fruits using your prefetch path, you won't receive duplicates in fruits. It's a little slower as the code will search linearly for the existing entity based on Equals(), however with not that much fruits in Basket (e.g. < 100) you won't notice it. It has no other impact on your code, by default duplicates are filtered out in fetches anyway.

Frans Bouma | Lead developer LLBLGen Pro
Anonymous
User
Posts: 0
Joined: 11-Nov-2006
# Posted on: 20-Apr-2009 17:55:10   

Thank you Frans, that's exactly what I was looking for. Your answer is very clear.

If you can sneak in an overload of prefetch path creation function to set this parameter without having to override OnInitClassMembersComplete for each entity in a future update of LLBLGen, that'd be the bee's knees.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39862
Joined: 17-Aug-2003
# Posted on: 20-Apr-2009 20:27:31   

I'll make a change request for this indeed. It should be less cumbersome simple_smile

Frans Bouma | Lead developer LLBLGen Pro
rdhatch
User
Posts: 198
Joined: 03-Nov-2007
# Posted on: 05-Nov-2009 08:12:13   

Hi Frans -

Any reason you wouldn't use the Context here? Would using the Context be more flexible here, instead of configuring partial classes for a particular fetch?

Many of my prefetches also require re-referencing other prefetched entities. I don't seem to need .DoNotPerformAddIfPresent if I use the Context, correct?

Please let me know your thoughts... interested to hear from you on this. Thanks!

Ryan

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39862
Joined: 17-Aug-2003
# Posted on: 05-Nov-2009 10:24:28   

I don't see what the context has to do with this, as it's not needed if you specify the tree correctly. Contexts are for uniquing, but have no effect on whether there are duplicates placed in collections or not.

Frans Bouma | Lead developer LLBLGen Pro
rdhatch
User
Posts: 198
Joined: 03-Nov-2007
# Posted on: 05-Nov-2009 10:48:02   

Roger. Thanks,

Ryan

arschr
User
Posts: 894
Joined: 14-Dec-2003
# Posted on: 05-Nov-2009 13:36:04   

any plans to change the .DoNotPerformAddIfPresent search from a linear search to a keyed search in v3.0?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39862
Joined: 17-Aug-2003
# Posted on: 05-Nov-2009 13:43:01   

Not for 3.0. We made a keyed list for Algorithmia, the library that's shipped with llblgen pro designer, but it's .net 3.5 based, so we need two builds for the runtime and with 3.0 we won't do that. Perhaps in 3.next (3.1, 2...)

It's a tad complicated to build the index, as pk fields can change too, and new entities don't have a pk hash. The biggest downside is that it takes memory to store an index. In the past years we've worked hard to limit memory usage, especially in large collections, and re-adding an index is adding extra overhead which is only used in some situations.

Frans Bouma | Lead developer LLBLGen Pro