jueves, 3 de junio de 2010

Recuperar la consulta generada por LinqToSql y ejecutar asincrónicamente

Ejecución asincrónica y filtros dinámicos

Al interesante de LinqToSql (desde ahora L2S) es la que no genera la consulta hasta último momento si nos apoyamos en IQueryable, es decir, siempre que interactuemos con esta interface vamos a poder seguir agregando condiciones a nuestra consulta y el SQL resultante se va a resolver recién en el momento de ir a la base de datos, con esto quiero decir que no va a traer toda la tabla y después filtrar en memoria (por decirlo de una manera sencilla). Pero para resumir la cosa dejo un par de ejemplo de esto usando la base de datos AdventureWorks, enjoy.

/// <summary>
/// Ejemplo de generación de consulta LinqToSql y ejecución posterir con SqlCommand
/// </summary>
public static void LlamadaAsincronica()
{
    //context Linq2Sql
    DBDataContext _ctx = new DBDataContext();

    //Generamos la consulta
    var r = from p in _ctx.Products
            where p.ProductCategory.Name.StartsWith("b")
            select p;

    //en lugar de ejecutarla
    //recuperamos el command
    var c =  _ctx.GetCommand(r) as System.Data.SqlClient.SqlCommand;

    //tomamos el command text, o sea, el sql
    var query = c.CommandText;

    //convertimos los parámetros para pasarlos al query
    var parametros = c.Parameters.Cast<System.Data.SqlClient.SqlParameter>().Select(p => p.Value).ToArray();

    //lo ejecutamos asincrónicamente
    var result = _ctx.ExecuteQuery<Product>(query,  parametros);
}

/// <summary>
/// Ejemplo de suma de filtros
/// </summary>
public static void SumandoFiltros()
{
    DBDataContext _ctx = new DBDataContext();

    //generamos un IQueryable
    var query = _ctx.Products.AsQueryable();

    //colocamos un fitro
    query = query.Where(p => p.ProductCategory.ParentProductCategoryID == 1).AsQueryable();

    //agregamos uno más
    query = query.Where(p => p.ProductID > 10);

    //y magia se arma la consulta completa
    var result = query.ToArray();         
}

 

Mapeos locos

A modo de regalo dejo un lindo ejemplo que demuestra como L2S mapea un resultado a cualquier tipo que le digamos siempre que pueda resolverlo, simplemente creo la clase Dummy que tiene un par de propiedades que coinciden con Product.

    /// <summary>
    /// Ejemplo sobre cómo el framework de LinqToSql hace el mejor esfuerzo para
    /// mapear un resultado a un tipo de objeto que nosotros le digamos
    /// </summary>
    public static void MapearOtraCosa()
    {
        //context Linq2Sql
        DBDataContext _ctx = new DBDataContext();

        //Generamos la consulta
        var r = from p in _ctx.Products
                select p;

        //en lugar de ejecutarla
        //recuperamos el command
        var c = _ctx.GetCommand(r);

        //ejecutamos la consulta asincrónicamente y además le decimos que el resultado
        //lo mapee al tipo Dummy intentando hacer coincidir los nobmres de las
        //propiedades
        var result = _ctx.ExecuteQuery(typeof(Dummy), c.CommandText);
    }
}

public class Dummy
{
    public int ProductID { get; set; }
    public string Name { get; set; }
}

Mágico, nos vemos la próxima.