2011-05-17 50 views
1

我得到错误过程或函数'getfoo2'需要参数'@x',它没有提供。错误:'程序或函数'getfoo2'需要参数'@x',它没有提供。'当它提供

当我在File1.fs的第156行设置断点并检查foo2的内容(它是我的DbCommand对象)时,参数集合包含我的参数@x和@y。他们都有正确的DbType和值集。所以我不知道去哪里寻找我的问题。 这是一个错误,还是我错过了我的代码中的其他地方?我已经发布了数据库的sql,我的f @ File1.fs,Program.fs和app.config。 File1.fs在项目中的Program.fs之前。

我的系统是:

  • Microsoft SQL Server的开发版(64位)版本10.0.4000.0
  • Windows 7专业版SP1
  • 的Visual Studio 2010 SP1

下面是源代码:

存储过程,表格和样本数据:

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> 
+1

我看不出您的代码有任何明显的问题。你有没有尝试使用SQL Profiler进行分析?这应该向您展示存储过程调用及其传递的参数。 – Robert 2011-05-17 08:08:26

+1

一致认为,虽然你可能想要在'CreateProcedure'中明确地设置'cmd.CommandType'到'CommandType.StoredProcedure',这对我来说看起来很好。 – ildjarn 2011-05-17 18:11:52

+0

@ildjarn - 你应该让你的评论一个答案,所以我可以将其标记为答案。大声笑。我不敢相信我错过了! – 2011-05-18 01:46:06

回答

2

(从评论转贴)

你的代码看起来虽然你可能想在CreateProcedure的内部明确地设置cmd.CommandTypeCommandType.StoredProcedure

相关问题