使用.NET中的类型化数据集将SQL参数传递给IN()子句

Sim*_*mon 13 c# sql parameter-passing strongly-typed-dataset

首先道歉,因为这个网站上有类似的问题,但没有一个直接回答这个问题.

我在VS 2010中使用了类型化数据集.我在数据集中创建一个TableAdapter,其查询类似于:

SELECT * from Table WHERE ID IN(@IDs)
Run Code Online (Sandbox Code Playgroud)

现在,如果我调用:TableAdapter.Fill(MyDataTable,"1,2,3")发生错误,说明VS无法将1,2,3转换为int类型.很公平.

那么我决定将参数(即@IDs)类型更改为参数集合中的字符串.再试一次 - 仍然是相同的错误消息.

那么这种类型的数据集是否可以接受我的"1,2,3"参数?目前我只有一些参数可以通过,所以我可以很容易地创建5个左右的参数并单独传递它们,但是如果有数百个呢?有没有办法Fill()用逗号分隔参数调用方法?

(我知道我可以使用动态SQL来创建语句并执行它但更喜欢是否有另一种方式允许我保留我的类型化数据集以用于例如ReportViewer/bindingsources)

Joe*_*Joe 10

您不能以这种方式将单个参数用于值列表.但是可能有特定于数据库的方法来实现您想要的.例如,使用SQL Server 2005或更高版本,您可以创建一个表值函数来拆分字符串参数,例如:

CREATE FUNCTION dbo.F_Split
(
@InputString VARCHAR(MAX)
,@Separator VARCHAR(MAX)
)
RETURNS @ValueTable TABLE (Value VARCHAR(MAX))
AS
BEGIN

    DECLARE @SeparatorIndex INT, @TotalLength INT, @StartIndex INT, @Value VARCHAR(MAX)
    SET @TotalLength=LEN(@InputString)
    SET @StartIndex = 1

    IF @Separator IS NULL RETURN

    WHILE @StartIndex <= @TotalLength
    BEGIN
        SET @SeparatorIndex = CHARINDEX(@Separator, @InputString, @StartIndex)
        IF @SeparatorIndex > 0
        BEGIN
            SET @Value = SUBSTRING(@InputString, @StartIndex, @SeparatorIndex-@StartIndex)
            SET @StartIndex = @SeparatorIndex + 1
        END
        ELSE
        BEGIN
            Set @Value = SUBSTRING(@InputString, @StartIndex, @TotalLength-@StartIndex+1)
            SET @StartIndex = @TotalLength+1
        END
        INSERT INTO @ValueTable
        (Value)
        VALUES
        (@Value)
    END

    RETURN
END
Run Code Online (Sandbox Code Playgroud)

然后您将按如下方式使用它:

SELECT * from Table WHERE ID IN (SELECT CAST(Value AS INT) FROM F_Split(@IDs, ','))
Run Code Online (Sandbox Code Playgroud)


ter*_*enf 9

我尝试了一种解决方法,以SQL方式使用字符串"包含"概念:

在你的情况下,更改SQL -

原版的:

SELECT*来自表WHERE ID IN(@IDs)

成为:

SELECT*from Table WHERE CharIndex(','+ Cast(ID As Varchar(10))+',',@ IDs)> 0

使用.net代码 -

原版的:

TableAdapter.Fill(MyDataTable, "1,2,3")

成为:

TableAdapter.Fill(MyDataTable," ,1,2,3, ")


Sim*_*ier 6

SQL Server 2008具有一个名为Table-Valued Parameters的功能

所以你需要

  1. 将您的查询定义为 SELECT * from Table WHERE ID IN (SELECT * FROM (@IDs))
  2. 返回Visual Studio中的TableAdapter可视化设计器,并更新@IDS参数以修改@IDS参数,如DbType = Object和ProviderType = Structured
  3. 在您正在使用的数据库中运行此SQL批处理:CREATE TYPE MyIntArray AS TABLE ( Value INT );GO.这将创建一个只有一列INT类型的MyIntArray"表类型".
  4. 现在最棘手的是将"MyIntArray"类型传递给ADO.NET端的TableAdapter.

不幸的是,Table Adapter设计器不支持该SqlParameter.TypeName参数,因此我们需要自己修复它.目标是修改CommandCollection生成的TableAdapter类的属性.不幸的是,这个属性是受保护的,所以你必须派生TableAdapter或者例如使用Reflection来调整它.以下是派生类的示例:

    public class MyTableAdapter2 : MyTableAdapter
    {
        public MyTableAdapter2()
        {
            SqlCommand[] cmds = base.CommandCollection;
            // here, the IDS parameter is index 0 of command 1
            // you'll have to be more clever, but you get the idea
            cmds[1].Parameters[0].TypeName = "MyIntArray";
        }
    }
Run Code Online (Sandbox Code Playgroud)

这就是你可以调用这个方法的方法:

        MyTableAdapter t = new MyTableAdapter2();

        // create the TVP parameter, with one column. the name is irrelevant.
        DataTable tvp = new DataTable();
        tvp.Columns.Add();

        // add one row for each value
        DataRow row = tvp.NewRow();
        row[0] = 1;
        tvp.Rows.Add(row);

        row = tvp.NewRow();
        row[0] = 2;
        tvp.Rows.Add(row);

        row = tvp.NewRow();
        row[0] = 3;
        tvp.Rows.Add(row);

        t.Fill(new MyDataTable(), tvp);
Run Code Online (Sandbox Code Playgroud)