2011-06-14 16 views
5

XML:¿Cómo consultar datos XML en la columna de la base de datos usando Linq a SQL y Linq a XML?

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

Los datos XML se almacena en una tabla de base de datos.

¿Puedo construir una consulta Linq que seleccione las filas, extraiga el XML y luego, por ejemplo, extraiga todas las etiquetas href? El resultado final sería una lista de todas las URL para todas las filas seleccionadas.

Este es mi intento, pero no me da lo que quiero, que sería una lista de todos los hrefs para todos los usuarios seleccionados. Acabo de obtener una lista de IEnumerations vacías.

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"); 


Solución

había 2 problemas.

- Supongo que la consulta solo se ejecuta cuando realmente se exige un resultado. A medida que progresaba de una consulta de SQL a XML, la consulta resultante se convirtió en una mezcla de SQL y XML y por lo tanto no ejecutable. Mi solución fue forzar un resultado al convertir la consulta SQL en una lista de resultados. Esto separó el linq-sql de linq-xml.

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

- El segundo problema fue que olvidé agregar el espacio de nombres a mi consulta XML. Una vez que hice eso obtuve el resultado requerido

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

¡Gracias por toda su ayuda!

+1

¿Qué quiere decir con "no darme lo que quiero"? ¿Resultados incorrectos? ¿No hay resultados? ¿Lento? – GalacticCowboy

+0

@GalacticCowboy - editado. Espero que esté más claro ahora – paul

+0

Otra pregunta: ¿cómo está pasando de LINQ a SQL a lo que está llamando aquí "MYTABLE"? ¿O es este pseudocódigo alrededor del "contexto.MYTABLE" real? – GalacticCowboy

Respuesta

1

Aquí hay un fragmento de código que usa su código y un contenido codificado de MYTABLE, y funciona perfectamente (validado con LinqPad). ¿Quizás su tabla de base de datos o MYTABLE no contenga lo que usted piensa que hace? ¿Puedes verificar el resultado de 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); 
} 

Salida:

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

Espero que esto ayude!

+0

gracias, pero la diferencia aquí es que todo es linq a xml - aquí no hay SQL involucrado. Aparece un mensaje de error de la acción 'from h in docs', algo así como 'XDocument.Parse - no compatible con SQL'. ¿Puedo mezclar consultas SQL y XML como esta? – paul

3

Aquí hay algunas cosas que probé.

  1. Configuración: Creé una base de datos con una tabla MYTABLE, que contiene 2 columnas. La columna 1 (SPP_USER_ID) es varchar (255), la columna 2 (SPP_BOOKMARKS_XML) es el tipo de datos xml. Agregué 2 filas, reflejando las que usó mellamokb. Creé una superficie de diseño LINQ to SQL y la arrastré en esta tabla. Mi aplicación es solo una aplicación de consola que carga el contexto de datos LINQ to SQL y luego llama a sus comandos.
  2. I consultados directamente contra la tabla de datos, como sigue:

     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"); 
    

    El resultado fue una colección de IEnumerables. Es decir. para cada fila en la base de datos, obtuve un IEnumerable que contiene todos los descendientes "href". Entonces en este escenario, obtuve dos resultados; el primer resultado fue un IEnumerable que contenía 2 elementos, y el segundo resultado fue un IEnumerable que contenía 1 elemento. Parece que, según su descripción, esto está al menos cerca de lo que desea.Sin embargo, es posible que no esté viendo lo que espera solo por la forma en que está estructurada su consulta.

    Tenga en cuenta que a veces es bastante difícil conseguir que Visual Studio le muestre los resultados de una consulta como esta. Descubrí que con frecuencia tengo que "mirar" el elemento dos veces antes de molestarme en disparar la enumeración de resultados.

  3. Me trataron de duplicar el código escrito en su OP de la siguiente manera: (?)

     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"); 
    

    Cuando hice esto, que dio como resultado el valor "xml" está colocado en la papelera porque ya era un XDocument por lo lanzarlo a una cadena resultó en la eliminación de todas las etiquetas. Entonces, las siguientes dos declaraciones fallaron con una excepción de análisis XML.

+0

Interesantes resultados. ¿Qué sucede si cambia 'SPP_BOOKMARKS_XML' a solo un tipo de datos' varchar'? – mellamokb

+0

Si realizo ese cambio, el ítem 3 se comporta exactamente como el ítem 2. – GalacticCowboy