Prefetching Backwards, Bug or not recommended?

Posts   
 
    
Posts: 112
Joined: 09-Aug-2004
# Posted on: 12-Jun-2009 21:08:40   

I have aded an attachment which contains an example of this issue. I am using version 2.6 final with the Adapter Template.

Why does this behavior occur? When I prefetch an element, then specify the sub element should fetch the original element, that part of the path is canceled out.

For example, consider the following path:


            IPrefetchPath2 path = new PrefetchPath2(EntityType.CustomerEntity);
            path.Add(CustomerEntity.PrefetchPathOrder)
                .SubPath.Add(OrderEntity.PrefetchPathCustomer);

The subpath to fetch the customer cancels out the path which is suppose to fetch the order. If I enable tracing, I can see that it is actually selecting all the data properly. It just isn't being populated in the entities. If I remove the subpath, the Orders are fetched fine.

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 13-Jun-2009 05:02:34   

In the code you wrote above, you don't need to add the SubPath. Why add unnecessary cyclic paths?

In other words, when you fetch the Customers and prefetch its Ordes, all that orders will contain the appropiate customer entity (related entity sync).

David Elizondo | LLBLGen Support Team
Posts: 112
Joined: 09-Aug-2004
# Posted on: 15-Jun-2009 15:35:08   

But then why do I see the correct SQL queries going through the output window? It will select Customers, Orders then Customers again. Also, why when there is the subpath do the Orders not get populated?

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

Which LLBLGen Pro runtime library version/build are you using?

Posts: 112
Joined: 09-Aug-2004
# Posted on: 15-Jun-2009 16:14:15   

I am using the v2.0.50727 runtime.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39859
Joined: 17-Aug-2003
# Posted on: 15-Jun-2009 17:59:18   

lethologica wrote:

I am using the v2.0.50727 runtime.

That's the .NET version, please check: http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=7725

Frans Bouma | Lead developer LLBLGen Pro
Posts: 112
Joined: 09-Aug-2004
# Posted on: 15-Jun-2009 18:03:11   

Ohh, the version of the ORM classes is 2.6.0.0 (Is this different from 2.6 final?)

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39859
Joined: 17-Aug-2003
# Posted on: 15-Jun-2009 18:24:52   

lethologica wrote:

Ohh, the version of the ORM classes is 2.6.0.0 (Is this different from 2.6 final?)

Heh the BUILD nr simple_smile Right mouse button on dll in explorer, -> Properties -> Version tab -> file version simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Posts: 112
Joined: 09-Aug-2004
# Posted on: 15-Jun-2009 19:18:06   

Wow sorry, its a monday, its version 2.6.8.1013.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39859
Joined: 17-Aug-2003
# Posted on: 15-Jun-2009 20:29:23   

lethologica wrote:

Wow sorry, its a monday, its version 2.6.8.1013.

that's a very old one, could you please download hte latest build of the runtime libs from the customer area and check whether the problem still persists?

Frans Bouma | Lead developer LLBLGen Pro
Posts: 112
Joined: 09-Aug-2004
# Posted on: 15-Jun-2009 20:50:56   

I just gave it a try with 2.6.9.511 and I got the same results with the sample project I attached.

The way the sample works is it displays the Count of entities when you click on each button. I would expect both to return 2.

Posts: 112
Joined: 09-Aug-2004
# Posted on: 15-Jun-2009 21:03:00   

Ignore this message (but not the thread).

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 16-Jun-2009 06:06:14   

I can reproduce it, but in my opinion, this is expected. Why add the the root prefetchpath entity as a subentity, in the first place? simple_smile

This is what is happening:

  1. The root collection is fetched (Customer)
  2. The fetch routine detects that there is a PrefetchPath.
  3. Fetch the entities of the PrefetchPath. (Order)
  4. Merge the entities of the prefetchPath (Order) with the root entities (Customer)
  5. The fetch routine detects that there is a SubPath
  6. Fetch the entities of the SubPath (Customer, again)
  7. Merge the entities of the SubPath (Customer) with the root entities (Order). At this point, the root entity is Order and the prefetchPath entity is Customer (note that this is a new customer instance, different form the customer at step 1). Then this line is reached at OrderEntity.cs:
case "Customer":
     this.Customer = (CustomerEntity)entity;

Before this line is reached, this.Customer already have a reference to the original Customer (fetched at step 1), and after that, the customer object is assigned to another instance, the synchronization takes care of Unset the original Customer of the Order, and remove that order from the customer.Order collection as well. That's why you don't see any orders at all.

Also note that in your example, you are fetching the same Customers twice.

The bottom line is Why are you doing this? simple_smile Is there any special reason you want to achieve such thing?

David Elizondo | LLBLGen Support Team
Posts: 112
Joined: 09-Aug-2004
# Posted on: 16-Jun-2009 14:22:33   

Ohh, I see what is happening.

I can't think of a legitimate reason for doing this. A team member accidentally created a path like this twice so I wanted to understand the problem a little more.

Now that I see exactly what is happening, (A references B), (B references C which dereferences A) where C is a copy of A, I am not sure what the desired behavior should be.

Would it make sense in the Fetch logic to check if an entity already references another which was set in the same Fetch?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39859
Joined: 17-Aug-2003
# Posted on: 17-Jun-2009 10:43:47   

It would, but it's an ambiguistic piece of code, because what if you want to fetch new entities at the spot of the old ones? In that case you want to have this scenario. It's therefore not clear what should be done. As the extra path is redundant, it can be ignored.

The question then arises of course: why isn't the redundant path node ignored? That's something we could look into and do more optimal graph fetching, as it is currently not doing any optimization whatsoever. Specifying a graph in code is sometimes awkward and it's not always directly clear what the end result will be. The prefetch path logic assumes that the path specified is correct and optimal, but that is sometimes not the case. We could add checks for that in the future. It will cause some other problems to solve but it could be more optimal than it is now.

Frans Bouma | Lead developer LLBLGen Pro