Как запросить данные XML в столбце базы данных, используя Linq to SQL и Linq to XML? - PullRequest
5 голосов
/ 14 июня 2011

XML:

<root>
    <item>
        <href>http://myurl</href>
    </item>
    <item>
        <href>http://myurl2</href>
    </item>
</root>

Данные XML хранятся в таблице базы данных.

Могу ли я создать запрос Linq, который выбирает строки, извлекает XML, а затем, например, извлекает все теги href ?Конечным результатом будет список всех URL-адресов для всех выбранных строк.

Это моя попытка, но она не дает мне того, что я хочу, а список всех ссылок для всех выбранных пользователей.Я просто получаю список пустых IEnumerations.

var all = from bm in MYTABLE
        select new { name=bm.SPP_USER_ID, xml=(string) bm.SPP_BOOKMARKS_XML};

var docs = from x in all
        select XDocument.Parse(x.xml);
var href = from h in docs
        select h.Descendants("href");

Решение

Было 2 проблемы.

- Я полагаю, что запрос выполняется только тогда, когда результат действительно требуется.По мере того как я переходил от SQL к XML-запросу, полученный запрос стал смесью SQL и XML и, следовательно, неисполнимым.Мое решение состояло в том, чтобы форсировать результат путем преобразования запроса SQL в список результатов.Это отделяло linq-sql от linq-xml.

var docs = from x in all
        select XDocument.Parse(x.xml);
var docs2 = docs.ToList();  // force result

- Вторая проблема заключалась в том, что я забыл добавить пространство имен в мой XML-запрос.Как только я это сделал, я получил требуемый результат

XNamespace ns = "http://acme/bookmarks";
var href = from h in docs2
    select h.Descendants(ns + "href");

Спасибо за вашу помощь!

Ответы [ 2 ]

3 голосов
/ 14 июня 2011

Вот пара вещей, которые я попробовал.

  1. Настройка: я создал базу данных с таблицей MYTABLE, содержащей 2 столбца. Столбец 1 (SPP_USER_ID) - это varchar (255), столбец 2 (SPP_BOOKMARKS_XML) - это тип данных xml. Я добавил 2 ряда, отражая те, которые использовал mellamokb. Я создал поверхность разработки LINQ to SQL и перетащил ее в эту таблицу. Мое приложение - это просто консольное приложение, которое загружает контекст данных LINQ to SQL и затем вызывает ваши команды.
  2. Я запросил непосредственно к таблице данных, следующим образом:

            var all = from bm in context.MYTABLEs
                      select new { name = bm.SPP_USER_ID, xml = (string)bm.SPP_BOOKMARKS_XML };
    
            var docs = from x in all
                       select XDocument.Parse(x.xml);
    
            var href = from h in docs
                       select h.Descendants("href");
    

    Результатом стала коллекция IEnumerables. То есть для каждой строки в базе данных я получил IEnumerable, содержащий все потомки "href". Таким образом, в этом сценарии я получил два результата; первый результат был IEnumerable, который содержал 2 элемента, а второй результат был IEnumerable, который содержал 1 элемент. Кажется, из вашего описания, это, по крайней мере, близко к тому, что вы хотите. Однако, возможно, вы не видите того, что ожидаете, просто из-за структуры вашего запроса.

    Обратите внимание, что иногда бывает трудно заставить Visual Studio фактически показать вам результаты такого запроса. Я обнаружил, что мне часто приходится «смотреть» элемент дважды, прежде чем он потрудится запустить перечисление результатов.

  3. Я попытался продублировать код, написанный в вашем ОП, следующим образом:

            var MYTABLE = (from bm in context.MYTABLEs select bm).ToList();
    
            var all = from bm in MYTABLE
                      select new { name = bm.SPP_USER_ID, xml = (string)bm.SPP_BOOKMARKS_XML };
    
            var docs = from x in all
                       select XDocument.Parse(x.xml);
    
            var href = from h in docs
                       select h.Descendants("href");
    

    Когда я это сделал, это привело к тому, что значение "xml" было уничтожено, потому что это уже был XDocument (?), Поэтому приведение его к строке привело к удалению всех тегов. Итак, следующие два оператора потерпели неудачу с исключением XML-разбора.

1 голос
/ 14 июня 2011

Вот фрагмент кода, который использует ваш код и жестко закодированное содержимое MYTABLE, и он отлично работает (проверено с LinqPad). Возможно, ваша таблица базы данных или MYTABLE не содержит того, что вы думаете, что она делает? Можете ли вы проверить результат all?

var MYTABLE = new  [] {
    new {
        SPP_USER_ID = "XML-SNIPPET-1",
        SPP_BOOKMARKS_XML = @"
        <root>
            <item>
                <href>http://myurl</href>
            </item>
            <item>
                <href>http://myurl2</href>
            </item>
        </root>
        ",
    },
    new {
        SPP_USER_ID = "XML-SNIPPET-2",
        SPP_BOOKMARKS_XML = @"
        <root>
            <item>
                <href>http://google.com</href>
            </item>
        </root>
        ",
    }
};

var all = from bm in MYTABLE
        select new { name=bm.SPP_USER_ID, xml=(string) bm.SPP_BOOKMARKS_XML};

var docs = from x in all
        select XDocument.Parse(x.xml);
var href = from h in docs
        select h.Descendants("href");

foreach (var h in href.SelectMany(h => h))
{
    Console.WriteLine(h);
}

Выход:

<href>http://myurl</href>
<href>http://myurl2</href>
<href>http://google.com</href>

Надеюсь, это поможет!

...