SQLProvider icon indicating copy to clipboard operation
SQLProvider copied to clipboard

Unexpected composed query behavior

Open halcwb opened this issue 4 years ago • 2 comments
trafficstars

Describe the bug When using composed queries an unexpected behavior occurs when a join is involved in a query. This results in a select with wrong values. See code examples below.

To Reproduce

let ctx = DataContext.getDataContextWithLog()

// === normal query with expected result
query { 
    for p in ctx.Dbo.Parameters do
    join c in ctx.Dbo.ParametersCategories on 
            (p.CategoryId = c.CategoryId)
    select p
} 
|> Seq.toList
|> List.take 3        
|> List.map (fun p -> p.ParameterId, p.ParameterName)
// Result:
// val it : (int16 * string) list =
//   [(3743s, "Allerg (T1) IgE-totaal"); (3744s, "Allerg (T1) Tryptase");
//    (3745s, "Allerg (T1) Huisstofmijt")]

// === composed query with unexpected result
let get (ctx : DataContext.sql.dataContext) =
    <@ fun _ ->
        query { 
            for p in ctx.Dbo.Parameters do
            join c in ctx.Dbo.ParametersCategories on 
                    (p.CategoryId = c.CategoryId)
            select (p)
        } @>

query {
for (p) in ((%get ctx) ()) do
    select (p.ParameterId, p.ParameterName)
}
|> Seq.toList
|> List.take 3        
// Result:
// val get :
//   ctx:FSharp.Data.Sql.SqlDataProvider<...>.dataContext ->
//     Quotations.Expr<('a ->
//                        Linq.IQueryable<FSharp.Data.Sql.SqlDataProvider<...>.dataContext.dbo.ParametersEntity>)>
// val it : (int16 * string) list = [(0s, ""); (0s, ""); (0s, "")]

// == composed query without join with expected result
let get (ctx : DataContext.sql.dataContext) =
    <@ fun _ ->
        query { 
            for p in ctx.Dbo.Parameters do
            // join c in ctx.Dbo.ParametersCategories on 
            //         (p.CategoryId = c.CategoryId)
            select (p)
        } @>

query {
for (p) in ((%get ctx) ()) do
    select (p.ParameterId, p.ParameterName)
}
|> Seq.toList
|> List.take 3        
// Result:
// val get :
//   ctx:FSharp.Data.Sql.SqlDataProvider<...>.dataContext ->
//     Quotations.Expr<('a ->
//                        Linq.IQueryable<FSharp.Data.Sql.SqlDataProvider<...>.dataContext.dbo.ParametersEntity>)>
// val it : (int16 * string) list =
//   [(3743s, "Allerg (T1) IgE-totaal"); (3744s, "Allerg (T1) Tryptase");
//    (3745s, "Allerg (T1) Huisstofmijt")]

// == composed query with a tuple return with a 'dummy' unit value returns expected result!?
let get (ctx : DataContext.sql.dataContext) =
    <@ fun _ ->
        query { 
            for p in ctx.Dbo.Parameters do
            join c in ctx.Dbo.ParametersCategories on 
                    (p.CategoryId = c.CategoryId)
            select (p, ())
        } @>

query {
for (p, _) in ((%get ctx) ()) do
    select (p.ParameterId, p.ParameterName)
}
|> Seq.toList
|> List.take 3        
// Result:
// val it : (int16 * string) list =
//   [(3743s, "Allerg (T1) IgE-totaal"); (3744s, "Allerg (T1) Tryptase");
//    (3745s, "Allerg (T1) Huisstofmijt")]

Expected behavior Clearly the second query result is inconsistent with the other queries.

Desktop (please complete the following information): .NET SDK (reflecting any global.json): Version: 5.0.202 Commit: db7cc87d51

Runtime Environment: OS Name: Windows OS Version: 10.0.17763 OS Platform: Windows RID: win10-x64 Base Path: C:\Program Files\dotnet\sdk\5.0.202\

Host (useful for support): Version: 5.0.5 Commit: 2f740adc14

.NET SDKs installed: 5.0.200-preview.21077.7 [C:\Program Files\dotnet\sdk] 5.0.201 [C:\Program Files\dotnet\sdk] 5.0.202 [C:\Program Files\dotnet\sdk]

halcwb avatar May 19 '21 09:05 halcwb

Just a quick look into this one, it seems that something in this.ReadEntities goes wrong:

  • The SQL-query is correct as far as I know, SELECT [p].[MYCOLUMN_ID] as '[p].[MYCOLUMN_ID]' ..., it probably leaves the alias p as how would the SQL know which table is it used for (as multiple tables can have same name columns)
  • SqlRuntime.DataContext.fs e.SetColumnSilent(reader.GetName(i),value) sets a correct value, but GetName(0) returns the full [p].[MYCOLUMN_ID]
  • Then later it will be tried to fetch with GetColumn by only the alias MYCOLUMN_ID which is not in that dictionary, because it has the full alias and not the column-name only.

Thorium avatar Jun 28 '21 16:06 Thorium

@Thorium So, is this something you can reproduce? Or do you need the generated SQL output?

halcwb avatar Jul 07 '21 12:07 halcwb