diff --git a/src/SqlClient/ISqlCommand.fs b/src/SqlClient/ISqlCommand.fs index ec6b76a7..9832b98f 100644 --- a/src/SqlClient/ISqlCommand.fs +++ b/src/SqlClient/ISqlCommand.fs @@ -127,6 +127,22 @@ type ``ISqlCommand Implementation``(cfg: DesignTimeConfig, connection: Connectio | unexpected -> failwithf "Unexpected ResultType value: %O" unexpected + // Cached reflection for TVP (Table-Valued Parameter) handling. + // SetParameters is called on every command execution, so these lookups + // are lazily initialised once and reused across all calls. + static let tvpSqlDataRecordType = + lazy typeof.Assembly.GetType("Microsoft.SqlServer.Server.SqlDataRecord", throwOnError = true) + + static let tvpCastMethod = + lazy typeof.GetMethod("Cast").MakeGenericMethod(tvpSqlDataRecordType.Value) + + static let tvpAnyMethod = + lazy ( + typeof.GetMethods(BindingFlags.Static ||| BindingFlags.Public) + |> Array.tryFind (fun m -> m.Name = "Any" && m.GetParameters().Length = 1) + |> Option.map (fun m -> m.MakeGenericMethod(tvpSqlDataRecordType.Value)) + ) + member this.CommandTimeout = cmd.CommandTimeout interface ISqlCommand with @@ -228,21 +244,12 @@ type ``ISqlCommand Implementation``(cfg: DesignTimeConfig, connection: Connectio | _ -> match p.SqlDbType with | SqlDbType.Structured -> - // TODO: Maybe make this lazy? - - //p.Value <- value |> unbox |> Seq.cast - - //done via reflection because not implemented on Mono - - let sqlDataRecordType = typeof.Assembly.GetType("Microsoft.SqlServer.Server.SqlDataRecord", throwOnError = true) - let records = typeof.GetMethod("Cast").MakeGenericMethod(sqlDataRecordType).Invoke(null, [| value |]) - let hasAny = - let anyMeth = - typeof.GetMethods(BindingFlags.Static ||| BindingFlags.Public) - |> Array.tryFind(fun m -> m.Name = "Any" && m.GetParameters().Length = 1) - - match anyMeth with - | Some x -> x.MakeGenericMethod(sqlDataRecordType).Invoke(null, [| records |]) :?> bool + // Cast the sequence to IEnumerable via reflection. + // Done via reflection because SqlDataRecord is not available on all platforms (e.g. Mono). + let records = tvpCastMethod.Value.Invoke(null, [| value |]) + let hasAny = + match tvpAnyMethod.Value with + | Some anyMeth -> anyMeth.Invoke(null, [| records |]) :?> bool | None -> false p.Value <- if not hasAny then null else records | _ -> p.Value <- value