Generated SQL has inconsistant use of alias, causing exception

Posts   
 
    
Posts: 98
Joined: 10-Nov-2006
# Posted on: 31-May-2012 22:17:07   

This is using LLBLGen 3.5, Self Servicing. I downloaded the latest version today.

QuerySpec.dll version: 3.5.12.0522 ORMSupporterClasses.NET20.dll version: 3.5.12.0507

I have the following code:


            qf = new QueryFactory();
            new TypedListDAO().FetchQuery(
                qf.Create()
                    .From(qf.Supporter.InnerJoin(qf.Project).On(SupporterFields.ClientId == ProjectFields.ClientId))
                    .Where(SupporterFields.SupporterId == 3)
                    .Select(() => new { ProjectId = ProjectFields.ProjectId.ToValue<int>() })
                );

The "Project" entity is at the root of a TargetPerEntity hierarchy.

The SQL generated is this:


SELECT [myDB].[dbo].[ap_Project].[ProjectId]
FROM   ( [myDB].[dbo].[ap_Supporter]
         INNER JOIN [myDB].[dbo].[ap_Project] [LPA_L1]
             ON [myDB].[dbo].[ap_Supporter].[ClientId] = [myDB].[dbo].[ap_Project].[ClientId])
WHERE  ((([myDB].[dbo].[ap_Supporter].[SupporterId] = @p1))) 

The Error is:


Message: The multi-part identifier "myDB.dbo.ap_Project.ClientId" could not be bound.

Note that in the JOIN, the ap_Project table has been given the alias of "LPA_L1", but that alias was not used in the select, which causes the error.

I can work around this by specifying an alias manually (same code, just use alias of "P"):


            qf = new QueryFactory();
            new TypedListDAO().FetchQuery(
                qf.Create()
                    .From(qf.Supporter.InnerJoin(qf.Project.As("P")).On(SupporterFields.ClientId == ProjectFields.ClientId.Source("P")))
                    .Where(SupporterFields.SupporterId == 2)
                    .Select(() => new { ProjectId = ProjectFields.ProjectId.Source("P").ToValue<int>() })
                );

Generates proper SQL:


SELECT [LPA_P1].[ProjectId]
FROM   ( [myDB].[dbo].[ap_Supporter]
         INNER JOIN [myDB].[dbo].[ap_Project] [LPA_P1]
             ON [myDB].[dbo].[ap_Supporter].[ClientId] = [LPA_P1].[ClientId])
WHERE  ((([myDB].[dbo].[ap_Supporter].[SupporterId] = @p1))) 

Similar code where I join an entity that is not part of a TargetPerEntity hierarchy does not show the problem (join to Name instead of Project):


    qf = new QueryFactory();
            new TypedListDAO().FetchQuery(
                qf.Create()
                    .From(qf.Supporter.InnerJoin(qf.Name).On(SupporterFields.NameId == NameFields.NameId))
                    .Where(SupporterFields.SupporterId == 1)
                    .Select(() => new { NameId = NameFields.NameId.ToValue<int>() })
                );


SQL:


SELECT [myDB].[dbo].[ap_Name].[NameId]
FROM   ( [myDB].[dbo].[ap_Supporter]
         INNER JOIN [myDB].[dbo].[ap_Name]
             ON [myDB].[dbo].[ap_Supporter].[NameId] = [myDB].[dbo].[ap_Name].[NameId])
WHERE  (((myDB].[dbo].[ap_Supporter].[SupporterId] = @p1))) 

For this reason, I'm thinking that this may have to do with the fact that ap_Project is part of a TargetPerEntity hierarchy, but that's just a guess - it might have to do with something else. And I'm seeing this with QuerySpec code - not sure if that's a factor or not.

Thanks,

Wes

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 01-Jun-2012 08:47:31   

I reproduced it, using InheritanceOne db. This happens in SelfServicing and Adapter, with the latest v3.5. This is the code:

var qf = new QueryFactory();
var query = qf.Create()
        .From(
            qf.Department
            .InnerJoin(qf.Employee)
                .On(DepartmentFields.DepartmentId == EmployeeFields.WorksForDepartmentId))
    .Where(DepartmentFields.DepartmentType == 1)
    .Select(() => new { EmployeeId = EmployeeFields.EmployeeId.ToValue<int>() });

We will look into it. In the meantime, use your workaround. This also seems to work (Specifying the IEntityRelation object):

var query = qf.Create()
        .From(
            qf.Department
            .InnerJoin(DepartmentEntity.Relations.EmployeeEntityUsingWorksForDepartmentId))
    .Where(DepartmentFields.DepartmentType == 1)
    .Select(() => new { EmployeeId = EmployeeFields.EmployeeId.ToValue<int>() });
David Elizondo | LLBLGen Support Team
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 01-Jun-2012 10:23:53   

When no alias is specified, it auto-aliases the elements. Apparently it doesn't work properly in this situation. Not sure whether this is an issue that's specific to queryspec or that it's a side effect of the Join being converted to a dynamic relation, which doesn't have auto-aliasing. We'll look into it.

Btw, the problem is in the ON clause as well, not only in the select.

(edit) Fails with low-level api as well. It's a problem with DynamicRelation, which doesn't auto-alias sides, as it has a CTor which forces the user to specify an alias. disappointed

(edit) interestingly enough, the linq query works and does the aliasing properly, because it works with sources which always get an alias assigned. In queryspec, that's not the case.

var metaData = new LinqMetaData(adapter);
var q = from d in metaData.Department
        join e in metaData.Employee on d.DepartmentId equals e.WorksForDepartmentId
        where d.DepartmentType == "1"
        select new { EmployeeId = e.Id };

The auto-aliasing, built into the EntityRelation should be usable here though, but we have to check whether that's possible.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 01-Jun-2012 11:34:42   

It was an ordinairy BUG in the dynamicrelationbase class. (true should have been false!). Fixed in next build, which is released in a few hours simple_smile

Frans Bouma | Lead developer LLBLGen Pro