开发者

Error: 'Procedure or function 'getfoo2' expects parameter '@x', which was not supplied.' when it is supplied

I'm getting the error Procedure or function 'getfoo2' expects parameter '@x', which was not supplied.

When I set a breakpoint on line 156 in File1.fs and examine the contents of foo2, which is my DbCommand object, the parameters collection contains both of my parameters @x and @y. They both have the correct DbType and value set. So I have no idea where to look to find my problem. Is this a bug, or am I missing something somewhere else in my code? I have posted the sql for the database, my f@ File1.fs, Program.fs, and the app.config. File1.fs comes before Program.fs in the project.

My system is:

  • Microsoft SQL Server Developer Edition (64-bit) version 10.0.4000.0
  • Windows 7 Professional SP1
  • Visual Studio 2010 SP1

Below is the source code:

stored proc, table, and sample data:

    IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[getfoo2]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[getfoo2]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

    CREATE PROCEDURE [dbo].[getfoo2] 
        @x int, 
        @y varchar(15)
    AS
    BEGIN
        SET NOCOUNT ON;

        select x,y,z from foo
        where
            x = @x
        and
            y = @y
    END
GO


IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[foo]') AND type in (N'U'))
DROP TABLE [dbo].[foo]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO

CREATE TABLE [dbo].[foo](
    [x] [int] NOT NULL,
    [y] [varchar](15) NOT NULL,
    [z] [datetime] NULL
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

insert into foo (x,y,z) values (1,'a',NULL)
insert into foo (x,y,z) values (1,'b','Jan  1 2001 12:00AM')
insert into foo (x,y,z) values (1,'c','Jan  2 2002 12:00AM')
insert into foo (x,y,z) values (2,'a','Feb  1 2001 12:00AM')
insert into foo (x,y,z) values (2,'b',NULL)
insert into foo (x,y,z) values (2,'c','Feb  2 2001 12:00AM')
insert into foo (x,y,z) values (3,'a','Mar  1 2001 12:00AM')
insert into foo (x,y,z) values (3,'b','Mar  2 2001 12:00AM')
insert into foo (x,y,z) values (3,'c',NULL)

GO

File1.fs

module File1

open System.Configuration
open System.Data.Common
open System.Data


type Direction =
| In
| Out
| Ref
| Return

type DbType =
| AnsiString of int
| AnsiStringFixedLength of int
| Binary of int
| Boolean
| Byte
| Currency
| Date
| DateTime
| DateTime2
| DateTimeOffset
| Decimal
| Double
| Guid
| Int16
| Int32
| Int64
| Object of int
| SByte
| Single
| String of int
| StringFixedLength of int
| Time
| UInt16
| UInt32
| UInt64
| VarNumeric of int
| Xml of int

type Db(cnnName:string) =
    let config = ConfigurationManager.ConnectionStrings.[cnnName]
    let factory = System.Data.Common.DbProviderFactories.GetFactory(config.ProviderName)

    let (|HasSize|NoSize|) p =
        match p with
        // no size
        | Boolean -> NoSize(System.Data.DbType.Boolean)
        | Byte -> NoSize(System.Data.DbType.Byte)
        | Currency -> NoSize(System.Data.DbType.Currency)
        | Date -> NoSize(System.Data.DbType.Date)
        | DateTime -> NoSize开发者_如何学运维(System.Data.DbType.DateTime)
        | DateTime2 -> NoSize(System.Data.DbType.DateTime2)
        | DateTimeOffset -> NoSize(System.Data.DbType.DateTimeOffset)
        | Decimal -> NoSize(System.Data.DbType.Decimal)
        | Double -> NoSize(System.Data.DbType.Double)
        | Guid -> NoSize(System.Data.DbType.Guid)
        | Int16 -> NoSize(System.Data.DbType.Int16)
        | Int32 -> NoSize(System.Data.DbType.Int32)
        | Int64 -> NoSize(System.Data.DbType.Int64)
        | SByte -> NoSize(System.Data.DbType.SByte)
        | Single -> NoSize(System.Data.DbType.Single)
        | Time -> NoSize(System.Data.DbType.Time)
        | UInt16 -> NoSize(System.Data.DbType.UInt16)
        | UInt32 -> NoSize(System.Data.DbType.UInt32)
        | UInt64 -> NoSize(System.Data.DbType.UInt64)
        // has size
        | AnsiString(x) -> HasSize(System.Data.DbType.AnsiString,x)
        | AnsiStringFixedLength(x) -> HasSize(System.Data.DbType.AnsiStringFixedLength,x)
        | Binary(x) -> HasSize(System.Data.DbType.Binary,x)
        | Object(x) -> HasSize(System.Data.DbType.Object,x)
        | String(x) -> HasSize(System.Data.DbType.String,x)
        | StringFixedLength(x) -> HasSize(System.Data.DbType.StringFixedLength,x)
        | VarNumeric(x) -> HasSize(System.Data.DbType.VarNumeric,x)
        | Xml(x) -> HasSize(System.Data.DbType.Xml,x)

    let dbDir (p:Direction) =
        match p with
        | In -> System.Data.ParameterDirection.Input
        | Out -> System.Data.ParameterDirection.Output
        | Ref -> System.Data.ParameterDirection.InputOutput
        | Return -> System.Data.ParameterDirection.ReturnValue

    member x.CreateProcedure(name) =
        let cmd = factory.CreateCommand()
        let cn = factory.CreateConnection()
        cn.ConnectionString <- config.ConnectionString
        cmd.Connection <- cn
        cmd.CommandText <- name
        cmd

    member x.CreateParameter(name:string,typ:DbType,dir:Direction) =
        let p = factory.CreateParameter()
        if name.StartsWith("@") then
            p.ParameterName <- name
        else
            p.ParameterName <- "@" + name
        p.Direction <- dbDir dir
        match typ with
        | HasSize(t,s) -> 
            p.DbType <- t
            p.Size <- s
        | NoSize(t) -> p.DbType <- t
        p

type Foo() =
    let mutable x:int = 0
    let mutable y:string = ""
    let mutable z:option<System.DateTime> = None

    member a.X with get() = x and set n = x <- n

    member a.Y with get() = y and set n = y <- n

    member a.Z with get() = z and set n = z <- n

let db = Db("db")

let proc name (parameters:list<string*DbType*Direction>) = 
    let cmd = db.CreateProcedure(name)
    let param p =
        db.CreateParameter p
        |> cmd.Parameters.Add
        |> ignore
    List.iter param parameters
    cmd



let (?<-) (cmd:DbCommand) (s:string) (value:'a) =
    cmd.Parameters.["@" + s].Value <- value 

let (<|>) (value:option<'a>) (replacement:'a) = 
    match value with
    | Some(x) -> x
    | _ -> replacement

let (?) (r:DbDataReader) (s:string) : option<'a> =
    let index = r.GetOrdinal s
    match r.IsDBNull index  with
    | true -> None
    | _ -> r.GetValue index
        :?> 'a
        |> Some

let foo x y =
    let foo2 = proc "getfoo2" 
             <| [ ("x",Int32,In);
                  ("y",String(15),In) ]
    foo2?x <- x
    foo2?y <- y
    try
        foo2.Connection.Open()
        use r = foo2.ExecuteReader()
        [
            while r.Read() do
                let item = Foo()
                item.X <- (r?x) <|> 1
                item.Y <- (r?y) <|> ""
                item.Z <- r?z
                yield item
        ]
    finally
        foo2.Connection.Close()

Program.fs

open System
open System.Data
open System.Data.Common
open System.Configuration
open File1

let config = ConfigurationManager.ConnectionStrings.Item("db")
let factory = DbProviderFactories.GetFactory(config.ProviderName)


[<EntryPoint>]
let main (args : string[]) =
    let foo1a = foo 1 "a"
    let foo1b = foo 1 "b"
    let foo1c = foo 1 "c"

    for f in foo1a do
        let mutable z = DateTime.Now
        match f.Z with
        | Some(x) -> z <- x
        | None -> z <- DateTime.MinValue
        printfn "%d : %s : %O" f.X f.Y z
    // program exit code
    0

app.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <connectionStrings>
    <add name="db" providerName="System.Data.SqlClient" connectionString="server=(local);uid=;pwd=;Trusted_Connection=yes;database=scratchPad"/>
  </connectionStrings>
</configuration>


(Reposting from comment)

Your code looks generally fine to me, although you may want to explicitly set cmd.CommandType to CommandType.StoredProcedure inside of CreateProcedure.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜