System.InvalidCastException: не удалось преобразовать значение параметра из XElement в строку - PullRequest
5 голосов
/ 16 декабря 2011

Примечание: Мне не удалось найти этот точный вопрос в поиске.Я нашел несколько похожий вопрос здесь о переполнении стека, что привело меня к решению.Я публикую вопрос и решение, чтобы следующий человек с проблемой мог легче найти решение.Я бы задал вопрос 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 как объект X-элемента LINQ to XML

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 в строку.---> System.InvalidCastException: объект должен реализовывать IConvertible

Как правильно передать XElement хранимой процедуре?

Ответы [ 2 ]

9 голосов
/ 16 декабря 2011

Код SqlClient не позволяет напрямую передавать элемент XElement.

Единственное, что вы можете сделать, это использовать System.Data.SqlTypes.SqlXml класс для передачи XML:

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

В зависимости от вашего кода вам может понадобиться поместить XmlReader, возвращенный из кода CreateReader, в блок using.

0 голосов
/ 12 февраля 2015

Вот два метода расширения, которые я построил на основе ответа Джона Сондерса.

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())
        });
    }
}
...