What happens if I use `AndExpression` without `CloseExpression`

114 Views Asked by At

I have this subsonic query:

Select.AllColumnsFrom<Data.Group>()
    .Where(Data.Group.GroupIDColumn).IsNotEqualTo(m_sRootGroupID)
    .AndExpression(Data.Group.Columns.OwnerPersonID).IsEqualTo(gUserID)
    .OrExpression(Data.Group.Columns.OwnerPersonID).IsEqualTo(gUserContextID)
    .AndExpression(Data.Group.Columns.IsCallList).IsEqualTo(true)
    .CheckLogicalDelete().ExecuteTypedList<Groups>();

At first sight, it seems that the previous developer has mistaken AndExpression for And. I know that AndExpression encloses the preceding statements inside parentheses.

How is the above subsonic query be translated into SQL?

This is what I'm thinking:

SELECT * 
FROM tblGroups
WHERE GroupID <> m_sRootGroupID
  AND ( --first [AndExpression]
    OwnerPersonID = `gUserID
    OR ( -- [OrExpression]
        OwnerPersonID = gUserContextID
        AND ( -- second [AndExpression]
             IsCallList = true
        )
    )
) -- first [AndExpression]
AND ISNULL(IsDeleted,0) = 0

How is the ..Expressions being handled if there is no CloseExpression?

2

There are 2 best solutions below

0
xGeo On BEST ANSWER

As has been pointed out by @MikeWalsh in his answer, calling .ToString() shows what the subsonic query looks like when translated to SQL.

Thus, the above code can be translated into:

SELECT * --subsonic specifies all columns

 FROM [dbo].[tblGroups]
 WHERE [dbo].[tblGroups].[GroupID] <> @GroupID0
 AND ([dbo].[tblGroups].[OwnerPersonID] = @OwnerPersonID1
)
 OR ([dbo].[tblGroups].[OwnerPersonID] = @OwnerPersonID3
)
 AND ([dbo].[tblGroups].[IsCallList] = @IsCallList5
)
 AND ([dbo].[tblGroups].[IsDeleted] IS NULL OR [dbo].[tblGroups].[IsDeleted] = 0)

Which tells us that calling AndExpression/OrExpression without a CloseExpression, subsonic assumes there is only one condition inside the AND statement enclosed in parentheses, thus:

.AndExpression(Data.Group.Columns.OwnerPersonID).IsEqualTo(gUserID)

is translated into: AND ([dbo].[tblGroups].[OwnerPersonID] = @OwnerPersonID1)


EDIT:

That's what I thought. However, when using this subsonic query:

Select.AllColumnsFrom<Data.Group>()
    .Where(Data.Group.GroupIDColumn).IsNotEqualTo(m_sRootGroupID)
    .AndExpression(Data.Group.Columns.OwnerPersonID).IsEqualTo("someownerID")
    .Or(Data.Group.Columns.OwnerPersonID).IsEqualTo("SomeContextID")
    .AndExpression(Data.Group.Columns.IsCallList).IsEqualTo(true)
    .CheckLogicalDelete().ToString();

I got this query (formatting mine):

SELECT <All columns>

 FROM [dbo].[tblGroups]
 WHERE [dbo].[tblGroups].[GroupID] <> @GroupID0
 AND ( -- first [AndExpression]
   [dbo].[tblGroups].[OwnerPersonID] = @OwnerPersonID1 --Data.Group.Columns.OwnerPersonID).IsEqualTo("someownerID")
   OR [dbo].[tblGroups].[OwnerPersonID] = @OwnerPersonID2 --.Or(Data.Group.Columns.OwnerPersonID).IsEqualTo("SomeContextID")
 ) -- close for first [AndExpression]
 AND ( -- second [AndExpression]
    [dbo].[tblGroups].[IsCallList] = @IsCallList4
 ) -- close for second [AndExpression]
 AND ([dbo].[tblGroups].[IsDeleted] IS NULL OR [dbo].[tblGroups].[IsDeleted] = 0)

As you can see, the first AndExpression includes .Or(Data.Group.Columns.OwnerPersonID).IsEqualTo("SomeContextID") inside its parentheses, which implies that ..Expression's continue to include preceding statements inside the parentheses until it finds another ..Expression (as we can observe on the second AndExpression.

Adding additional And/Or methods after the first AndExpression strengthens the proof that

Using ..Expression's without CloseExpression will encapsulate preceding statements in parentheses until another ..Expression is called.

1
Mike Walsh On

To get the emitted sql just call the ToString method of the query, which will call BuildSqlStatement.