C# 使用.NET中的类型化数据集将SQL参数传递给IN()子句
首先道歉,因为在这个网站上有类似的问题,但没有人直接回答这个问题 我在VS2010中使用类型化数据集。我使用如下查询在数据集中创建TableAdapter:C# 使用.NET中的类型化数据集将SQL参数传递给IN()子句,c#,sql,parameter-passing,strongly-typed-dataset,C#,Sql,Parameter Passing,Strongly Typed Dataset,首先道歉,因为在这个网站上有类似的问题,但没有人直接回答这个问题 我在VS2010中使用类型化数据集。我使用如下查询在数据集中创建TableAdapter: SELECT * from Table WHERE ID IN(@IDs) 现在,如果我调用:TableAdapter.Fill(MyDataTable,“1,2,3”)会出现一个错误,说明VS无法将1,2,3转换为int.Fair类型 因此,我决定在参数集合中将参数(即@IDs)类型更改为string。重试-仍然显示相同的错误消息 那么
SELECT * from Table WHERE ID IN(@IDs)
现在,如果我调用:TableAdapter.Fill(MyDataTable,“1,2,3”)
会出现一个错误,说明VS无法将1,2,3转换为int.Fair类型
因此,我决定在参数集合中将参数(即@IDs)类型更改为string。重试-仍然显示相同的错误消息
那么,这个类型化数据集有没有办法接受我的“1,2,3”参数?目前我只有几个参数要传递,所以我可以轻松地创建5个左右的参数并分别传递它们,但是如果有数百个呢?有没有办法用逗号分隔的参数调用Fill()
方法
(我知道我可以使用动态SQL创建并执行该语句,但如果有其他方法允许我保留类型化数据集以供在ReportViewer/bindingsources中使用,我会更喜欢)您不能以这种方式对值列表使用单个参数。但可能有特定于数据库的方法来实现您想要的。例如,使用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
int[] arr = new int[3];
arr[0] = "1";
arr[1] = "2";
arr[2] = "3";
foreach(vat data in arr)
{
//Do your Code here
//
var MyDatatable = obj.GetDatabyID(data);
TableAdapter.Fill(MyDataTable);
}
@乔是对的
或者可以使用foreach循环来实现这一点
比如:
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
int[] arr = new int[3];
arr[0] = "1";
arr[1] = "2";
arr[2] = "3";
foreach(vat data in arr)
{
//Do your Code here
//
var MyDatatable = obj.GetDatabyID(data);
TableAdapter.Fill(MyDataTable);
}
关于我所知道的唯一一个可以在子句中使用.NET参数的数据库是PostgreSQL,因为PostgreSQL的数组概念可以与中的
一起使用,Npgsql允许使用数组(或IEnumerable
)参数
对于其他数据库,您必须构造SQL,或者将字符串传递给数据库过程,该过程将其转换为0个或多个参数,然后对这些参数执行操作。SQL Server 2008具有一个名为
所以你需要
将查询定义为SELECT*from表,其中ID位于(SELECT*from(@IDs))
返回visual Studio中的TableAdapter visual designer,并更新@IDS参数以将@IDS参数修改为DbType=Object和ProviderType=Structured
在您使用的数据库中运行此SQL批处理:CREATE TYPE MyIntArray AS TABLE(Value INT);转到
。
这将创建一个MyIntArray“表类型”,其中只有一列为INT类型
现在棘手的事情是将“MyIntArray”类型传递给ADO.NET端的TableAdapter李>
不幸的是,表适配器设计器不支持SqlParameter.TypeName
参数,因此我们需要自己修复它。目标是修改生成的TableAdapter类的CommandCollection
属性。不幸的是,此属性受保护,因此您必须派生TableAdapter,或者例如使用反射来调整它。下面是一个派生类的示例:
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";
}
}
下面是调用此方法的方法:
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);
您还可以创建IDs参数列表
因此,您将使用@ID1、@ID2、@ID3等,而不是使用@IDs
var sql = "SELECT * from Table WHERE ID IN (" + getKeys(values.Count) + ")";
和getKeys(count)执行如下操作:
var result = string.Empty;
for (int i = 0; i < count; i++)
{
result += ", @ID" + i;
}
return string.IsNullOrEmpty(result) ? string.Empty : result.Substring(1);
var result=string.Empty;
for(int i=0;i
最后,添加以下参数:
foreach (int i = 0; i < values.Count; i++)
{
cmd.Parameters.Add(new SqlParameter("@ID" + i, SqlDbType.VarChar) { Value = values[i]});
}
foreach(inti=0;i
我尝试了一种在SQL方式中使用字符串“contains”概念的变通方法:
在您的情况下,更改SQL-
原件:
从ID所在的表中选择*(@IDs)
成为:
从表中选择*,其中CharIndex(','+Cast(ID为Varchar(10))+',',@IDs)>0
使用.net代码-
原件:
TableAdapter.Fill(MyDataTable,“1,2,3”)
成为:
TableAdapter.Fill(MyDataTable,“,1,2,3,”)
您还可以使用XML将参数列表传入存储过程:
1) 在Visual Studio中:
创建新的Tableadapter并创建类型化数据集以获取单个记录:
SELECT * FROM myTable WHERE (ID = @ID)
2) 在SQL Server管理器中:
使用与类型化数据集相同的选择字段创建存储过程:
CREATE PROCEDURE [dbo].[usrsp_GetIds]
@paramList xml = NULL
AS
SET NOCOUNT ON;
/*
Create a temp table to hold paramaters list.
Parse XML string and insert each value into table.
Param list contains: List of ID's
*/
DECLARE @tblParams AS TABLE (ID INT)
INSERT INTO @tblParams(ID)
SELECT
XmlValues.ID.value('.', 'INT')
FROM
@paramList.nodes('/params/value') AS XmlValues(ID)
/*
Select records that match ID's in param list:
*/
SELECT * FROM myTable
WHERE
ID IN (
SELECT ID FROM @tblParams
)
3) 在Visual Studio中:
将新查询添加到Tableadapter,选择上面创建的存储过程usrsp_GetIds,并将其命名为FillBy_Ids。这将创建以下命令:
TableAdapter.FillBy_Ids(@paramList)
4) 在Visual Studio中:
在.net代码中,创建一个实用程序函数,将字符串数组转换为XML:
''' <summary>
''' Converts an array of strings to XML values.
''' </summary>
''' <remarks>Used to pass parameter values to the data store.</remarks>
Public Shared Function ConvertToXML(xmlRootName As String, values() As String) As String
'Note: XML values must be HTML encoded.
Dim sb As New StringBuilder
sb.AppendFormat("<{0}>", HttpUtility.HtmlEncode(xmlRootName))
For Each value As String In values
sb.AppendLine()
sb.Append(vbTab)
sb.AppendFormat("<value>{0}</value>", HttpUtility.HtmlEncode(value))
Next
sb.AppendLine()
sb.AppendFormat("</{0}>", xmlRootName)
Return sb.ToString
End Function
我可以通过将ClearBeforeFill
属性设置为false
并在foreach
循环中填充TableAdapter
来解决这个问题
List<string> aList = new List<string>();
aList.Add("1");
aList.Add("2");
aList.Add("3");
yourTableAdapter.ClearBeforeFill = true;
yourTableAdapter.Fill(yourDataSet.yourTableName, ""); //clears table
foreach (string a in aList)
{
yourTableAdapter.ClearBeforeFill = false;
yourTableAdapter.Fill(yourDataSet.yourTableName, a);
}
yourTableAdapter.Dispose();
List aList=newlist();
添加(“1”);
(a)添加(“2”);
(a)添加(“3”);
yourTableAdapter.ClearBeforeFill=true;
yourTableAdapter.Fill(yourDataSet.yourTableName,“”)//清除表格
foreach(列表中的字符串a)
{
yourTableAdapter.ClearBeforeFill=false;
yourTableAdapter.Fill(yourDataSet.yourTableName,a);
}
yourTableAdapter.Dispose();
是SQL Server吗?如果是,哪个版本?SQL server 2008(及更高版本)允许表值参数。但这需要SQL server上的类型定义。如果允许您在服务器上使用“创建类型”,我可以回答这个问题。是的,我有完全访问权限,请详细说明。对于阅读本文的任何人,请查看Joe和Simon M的答案。这两个答案都有助于解决我的问题。这可能会有帮助:效果很好。我只想补充一件事来澄清@在查询中,ID必须类似于“1,2,3”。当我尝试它时,我感到困惑。但是如何在类型化数据集中声明函数呢?这是唯一一个简单的1TVP行示例