ORMQueryExecutionException thrown by a prefetching operation

Posts   
 
    
putnam
User
Posts: 2
Joined: 08-Jun-2005
# Posted on: 08-Jun-2005 04:22:30   

I'm just beginning to learn how to use prefetches, so you will probably tear me apart.

I'm getting this ORMQueryExecutionException:

Exception:

An exception was caught during the execution of a retrieval query: The column prefix 'ITSCAKE2.dbo.User' does not match with a table name or alias name used in the query. The column prefix 'ITSCAKE2.dbo.Application' does not match with a table name or alias name used in the query.. Check InnerException, QueryExecuted and Parameters of this exception to examine the cause of this exception.

Inner Exception:

System.Data.SqlClient.SqlException: The column prefix 'ITSCAKE2.dbo.User' does not match with a table name or alias name used in the query.
The column prefix 'ITSCAKE2.dbo.Application' does not match with a table name or alias name used in the query.
   at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream)
   at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior)
   at System.Data.SqlClient.SqlCommand.System.Data.IDbCommand.ExecuteReader(CommandBehavior behavior)
   at SD.LLBLGen.Pro.ORMSupportClasses.RetrievalQuery.Execute(CommandBehavior behavior)

Query:

SELECT [ITSCAKE2].[dbo].[ApplicationInstance].[ApplicationInstanceID] AS [ApplicationInstanceId],[ITSCAKE2].[dbo].[ApplicationInstance].[ClientID] AS [ClientId],[ITSCAKE2].[dbo].[ApplicationInstance].[ApplicationID] AS [ApplicationId],[ITSCAKE2].[dbo].[ApplicationInstance].[Active] AS [Active],[ITSCAKE2].[dbo].[ApplicationInstance].[Enabled] AS [Enabled],[ITSCAKE2].[dbo].[ApplicationInstance].[AdminLinkName] AS [AdminLinkName],[ITSCAKE2].[dbo].[ApplicationInstance].[WebsiteID] AS [WebsiteId],[ITSCAKE2].[dbo].[ApplicationInstance].[VirtualPath] AS [VirtualPath] FROM [ITSCAKE2].[dbo].[ApplicationInstance]  WHERE ( [ITSCAKE2].[dbo].[User].[UserID] = @UserId1 And [ITSCAKE2].[dbo].[Application].[HideAdmin] = @HideAdmin2)
    Parameter: @UserId1 : Int32. Length: 0. Precision: 10. Scale: 0. Direction: Input. Value: 10.
    Parameter: @HideAdmin2 : Boolean. Length: 0. Precision: 1. Scale: 0. Direction: Input. Value: False.

Whenever I call this function in my UserEntity class:

public EntityCollection GetAdminApplications()
        {
            ////////////////////////////////////////////////////////////////
            /// Retrieve all AdminApplicationTypedView objects that have this UserID
            IPrefetchPath2 prefetchPath = new PrefetchPath2((int)EntityType.ApplicationInstanceEntity);
            prefetchPath.Add(ApplicationInstanceEntity.PrefetchPathApplication);
            prefetchPath.Add(ApplicationInstanceEntity.PrefetchPathApplicationRole).SubPath.Add(ApplicationRoleEntity.PrefetchPathUser);
            IRelationPredicateBucket filter = new RelationPredicateBucket();
            filter.PredicateExpression.Add(
                PredicateFactory.CompareValue(UserFieldIndex.UserId, ComparisonOperator.Equal, this.UserId));
            filter.PredicateExpression.Add(
                PredicateFactory.CompareValue(ApplicationFieldIndex.HideAdmin, ComparisonOperator.Equal, false));
            EntityCollection aiCollection = new EntityCollection(new ApplicationInstanceEntityFactory());
            DataAccessAdapter adapter = new DataAccessAdapter();
            adapter.FetchEntityCollection(aiCollection, filter, prefetchPath);
            return aiCollection;
}

I'm totally lost on what could be causing this. Can anyone pick out what the problem is here?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 08-Jun-2005 12:05:29   

When you're using a prefetch path, to fetch a graph of objects, in your case ApplicationInstance - Application and ApplicationInstance - ApplicationRole - User, for each node a query is used. If you want to use a filter on a node, for example, you want to fetch only the users with a given surname, you have to specify the filter for that when you call 'Add()' to add the prefetch path node.

You want to filter on the user 'this.UserId'. What exactly do you want to do: fetch the rest of the graph normally and only for the User fetch you want to specify this filter (in that case, specify the predicate expression when calling Add() on the SubPath), or do you want to limit the complete graph for this user? In that case, you should use the filter on the ROOT of the graph, ApplicationInstance. You already do that in your code, though you forget to apply the relations to do the filtering. You've to specify the filter's relations as well, i.e.: ApplicationInstance - ApplicationRole and ApplicationRole - user, and add them to filter.RelationCollection.

That will result in the usage of these joins in all node fetches. To be more efficient, build your graph from the other side: fetch User and it's related ApplicationRoles - ApplicationInstance and that applicationInstance's Application object. That way you just have to specify the filter for the user id, and your query is much simpler and yet, you can traverse the graph from user to applicationinstance without a problem, using user.ApplicationRoles[0].ApplicationInstance. Please supply a Context object when fetching the graph using FetchEntity(user) so you'll get unique objects. simple_smile

Frans Bouma | Lead developer LLBLGen Pro
putnam
User
Posts: 2
Joined: 08-Jun-2005
# Posted on: 12-Jun-2005 00:49:05   

Thanks for your help Otis. I've got the code working now but I am not sure what you meant by using a context object. Here is what I changed my code to:

        public EntityCollection GetAdminApplications()
        {           
            // Build the prefetchPath - root node (User)
            IPrefetchPath2 prefetchPath = new PrefetchPath2((int)EntityType.UserEntity);
            
            // Add the second node (ApplicationRole)
            IPrefetchPathElement2 secondNode = prefetchPath.Add(UserEntity.PrefetchPathApplicationRole);
            
            // Add the third node (ApplicationInstance)
            IPrefetchPathElement2 thirdNode = secondNode.SubPath.Add(ApplicationRoleEntity.PrefetchPathApplicationInstance);

            // Add the fourth node (Application)
            IPrefetchPathElement2 fourthNode = thirdNode.SubPath.Add(ApplicationInstanceEntity.PrefetchPathApplication);
            // Filter the fourth node so we only get admin applications
            IPredicateExpression adminfilter = new PredicateExpression(PredicateFactory.CompareValue(ApplicationFieldIndex.HideAdmin, ComparisonOperator.Equal, false));
            fourthNode.Filter.Add(adminfilter);

            // Instantiate filter for the fetching operation
            IRelationPredicateBucket filter = new RelationPredicateBucket();
                
            // Add relation for ApplicationRole-ApplicationInstance and ApplicationInstance-Application
            filter.Relations.Add(ApplicationRoleEntity.Relations.ApplicationInstanceEntityUsingApplicationInstanceId);
            filter.Relations.Add(ApplicationInstanceEntity.Relations.ApplicationEntityUsingApplicationId);
            filter.Relations.Add(UserEntity.Relations.ApplicationRoleEntityUsingUserId);
        
            // Only retrieve the userid we want - Root filtering occurs during the fetchentitycollection call
            filter.PredicateExpression.Add( new PredicateExpression(PredicateFactory.CompareValue(UserFieldIndex.UserId, ComparisonOperator.Equal, this.UserId)) );
            
            // Instantiate collection to fill and return
            EntityCollection aiCollection = new EntityCollection(new ApplicationInstanceEntityFactory());
            
            // Perform data fetching with adapter
            DataAccessAdapter adapter = new DataAccessAdapter();
            adapter.FetchEntityCollection(aiCollection, filter, prefetchPath);
            return aiCollection;
        }

I'm able to get all the objects I need, but when I try to reference an object through an instance, like say aiCollection[0].Application, it is not set to an instance of an object.

What am I missing to get access to these objects?

I am getting unique objects with this code. Is the context necessary?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 12-Jun-2005 14:27:50   

You specify the prefetch path from User as the starting point, though you fetch applications in a collection, i.e. 'application' is the starting point. That's not correct. You should fetch the USER, then traverse the graph till you reach application. (user -> application role -> ApplicationInstance -> Application.)

If you specify a Context object, every 'Application' object is the same instance. Otherwise the same data could end up in multiple application objects (though through teh nature how prefetch paths are used internally I don't think that will be the case here).

Frans Bouma | Lead developer LLBLGen Pro