System.InvalidCastException:无法将参数值从 XElement 转换为 String

System.InvalidCastException: Failed to convert parameter value from a XElement to a String

提问人:John Saunders 提问时间:12/16/2011 最后编辑:John Saunders 更新时间:2/12/2015 访问量:8904

问:

注意:我在搜索中找不到这个确切的问题。我在 Stack Overflow 上发现了一个有点类似的问题,这让我找到了解决方案。我正在发布问题和解决方案,以便下一个有问题的人可以更轻松地找到解决方案。如果这仍然可能,我会向 CommunityWiki 提出问题 - 我不是在寻找代表。


我正在尝试使用 ADO.NET 调用SQL Server 2005存储过程,该过程接受以下类型的参数:Xml

CREATE PROCEDURE dbo.SomeProcedure(
    @ListOfIds Xml)
AS
BEGIN
    DECLARE
            @Ids TABLE(ID Int);
    INSERT INTO @Ids
    SELECT ParamValues.ID.value('.', 'Int')
    FROM @ListOfIds.nodes('/Persons/id') AS ParamValues(ID);

    SELECT p.Id,
           p.FirstName,
           p.LastName
    FROM Persons AS p
         INNER JOIN @Ids AS i ON p.Id = i.ID;
END;

我将 XML 作为 LINQ to XML XElement 对象传递

var idList = new XElement(
    "Persons",
    from i in selectedPeople
    select new XElement("id", i));

SqlCommand cmd = new SqlCommand
                 {
                     Connection = conn,
                     CommandText = "dbo.SomeProcedure",
                     CommandType = CommandType.StoredProcedure
                 };
cmd.Parameters.Add(
    new SqlParameter
    {
        ParameterName = "@ListOfIds",
        SqlDbType = SqlDbType.Xml,
        Value = idList)
    });
using (var reader = cmd.ExecuteReader())
{
    // process each row
}

这在行上失败,并出现异常:ExecuteReader

System.InvalidCastException:无法将参数值从 XElement 转换为 String。---> System.InvalidCastException:对象必须实现 IConvertible

将 传递给存储过程的正确方法是什么?XElement

C# sql-server-2005 ado.net sqlclient

评论

1赞 Jim Mischel 12/16/2011
C#/SQL 的可能重复 - 过程中的 SqlDbType.Xml 有什么问题?
0赞 John Saunders 12/16/2011
不是重复的 - 这是一个不同的例外。
1赞 JsonStatham 1/11/2012
你有什么问题?你有没有尝试过什么,但没有用?
0赞 John Saunders 1/11/2012
正如我在问题中所说,我接到了电话。InvalidCastExceptionExecuteReader

答:

12赞 John Saunders #1

SqlClient 代码不允许直接传递 XElement。

可以做的一件事是使用 System.Data.SqlTypes.SqlXml来传递 XML:

cmd.Parameters.Add(
    new SqlParameter
    {
        ParameterName = "@ListOfIds",
        SqlDbType = SqlDbType.Xml,
        Value = new SqlXml(idList.CreateReader())
    });

根据您的代码,您可能需要将从代码返回的内容放入块中。XmlReaderCreateReaderusing

1赞 Chris 2/12/2015 #2

这是我根据 John Saunders 的答案构建的两种扩展方法。

public static class ExtensionMethods
{
    public static void AddXml(this SqlParameterCollection theParameters, string name, XElement value)
    {
        theParameters.Add(new SqlParameter()
        {
            ParameterName = name,
            SqlDbType = SqlDbType.Xml,
            Value = new SqlXml(value.CreateReader())
        });
    }

    public static void AddXml(this SqlParameterCollection theParameters, string name, string value)
    {
        theParameters.Add(new SqlParameter()
        {
            ParameterName = name,
            SqlDbType = SqlDbType.Xml,
            Value = new SqlXml(XElement.Parse(value).CreateReader())
        });
    }
}