Sector 7G

Sector7G Live Search

About Me

About Me

Windows Live Messenger Presence Gadget

My Photo Albums

My Photo Web Albums

Logos

  • Sector7G
  • ilitia Technologies


Kartones.Net MVF Winner

April 2008 - Posts

Ejecución de consultas en LINQ

En LINQ las consultas pueden ser ejecutadas de dos formas diferentes. Mediante ejecución inmediata, la consulta devuelve los resultados en el mismo momento en el que es definida, es decir, en el caso de LINQ To SQL el acceso a la base de datos se ejecuta cuando la sentencia es construida. Y mediante ejecución diferida, la sentencia LINQ es creada y su ejecución se produce cuando el resultado es enumerado, al hacer un foreach por ejemplo.

Ejecución diferida en LINQ

Una consulta es de ejecución diferida, cuando la ejecución de la consulta se produce en el momento de ser enumerado el resultado, no en el instante de ser creada. Para entender esto mejor veamos el siguiente ejemplo, ¿cuál es el resultado?.

List<string> blogs = new List<string> { 
    "Sector 7G", "KaRt0nEs Blog", "La Web de Programación",  
    "Code, Freak and Videotape", "Dave Dan", "Frankys", "FreakWorld", 
    "Haztelo Tu", "Jad Engine Blog", "Lobo666 Blog", "MAD-MAX", 
    "Mi Ubuntu y yo", "Myrjam's Blog", "NetCódigo e Internet",  
    "The Elder Thoughts", "The Spike", "Berks Worlds"
};
 
var names = from b in blogs
                where b.EndsWith("7G")
                select b;
 
blogs[1] = "KaRt0nEs Blog 7G";
 
foreach (var item in names)
{
    Console.WriteLine(item);
}

Seguramente en un primer momento pienses que el resultado es:


Sector 7G

Pero realmente el resultado de ejecutar esa sentencia LINQ es:


Sector 7G
KaRtOnEs Blog 7G

Esto es debido a que cuando la sentencia es definida dentro del objeto names, ésta todavía no ha sido ejecutada, es decir, todavía no se han devuelto los resultados. Este objeto almacenado dentro de names ya implementa la interfaz IEnumerable<string>.

var names = from b in blogs
                where b.EndsWith("7G")   <- La consulta no se
                select b;                   ejecuta aquí.

Así que hasta este punto names sólo sabe que tiene que hacer, pero todavía no ha hecho nada. La consulta será ejecuta, cuando ésta esa enumerada a través del método GetEnumerator, el cual hace uso del operador yield. Así que hasta que el foreach no es ejecutado no tiene lugar la consulta, es decir,  la consulta no se ha ejecutada realmente. De esta manera, al verse alterada la colección blogs antes del foreach, el resultado esperado también se ha visto alterado.

foreach (var item in names)     <- Aquí es cuando la consulta
{                                  tiene lugar.
    Console.WriteLine(item); 
}

Por este motivo, por ejemplo en LINQ to SQL, una consulta que es ejecutada varias veces puede tener resultados diferentes. Si no se quiere que esto ocurra, se puede hacer que la consulta sea de ejecución inmediata. Para que una consulta se ejecute nada más definirla se pueden usar cualquiera de estos métodos: ToArray, ToList, ToLookup, ToDictionary, etc (ver el listado de operadores inmediatos). Estos métodos cambian la estructura de datos de datos y cachean el resultado.

Listado de operadores de ejecución diferida:

Operador Operator Name
Conversion Cast, OfType, AsEnumerable
Element DefaultIfEmpty
Generation Empty, Range, Repeat
Grouping GroupBy
Union GroupJoin, Join
Ordination OrderBy, ThenBy, OrderByDescending, ThenByDescending, Reverse
Partition Skip, SkipWhile, Take, TakeWhile
Restriction Where
Selection Select, SelectMany
Set Concat, Distinct, Except, Intersect, Union

Evidentemente esto tiene sus beneficios y sus inconvenientes, sólo hay que conocerlo para poder sacar el mayor provecho.

Ejecución inmediata

Una consulta es de ejecución inmediata, cuando ésta es ejecutada en el momento de su definición. Para conseguir forzar la ejecución de una consulta, sólo hay que usar cualquiera de los operadores que se muestran en la lista de abajo. Estos operadores lo que hacen es cambiar la estructura de datos devuelta por la consulta y cachear el resultado.

var names = (from b in blogs
                where b.EndsWith("7G")
                select b).ToList();   <- La consulta SÍ es ejecutada
                                         aquí.
 
foreach (var item in names)
{
    Console.WriteLine(item);
}

Esta vez el resultado si es:


Sector 7G

Listado de operadores de ejecución inmediata:

Operador Operator Name
Aggregation Aggregate, Average, Count, LongCount, Max, Min, Sum
Conversion ToArray, ToDictionary, ToList, ToLookup
Element ElementAt, ElementAtOrDefault, First, FirstOrDefault, Last, LastOrDefault, Single, SingleOrDefault
Equality SequenceEqual
Quantifiers All, Any, Contains

Posted: Apr 19 2008, 09:09 PM by Pedroafa | with no comments
Filed under: , ,
Sintaxis LINQ: Average

El operador Average calcula la média aritmética de una colección de registros. Las signaturas del método son las siguientes:

   1:  public static decimal Average(
   2:      this IEnumerable<decimal> source)
   3:   
   4:  public static double Average(
   5:      this IEnumerable<int> source)
   6:   
   7:  public static Nullable<decimal> Average(
   8:      this IEnumerable<Nullable<decimal>> source)
   9:   
  10:  public static Nullable<double> Average(
  11:      this IEnumerable<Nullable<double>> source)
  12:   
  13:  public static double Average(
  14:      this IEnumerable<long> source)
  15:   
  16:  public static Nullable<double> Average(
  17:      this IEnumerable<Nullable<int>> source)
  18:   
  19:  public static double Average(
  20:      this IEnumerable<double> source)
  21:   
  22:  public static Nullable<double> Average(
  23:      this IEnumerable<Nullable<long>> source)
  24:   
  25:  public static Nullable<float> Average(
  26:      this IEnumerable<Nullable<float>> source)
  27:   
  28:  public static float Average(
  29:      this IEnumerable<float> source)
  30:   
  31:  public static decimal Average<TSource>(
  32:      this IEnumerable<TSource> source, 
  33:      Func<TSource, decimal> selector)
  34:   
  35:  public static double Average<TSource>(
  36:      this IEnumerable<TSource> source, 
  37:      Func<TSource, double> selector)
  38:   
  39:  public static double Average<TSource>(
  40:      this IEnumerable<TSource> source, 
  41:      Func<TSource, int> selector)
  42:   
  43:  public static double Average<TSource>(
  44:      this IEnumerable<TSource> source, 
  45:      Func<TSource, long> selector)
  46:   
  47:  public static Nullable<decimal> Average<TSource>(
  48:      this IEnumerable<TSource> source, 
  49:      Func<TSource, Nullable<decimal>> selector)
  50:   
  51:  public static Nullable<double> Average<TSource>(
  52:      this IEnumerable<TSource> source, 
  53:      Func<TSource, Nullable<double>> selector)
  54:   
  55:  public static Nullable<double> Average<TSource>(
  56:      this IEnumerable<TSource> source, 
  57:      Func<TSource, Nullable<int>> selector)
  58:   
  59:  public static Nullable<double> Average<TSource>(
  60:      this IEnumerable<TSource> source, 
  61:      Func<TSource, Nullable<long>> selector)
  62:   
  63:  public static Nullable<float> Average<TSource>(
  64:      this IEnumerable<TSource> source, 
  65:      Func<TSource, Nullable<float>> selector)
  66:   
  67:  public static float Average<TSource>(
  68:      this IEnumerable<TSource> source, 
  69:      Func<TSource, float> selector)

Cómo se puede observar este método tiene una sobrecarga para cada tipo numérico.

Veamos un ejemplo y cómo se utilizaría el método en cuestión.

   1:  double average = (from n in numeros
   2:                    select n).Average();
   3:   
   4:  double average = numeros.Average();

Cómo se puede ver en los ejemplos este método carece de palabra clave o alias.

Cast vs OfType en LINQ

LINQ no puede trabajar con colecciones que no implementen la interfaz IEnumerable<T>. Esto es debido a que no se encuentran fuertemente tipadas. Por este motivo dentro de un ArrayList podríamos encontrarnos tanto elementos de tipo string como de tipo integer.

ArrayList products = new ArrayList{
    new Product { Name= "Product1"},
    new Product { Name= "Product2"},
    1
};

Esto ocurre con todos los tipos de colecciones que se encuentran dentro del namespace System.Colleccitons:

En este punto entran en juego los métodos Cast<T> y OfType<T>. Estos métodos son capaces de convertir una colección que no implemente la interfaz IEnumerable<T>, en una que si lo haga. De esta manera es posible utilizar este tipo de colecciones dentro de LINQ.

var items = products.OfType<Product>()
                .Where(p => p.Name.EndsWith("1"));
 
foreach (var item in items)
{
    Console.WriteLine(item.Name);
}


Product1

La diferencia que existe entre los dos métodos es que en el caso de Cast, si dentro de la colección se encuentra un elemento que no pueda ser convertido al tipo marcado, se lanzará una excepción. En el caso de OfType, si se encuentra un elemento que no se pueda convertir al tipo indicado, este se desecha.

var items = products.Cast<Product>()
                        .Where(p => p.Name.EndsWith("1"));
 
var item in items)
{
    Console.WriteLine(item.Name);
}


Product1
Invalid cast from ‘Sistem.Int32’ to SampleLinq.Product’.

Posted: Apr 16 2008, 08:41 PM by Pedroafa | with 1 comment(s)
Filed under: ,
Twitter Gadget

Twitter follower twitter follower twitter follower, ¿Quién gana: 'Twitter' o 'follower'?.

Tras un primer intento de hacer un gadget que consumirá los post de Twitter (ver demo). Diego y yo nos quedamos con las ganas de hacer una versión del mismo con Silverlight. Así que el otro día que tenía algo de tiempo me puse manos a la obra. El resultado final se puede ver en esta Live Demo o en la parte izquierda de mi blog.

twitter gadget

Para poder utilizar el gadget dentro de un blog o una web, sólo hay que hacer uso de un iframe. La url donde se encuentra hospedado el gadget es http://demos.kartones.net/006/default.html. Esta url hace uso de dos parámetros dentro de su querystring: user, donde se introduce el código de usuario del Twitter y foot que se debe establecer a 0 para esconder el pie de la página. También hay que tener en cuenta que el gadget tiene un tamaño de 150x150 pixeles. El siguiente snippet de código es el que he utilizado para embeberlo dentro de mi blog.

<iframe id="Iframe1" height="150" width="150" frameborder="0" scrolling="no" src="http://demos.kartones.net/006/default.html?user=9658712&foot=0"></iframe>

Así de sencillo es embeber el gadget dentro de una web :).

Gadget Enjoin!!.