Buscar este blog

miércoles, 30 de marzo de 2011

Validando esquemas xml con .Net Framework

Uno de los objetivos de los esquemas xml (archivos .xsd) es poder validar que un archivo xml cumpla con las reglas que se especifican en el esquema, .Net tiene el API necesaria para realizar esta validación y es muy sencillo.
Consideremos el siguiente esquema:

   1:  <?xml version="1.0" standalone="yes"?>
   2:  <xs:schema id="Peliculas"
   3:                       targetNamespace="ProbadorConsola"
   4:                       xmlns:xs="http://www.w3.org/2001/XMLSchema"
   5:                       xmlns="ProbadorConsola"
   6:                       elementFormDefault="qualified">
   7:    <xs:element name="Peliculas">
   8:      <xs:complexType>
   9:        <xs:choice minOccurs="0" maxOccurs="unbounded">
  10:          <xs:element name="Pelicula">
  11:            <xs:complexType>
  12:              <xs:sequence>
  13:                <xs:element name="Titulo" type="xs:string" minOccurs="0" />
  14:                <xs:element name="Director" type="xs:string" minOccurs="0" />
  15:                <xs:element name="Estrenado" type="xs:string" minOccurs="0" />
  16:                <xs:element name="Actores" minOccurs="0" maxOccurs="unbounded">
  17:                  <xs:complexType>
  18:                    <xs:sequence>
  19:                      <xs:element name="Actor" minOccurs="0" maxOccurs="unbounded">
  20:                        <xs:complexType>
  21:                          <xs:sequence>
  22:                            <xs:element name="Nombre" type="xs:string" minOccurs="0" />
  23:                            <xs:element name="Nacimiento" type="xs:string" minOccurs="0" />
  24:                            <xs:element name="Roles" minOccurs="0" maxOccurs="unbounded">
  25:                              <xs:complexType>
  26:                                <xs:sequence>
  27:                                  <xs:element name="Rol" minOccurs="0" maxOccurs="unbounded">
  28:                                    <xs:complexType>
  29:                                      <xs:sequence>
  30:                                        <xs:element name="NombrePelicula" type="xs:string" minOccurs="0" />
  31:                                        <xs:element name="NombreRol" type="xs:string" minOccurs="0" />
  32:                                      </xs:sequence>
  33:                                    </xs:complexType>
  34:                                  </xs:element>
  35:                                </xs:sequence>
  36:                              </xs:complexType>
  37:                            </xs:element>
  38:                          </xs:sequence>
  39:                        </xs:complexType>
  40:                      </xs:element>
  41:                    </xs:sequence>
  42:                  </xs:complexType>
  43:                </xs:element>
  44:              </xs:sequence>
  45:            </xs:complexType>
  46:          </xs:element>
  47:        </xs:choice>
  48:      </xs:complexType>
  49:    </xs:element>
  50:  </xs:schema>

Y el contenido xml que queremos validar:

   1:  <Peliculas xmlns="ProbadorConsola">
   2:      <Pelicula>
   3:      <Titulo>Mazinger</Titulo>
   4:      <Director>Jackie Chan</Director>
   5:      <Estrenado>1975-03-19T00:00:00</Estrenado>
   6:      <Actores>
   7:        <Actor>
   8:          <Nombre>John Wayne</Nombre>
   9:          <Nacimiento>1915-10-23T00:00:00</Nacimiento>
  10:          <Roles>
  11:            <Rol>
  12:              <NombrePelicula>Mazinger</NombrePelicula>
  13:              <NombreRol>Estrella</NombreRol>
  14:            </Rol>
  15:          </Roles>
  16:        </Actor>
  17:      </Actores>
  18:    </Pelicula>
  19:  </Peliculas>

Lo primero que debemos hacer es validar que el documento contenga el espacio de nombres del esquema si no lo contiene la validación fallara diciéndonos que el documento es valido aun cuando en realidad no cumpla las reglas del esquema.
El código para encontrar el espacio de nombres (c#):

   1:  XDocument peliculas = XDocument.Load("peliculas.xml");
   2:  XPathNavigator nav = peliculas.CreateNavigator();
   3:  nav.MoveToFollowing(XPathNodeType.Element);
   4:  IDictionary<string, string> ns
   5:      = nav.GetNamespacesInScope(XmlNamespaceScope.All);
   6:  bool schemaFound = false;
   7:  foreach(KeyValuePair<string, string> namespaces in ns) {
   8:      if(namespaces.Value.CompareTo("ProbadorConsola") == 0)
   9:          schemaFound = true;
  10:  }
  11:  if(!schemaFound) {
  12:      Console.WriteLine("Esquema no encontrado");
  13:      return;
  14:  }
Ahora si podemos proceder a validar el documento con el esquema que puede estar en un archivo local o en Internet:

   1:  XmlSchemaSet schema = new XmlSchemaSet();
   2:  schema.Add("ProbadorConsola", "peliculas.xsd");
   3:  peliculas.Validate(schema, null);
   4:  Console.WriteLine("Esquema valido");
   5:  Console.ReadLine();

Hacemos notar que si utilizas Linq a XSD todo esto lo hace en una sola linea de código al cargar el documento.

Para aprender más sobre el uso de XML en .Net Framework visita:
Lista de artículos acerca del uso de XML en .Net Framework

sábado, 26 de marzo de 2011

Instalar Linq a XSD

En una entrada anterior ya vimos lo que se puede hacer con Linq a XSD pero dejamos el proceso de instalación pendiente ya que es un poco complicado y merece una entrada independiente.
Linq a XSD es muy útil y no deberíamos detenernos en su uso debido a las pocas complicaciones que tiene su instalación sobre todo tomando en cuenta que es un proyecto de Microsoft y probablemente se incluya en versiones futuras de Visual Studio.
Bueno lo primero es descargarlo desde el proyecto de Linq a XSD en Codeplex y colocar los archivos descargados en una carpeta preferentemente dentro de la carpeta de nuestra solución, en nuestro ejemplo se colocara en la carpeta Components\LinqToXsd\bin en la raíz de nuestra solución y añadimos los archivos en una carpeta de solución solo para recordarnos donde están y no es un paso obligatorio.
Ahora abrimos las propiedades del proyecto en que vamos a usarlo y en la pestaña Build Events en el recuadro Pre-build event command line colocamos el siguiente texto:

SET LINQTOXSDBINDIR=$(SolutionDir)Components\LinqToXsd\bin

Cuidando que la ruta apunte a donde pusimos los archivos.


Ahora necesitamos modificar el archivo csproj de la solución (Linq a XSD solo funciona en C-Sharp, pero puedes hacer una DLL que después utilizaras en VB.Net), para esto descargamos la solución, en el explorador de la solución escogemos el proyecto que estamos usando, click derecho y Unload Project, click derecho y Edit proyecto.csproj.
Vamos al final del archivo y después del cierre del último elemento <propertygroup> ponemos este código:

   1:  <PropertyGroup>
   2:      <LinqToXsdBinDir Condition="'$(LinqToXsdBinDir)' == ''">$(SolutionDir)Components\LinqToXsd\bin</LinqToXsdBinDir>
   3:  </PropertyGroup>

Nótese que al pegar el código Visual Studio lo formatea poniéndole lineas nuevas alrededor de la ruta, debemos modificar esto de tal forma que la quede igual que en el código de ejemplo de lo contrario tendremos errores. A continuación muestro la forma en que NO debe quedar la modificación

   1:  <PropertyGroup>
   2:      <LinqToXsdBinDir Condition="'$(LinqToXsdBinDir)' == ''">
   3:          $(SolutionDir)Components\LinqToXsd\bin
   4:      </LinqToXsdBinDir>
   5:  </PropertyGroup>

Falta introducir otro código en el mismo archivo, también al final del archivo después de el cierre del último elemento <import> colocamos el siguiente código:

   1:  <Import Project="$(LinqToXsdBinDir)\LinqToXsd.targets" />

Listo recargamos la solución y al archivo .xsd para el que queremos crear las clases le cambiamos el Build Action a LinqToXsdSchema compilamos y se nos generan las clases que necesitamos, es necesario notar que las clases se encuentran en el espacio de nombres indicado en el atributo targetNamespace del esquema xml (.xsd) y no en el de nuestro proyecto por lo que debemos buscar las clases en ese espacio de nombres.

Para aprender más sobre Linq visita:
Lista de artículos acerca de Linq

Para aprender más sobre el uso de XML en .Net Framework visita:
Lista de artículos acerca del uso de XML en .Net Framework

viernes, 18 de marzo de 2011

Cobertura de código (Code Coverage) con pruebas unitarias de Visual Studio

Una de las funciones que tiene los proyectos de pruebas de Visual Studio es la Cobertura de Código o Code Coverage en ingles, esta función nos permite saber que porcentaje del código de nuestro proyecto estamos probando lo cual es muy importante pues puede haber errores en el código que no estamos probando y esta función nos da una idea de que pruebas nos faltan por escribir.

Para habilitar la cobertura de código previo requisito es que tengamos una versión de Visual Studio que tenga soporte para proyectos de prueba, al crear nuestro proyecto de prueba Visual Studio crea automáticamente un archivo llamado LocalTestRun.testrunconfig en una carperta Elementos de la solución (Solution Items) directamente bajo la solución para habilitar la cobertura de código hacemos doble click en este archivo y nos aparecerá la ventana de configuración de las pruebas en esta ventana escogemos la sección Cobertura de Código y nos aparece una lista con las dll's y ejecutables que produce nuestra solución debemos marcar los elementos para los que queremos habilitar la cobertura de código aplicamos los cambios cerramos y listo ya tenemos habilitada la cobertura de código en nuestras pruebas.


Para obtener los resultados ejecutamos las pruebas que queremos analizar y abrimos el panel Resultado de Cobertura de Código (Code Coverage Results) aquí vemos una lista que nos muestra detalle los porcentajes de código que estamos probando pudiendo expandir la lista hasta saber exactamente que parte del código se probo en que porcentaje.


En la imagen podemos ver que solo se probo el 4 por ciento del código con lo cual sabemos que nos falta mucho por probar, por supuesto es un ejemplo solo demostrativo.

Para aprender más acerca de las pruebas unitarias con .Net Framework visita:
Lista de artículos acerca de pruebas unitarias con .Net Framework

miércoles, 16 de marzo de 2011

Integrar NUnit a Visual Studio

Hay varias formas de integrar NUnit a Visual Studio, aquí mostrare la más sencilla y la que me parece la más conveniente.
Siguiendo las instrucciones del sitio de NUnit agregamos una herramienta personalizada a Visual Studio y le agregamos los parámetros necesarios para ejecutar NUnit en el proyecto actual estos datos son:

Titulo: NUnit
Comando: C:\Program Files\NUnit 2.5.1\bin\net-2.0\nunit.exe
ajustando la ruta a donde tenemos instalado NUnit
Argumentos: $(ProjectDir)$(ProjectFileName)
Directorio Inicial: $(ProjectDir)bin/Debug/



Eso es todo seleccionamos en el editor un archivo que este en un proyecto de pruebas NUnit y en el menú de herramientas seleccionamos NUnit y se abrira NUnit usando el proyecto de pruebas seleccionado, nótese que tiene que estar abierto y activo en el editor algún archivo que pertenezca a un proyecto de pruebas de NUnit de lo contrario nos marcara un error.

La otra opción es mucho mejor ya que integra los proyectos de pruebas de NUnit con la interfaz de Visual Studio sin necesidad de abrir el ejecutable de NUnit y mostrando los resultados dentro de la pantalla de Visual Studio, el requisito es que tengamos una versión de Visual Studio que soporte proyectos de prueba.
Esto se logra usando el componente NUnitForVS que podemos bajar de CodePlex y funciona para las versiones 2008 y 2010 de Visual Studio.
Después de instalar el complemento tenemos que modificar los proyectos de NUnit en nuestras soluciones lo que debemos hacer es descargar el proyecto de la solución (Unload Project desde el explorador de soluciones) y editar el archivo csproj tenemos que añadir la siguientes lineas:

<projecttypeguids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</projecttypeguids>

al final de la primer sección <propertygroup> que encontremos en el archivo.
Después de esto ya estamos listos para ejecutar nuestras pruebas abrimos la ventana Vista de Pruebas (Test View) y encontraremos nuestras de NUnit mezcladas con las pruebas de Visual Studio (si es que tenemos alguna) e identificadas por un icono de una N al pricipio:


Ejecutamos las pruebas y obtenemos los resultados en el panel de resultados de las pruebas:


Para aprender más acerca de las pruebas unitarias con .Net Framework visita:
Lista de artículos acerca de pruebas unitarias con .Net Framework

martes, 8 de marzo de 2011

Linq a XSD: leyendo xml con tipos

Como hemos comentado en una entrada anterior es muy fácil usar xml con Linq en .Net, pues bien es posible usarlo aun mas fácilmente usando Linq a Xsd que es un proyecto de Microsoft disponible en CodePlex y que nos permite crear una estructura de clases a partir de un esquema de xml que representa el contenido de nuestro xml, obviamente el requisito es que tengamos o creemos un esquema xml para poder usar esta característica. Recordemos que en una entrada anterior vimos como crear esquemas con herramientas disponibles libremente.

Instalar esta herramienta es un poco complicado por lo que en esta entrada solo dare una breve introducción a lo que se puede hacer con esta herramienta y en otra entrada incluire otros ejemplos incluyendo el procedimiento de instalación.

Lo primero es tener a la mano nuestro esquema consideremos este xsd:


   1:  <?xml version="1.0" standalone="yes"?>
   2:  <xs:schema id="Peliculas"
   3:                       targetNamespace="ProbadorConsola"
   4:                       xmlns:xs="http://www.w3.org/2001/XMLSchema"
   5:                       xmlns="ProbadorConsola"
   6:                       elementFormDefault="qualified">
   7:    <xs:element name="Peliculas">
   8:      <xs:complexType>
   9:        <xs:choice minOccurs="0" maxOccurs="unbounded">
  10:          <xs:element name="Pelicula">
  11:            <xs:complexType>
  12:              <xs:sequence>
  13:                <xs:element name="Titulo" type="xs:string" minOccurs="0" />
  14:                <xs:element name="Director" type="xs:string" minOccurs="0" />
  15:                <xs:element name="Estrenado" type="xs:string" minOccurs="0" />
  16:                <xs:element name="Actores" minOccurs="0" maxOccurs="unbounded">
  17:                  <xs:complexType>
  18:                    <xs:sequence>
  19:                      <xs:element name="Actor" minOccurs="0" maxOccurs="unbounded">
  20:                        <xs:complexType>
  21:                          <xs:sequence>
  22:                            <xs:element name="Nombre" type="xs:string" minOccurs="0" />
  23:                            <xs:element name="Nacimiento" type="xs:string" minOccurs="0" />
  24:                            <xs:element name="Roles" minOccurs="0" maxOccurs="unbounded">
  25:                              <xs:complexType>
  26:                                <xs:sequence>
  27:                                  <xs:element name="Rol" minOccurs="0" maxOccurs="unbounded">
  28:                                    <xs:complexType>
  29:                                      <xs:sequence>
  30:                                        <xs:element name="NombrePelicula" type="xs:string" minOccurs="0" />
  31:                                        <xs:element name="NombreRol" type="xs:string" minOccurs="0" />
  32:                                      </xs:sequence>
  33:                                    </xs:complexType>
  34:                                  </xs:element>
  35:                                </xs:sequence>
  36:                              </xs:complexType>
  37:                            </xs:element>
  38:                          </xs:sequence>
  39:                        </xs:complexType>
  40:                      </xs:element>
  41:                    </xs:sequence>
  42:                  </xs:complexType>
  43:                </xs:element>
  44:              </xs:sequence>
  45:            </xs:complexType>
  46:          </xs:element>
  47:        </xs:choice>
  48:      </xs:complexType>
  49:    </xs:element>
  50:  </xs:schema>

Y después el archivo xml que vamos a utilizar:


   1:  <?xml version="1.0"?>
   2:  <Peliculas xmlns="ProbadorConsola">
   3:    <Pelicula>
   4:      <Titulo>Mazinger</Titulo>
   5:      <Director>Jackie chan</Director>
   6:      <Estrenado>1975-03-19T00:00:00</Estrenado>
   7:      <Actores>
   8:        <Actor>
   9:          <Nombre>John Wayne</Nombre>
  10:          <Nacimiento>1915-10-23T00:00:00</Nacimiento>
  11:          <Roles>
  12:            <Rol>
  13:              <NombrePelicula>Mazinger</NombrePelicula>
  14:              <NombreRol>Estrella</NombreRol>
  15:            </Rol>
  16:          </Roles>
  17:        </Actor>
  18:      </Actores>
  19:    </Pelicula>
  20:    <Pelicula>
  21:      <Titulo>Terminator</Titulo>
  22:      <Director>James Cameron</Director>
  23:      <Estrenado>1985-02-14T00:00:00</Estrenado>
  24:      <Actores>
  25:        <Actor>
  26:          <Nombre>Arnold</Nombre>
  27:          <Nacimiento>1953-10-11T00:00:00</Nacimiento>
  28:          <Roles>
  29:            <Rol>
  30:              <NombrePelicula>Terminator</NombrePelicula>
  31:              <NombreRol>Protagonista</NombreRol>
  32:            </Rol>
  33:            <Rol>
  34:              <NombrePelicula>Terminator</NombrePelicula>
  35:              <NombreRol>Enemigo</NombreRol>
  36:            </Rol>
  37:          </Roles>
  38:        </Actor>
  39:        <Actor>
  40:          <Nombre>Linda Hamilton</Nombre>
  41:          <Nacimiento>1972-08-12T00:00:00</Nacimiento>
  42:          <Roles>
  43:            <Rol>
  44:              <NombrePelicula>Terminator</NombrePelicula>
  45:              <NombreRol>Protagonista</NombreRol>
  46:            </Rol>
  47:            <Rol>
  48:              <NombrePelicula>Terminator</NombrePelicula>
  49:              <NombreRol>Perseguida</NombreRol>
  50:            </Rol>
  51:          </Roles>
  52:        </Actor>
  53:      </Actores>
  54:    </Pelicula>
  55:  </Peliculas>

Linq a XSD nos genera una jerarquía de clases que nos permite manejar el xml usando datos tipeados con soporte de Intellisense y comprobación por parte del compilador, por ejemplo para listar los datos de todos los actores:


   1:  Peliculas peliculas = Peliculas.Load("peliculas.bak.xml");
   2:  var actores = from p in peliculas.Pelicula
   3:                from a in p.Actores
   4:                from actor in a.Actor
   5:                select actor;
   6:  Console.WriteLine("Todos los actores");
   7:  foreach(var actor in actores) {
   8:      Console.Out.WriteLine("Nombre: " + actor.Nombre);
   9:      Console.Out.WriteLine("Fecha de nacimiento: " + actor.Nacimiento);
  10:  }

En conclusion Linq a XSD es un complemento muy útil para el manejo de XML en .Net Framework.
Hay que tener en cuenta que el proyecto a Marzo del 2011 aún esta en etapa Beta y es mejor probar bien nuestro código para evitar errores inesperados, como sea el proyecto es muy útil y es probable que posteriormente sea incluido como parte del .Net Framework.

Para aprender más sobre Linq visita:
Lista de artículos acerca de Linq

Para aprender más sobre el uso de XML en .Net Framework visita:
Lista de artículos acerca del uso de XML en .Net Framework

viernes, 25 de febrero de 2011

Creando DataSets tipeados a partir de cualquier XML

Un DataSet tipeado es muy útil ya que nos permite acceder a los datos del DataSet por medio de tipos fuertes usando los nombres de las columnas y con comprobación de parte del compilador.
La forma de crear un DataSet de este tipo es con el editor de DataSets que es en realidad un editor de esquemas xml.
Una propiedad del xml es que se puede inferir su esquema prográmaticamente y usar el resultado para crear un el DataSet tipeado, esto se hace leyendo el xml en un DataSet sin tipos y usando el método WriteXmlSchema del DataSet para escribir el esquema en un archivo, se incluye el archivo en el proyecto en que se desea usarlo y al abrirlo Visual Studio crea automáticamente el código y los archivos de soporte necesarios para el DataSet tipeado.

Aquí esta el código para crear el Dataset.

   1:  DataSet schemaCreator = new DataSet();
   2:  schemaCreator.ReadXml("peliculas.xml");
   3:  schemaCreator.WriteXmlSchema("peliculas.xsd");

Por ejemplo para el siguiente XML.

   1:  <Peliculas>
   2:    <Pelicula>
   3:      <Titulo>Mazinger</Titulo>
   4:      <Director>Jackie Chan</Director>
   5:      <Estrenado>1975-03-19T00:00:00</Estrenado>
   6:      <Actores>
   7:        <Actor>
   8:          <Nombre>John Wayne</Nombre>
   9:          <Nacimiento>1915-10-23T00:00:00</Nacimiento>
  10:          <Roles>
  11:            <Rol>
  12:              <NombrePelicula>Mazinger</NombrePelicula>
  13:              <NombreRol>Estrella</NombreRol>
  14:            </Rol>
  15:          </Roles>
  16:        </Actor>
  17:      </Actores>
  18:    </Pelicula>
  19:  </Peliculas>

Nos genera este esquema


Todo esto nos permite usar los métodos  ReadXml y WriteXml del DataSet para cargar el y guardar el contenido xml y usar el mismo de una forma muy similar a una base de datos, también podemos usar Linq contra el DataSet.

Claro que también hay herramientas que nos permiten obtener el esquema del xml sin escribir código, una de ellas es XMLViewer, que es una utilidad para ver el contenido de archivos xml en forma tabular y también obtiene el esquema del archivo, también la herramienta de linea de comandos xsd que se incluye con el SDK de .Net Framework nos sirve para obtener el esquema.

Para aprender más sobre el uso de XML en .Net Framework visita:
Lista de artículos acerca del uso de XML en .Net Framework

sábado, 12 de febrero de 2011

Que es LINQ

Linq es el acrónimo en ingles para Language-Integrated Query que significa Lenguaje Integrado de Consulta y es un subconjunto agregado a los lenguajes de .Net para realizar búsquedas  y otras operaciones sobre conjuntos de datos, esto es: el mismo lenguaje de tu preferencia puede realizar operaciones sobre conjuntos de datos proporcionándote verificación por parte del compilador,  Intelisense y verificación de tipos sobre las consultas, la sintaxis es muy parecida a SQL con la ventajas antes mencionadas debido a que no se usan con cadenas como en SQL.

Linq puede realizar consultas sobre diversas formas de conjuntos de datos a través de extensiones especificas al conjunto de datos que estas manejando, así existen por lo menos las siguientes extensiones provenientes de Microsoft y otras fuentes:

Linq a objetos: permite manejar consultas a los tipos básicos de .Net como listas y arreglos y sobre clases ya sea del sistema o propias.
Linq a DataSets: las consultas se hacen sobre los componentes de un DataSet ya sea normal o tipeado.
Linq a SQL: las consultas se realizan sobre la base de datos SQL Server con todas las ventajas antes mencionadas.
DBLinq: es un proyecto independiente que es similar a Linq a SQL con la ventaja de que podemos usar bases de datos diferentes a SQL Server y de hecho podemos cambiar de tipo de base de datos con solo modificar la cadena de conexión.
Linq a XML: nos permite realizar consultas en datos guardados en XML.

Para darnos una idea rápida de la forma en que se utiliza Linq tenemos los siguientes ejemplos sencillos de Linq a datos.
Podemos consultar en un arreglo los elementos que cumplen con cierta condición (c#):


   1:  string[] strings = new string[] { "1", "2", "3", "2", "1" };
   2:  IEnumerable<string> two = from s in strings
   3:                            where s == "2"
   4:                            select s;
   5:  Console.Out.WriteLine("s == 2, count{0}", two.Count());

el mismo código en Visual Basic es prácticamente idéntico:


   1:  Dim strings() As String = New String() {"1", "2", "3", "2", "1"}
   2:  Dim two As IEnumerable(Of String) = From s In strings _
   3:     Where s = "2" _
   4:     Select s
   5:  Console.Out.WriteLine("s == 2, count{0}", two.Count())

El resultado de la consulta es un IEnumerable y tenemos que recorrerlo de alguna forma para obtener resultados, en el ejemplo el método Count (que es un método de extensión) recorre el resultado de la consulta y nos entrega la cuenta de los elementos que cumplieron con las condiciones.

También podemos consultar más de un conjunto de datos a la vez (c#):



   1:  int[] integers = new int[] { 1234, 754, 309, 233 };
   2:  var query = from i in integers
   3:              from s in strings
   4:              where i.ToString().Contains(s)
   5:              select new { s, i };
   6:  foreach(var i in query) {
   7:      Console.Out.WriteLine("{0}, {1}", i.s, i.i);
   8:  }

en Visual Basic:

   1:  Dim integers() As Integer = New Integer() {1234, 754, 309, 233}
   2:  Dim query = From i In integers _
   3:     From s In strings _
   4:     Where i.ToString().Contains(s) _
   5:     Select New With {s, i}
   6:  For Each i In query
   7:      Console.Out.WriteLine("{0}, {1}", i.s, i.i)
   8:  Next

En este caso usamos una consulta que une dos conjuntos y después se recorre la consulta para obtener los resultados.
Para aprender más sobre Linq visita:
Lista de artículos acerca de Linq