2009-04-28 26 views
12

A continuación se incluyen dos consultas que devuelven los mismos datos. Aparte del estilo, no estoy seguro de cuál es mejor.Cuál es la diferencia entre las expresiones de consulta LINQ y los métodos de extensión

¿Qué factores influyen en estas consultas? ¿Cuáles son los beneficios de usar un estilo sobre el otro?

Muestra 1

var x = from s in db.Surveys 
    join sq in db.Survey_Questions on s.ID equals sq.Survey_ID 
    join q in db.Questions on sq.Question_ID equals q.ID 
    join qg in db.Question_Groups on q.ID equals qg.Question_ID 
    where s.Type_ID.Equals(typeID) & s.Type.Equals(type) 
    select new { question = sq.Question, status = sq.Status, grp = qg }; 

Muestra 2

var x = db.Surveys.Where(s => s.Type_ID.Equals(typeID) & s.Type.Equals(type)) 
       .Join(db.Survey_Questions, 
         s => s.ID, 
         sq => sq.Survey_ID, 
         (s, sq) => new 
         { 
          question = sq.Question, 
          status = sq.Status 
         }) 
       .Join(db.Question_Groups, 
         q => q.question.ID, 
         qg => qg.Question_ID, 
         (q, qg) => new 
         { 
          question = q.question, 
          status = q.status, 
          group = qg 
         }).ToList(); 
+0

sus vale la pena mencionar sus muestras no son idénticos ... –

+0

También el .ToList() a las fuerzas finales de ejecución muy diferente. Déjelo apagado para que sea equivalente. La primera x es de tipo IQueryable y la segunda es IList . –

Respuesta

19

Actualización: Ha corregido su título, por lo tanto, ignórelo.

El título de su pregunta no tiene nada que ver con los ejemplos de su código. Su pregunta implica que una sintaxis es IEnumerable y la otra es IQueryable, pero esto es incorrecto. En sus muestras, si db.Surveys es un IQueryable, entonces ambos sus muestras están usando IQueryable. Trataré de responder ambas preguntas.

Los dos ejemplos de código son simplemente formas diferentes de escribir las mismas consultas LINQ (suponiendo que estén bien escritas). El código en la muestra 1 es solo una abreviatura del código en la muestra 2. El compilador trata el código en ambas muestras de la misma manera. Piense en la forma en que el compilador de C# tratará int? de la misma manera que Nullable<System.Int32>. Los lenguajes C# y VB.Net proporcionan esta sintaxis de consulta abreviada. Es posible que otros idiomas no tengan esta sintaxis y deberá usar la sintaxis de la muestra 2. De hecho, es posible que otros lenguajes ni siquiera admitan métodos de extensión o expresiones lambda, y usted tendría que usar una sintaxis más fea aún.


Actualización:

Para tomar el ejemplo de Sander aún más, al escribir esto (la sintaxis de la comprensión de la consulta):

var surveyNames = from s in db.Surveys select s.Name 

Usted piensa el compilador vueltas que forma abreviada en este (métodos de extensión y expresión lambda):

IQueryable<string> surveryNames = db.Surveys.Select(s => s.Name); 

Pero en realidad los métodos de extensión y las expresiones lambda son taquigrafía.Los compiladores emite algo como esto (no exactamente, pero sólo para dar una idea):

Expression<Func<Survey, string>> selector = delegate(Survey s) { return s.Name; }; 
IQueryable<string> surveryNames = Queryable.Select(db.Surveys, selector); 

Tenga en cuenta que Select() es sólo un método estático de la clase Queryable. Si su lenguaje .NET no admite sintaxis de consulta, lambdas o métodos de extensión, de alguna manera tendrá que escribir el código usted mismo.


¿Cuáles son los beneficios de usar un estilo sobre el otro?

Para pequeñas consultas, métodos de extensión pueden ser más compacta:

var items = source.Where(s => s > 5); 

Además, la sintaxis método de extensión puede ser más flexible, tal como condicional donde cláusulas:

var items = source.Where(s => s > 5); 

if(smallerThanThen) 
    items = items.Where(s => s < 10); 
if(even) 
    items = items.Where(s => (s % 2) == 0); 

return items.OrderBy(s => s); 

Además , varios métodos solo están disponibles a través de la sintaxis del método de extensión (Count(), Aggregate(), Take(), Skip(), ToList(), ToArray(), etc.), así que si uso uno de estos, I ' Normalmente escribiré toda la consulta en esta sintaxis para evitar mezclar b otras sintaxis

var floridaCount = source.Count(s => s.State == "FL"); 

var items = source 
      .Where(s => s > 5) 
      .Skip(5) 
      .Take(3) 
      .ToList(); 

Por otra parte, cuando una consulta se hace más grande y más compleja, la sintaxis comprensión consulta puede ser más claro, sobre todo una vez que comience complicando con unos pocos let, group, join, etc.

En el Fin usualmente usaré el que funcione mejor para cada consulta específica.


Actualización: usted fijó su título, así que ignore el resto ...

Ahora, sobre su título: Con respecto a LINQ, IEnumerable y IQueryable son muy similares. Ambos tienen prácticamente los mismos métodos de extensión (Seleccionar, Dónde, Contar, etc.), siendo la principal (¿única?) Diferencia que IEnumerable toma Func<TIn,TOut> como parámetros e IQueryable toma Expression<Func<TIn,TOut>> como parámetros. Expresas ambos de la misma manera (generalmente expresiones lamba), pero internamente son completamente diferentes.

IEnumerable es la puerta de entrada a LINQ to Objects. Se pueden invocar los métodos de extensión LINQ to Objects en cualquier IEnumerable (matrices, listas, cualquier cosa que pueda iterar con foreach) y el Func<TIn,TOut> se convierte a IL en tiempo de compilación y se ejecuta como un código de método normal en tiempo de ejecución. Tenga en cuenta que algunos otros proveedores de LINQ utilizan IEnumerable y, de hecho, están utilizando LINQ to Objects tras bastidores (LINQ to XML, LINQ to DataSet).

IQueryable es utilizado por LINQ to SQL, LINQ to Entities y otros proveedores de LINQ que necesitan examinar su consulta y traducirla en lugar de ejecutar su código directamente. Las consultas IQueryable y sus Expression<Func<TIn,TOut>> s no se compilan en IL en el momento de la compilación. En su lugar, se crea un árbol de expresión que se puede examinar en tiempo de ejecución. Esto permite que las declaraciones se traduzcan a otros lenguajes de consulta (por ejemplo, T-SQL). Un árbol de expresiones se puede compilar en un Func < TIn, TOut > en tiempo de ejecución y se puede ejecutar si se desea.

Encontrará un ejemplo que ilustra la diferencia en this question donde OP desea hacer parte de una consulta LINQ to SQL en SQL Server, llevar los objetos al código administrado y hacer el resto de la consulta en LINQ to Objects . Para lograr esto, todo lo que tiene que hacer es convertir el IQueryable en un IEnumerable donde quiera que ocurra el cambio.

3

LINQ es palabra de moda para una tecnología.

IQueryable es una interfaz .NET que utiliza LINQ.

Aparte del estilo, no hay diferencia entre los dos. Use el estilo que prefiera.

Prefiero el primer estilo para el enunciado largo (como el que se muestra aquí) y el segundo para los enunciados muy breves.

0

Creo que su pregunta es mejor lo expresó de esta manera, "¿Cuál es la diferencia entre IEnumerable <T> y IQueryable <T> con respecto a LINQ"

consultas LINQ devuelven un IQueryable <T> por defecto. IQueryable <T> le permite agregar otros filtros o "cláusulas" a su consulta antes de ejecutarla.

Su consulta LINQ (primer ejemplo) y su LINQ utilizando el método de encadenamiento (segundo ejemplo) producen el mismo resultado, con una sintaxis diferente.

Es posible escribir una consulta LINQ como una cadena de métodos LINQ y viceversa. Realmente depende de tu preferencia.

@Lucas: El diferente es IEnumerable <T> hace consultas en memoria y IQueryable <T> hace fuera de la memoria. Es decir, una vez que está en un iterador foreach, está utilizando IEnumerable, y cuando está construyendo su consulta, ya sea a través de métodos de extensión o utilizando LINQ from o in object synatax, está construyendo un IQueryable <T>. El IQueryable <T> se ejecuta tan pronto como toca el Enumerador.

+0

"Las consultas LINQ devuelven un IQueryable de forma predeterminada." Quiere decir LINQ to SQL o LINQ to Entities. LINQ to Objects usa IEnumerable – Lucas

+0

"IQueryable le permite agregar otros filtros o" cláusulas "a su consulta antes de ejecutarlo." También lo hace IEnumerable. – Lucas

+0

oh y el título de la la pregunta fue arreglada :) – Lucas

1

1./El título de su pregunta no coincide con lo que pidió.
2./Su título de pregunta realmente no tiene sentido. Linq significa Language Integrated Query y es un término genérico para un grupo de tecnologías y prácticas, IQueryable es una interfaz que se usa comúnmente para facilitar Linq. está comparando manzanas y naranjas
3./Sobre su pregunta real, la principal diferencia es el estilo, para consultas complejas como esta, mi preferencia personal es la segunda versión, ya que muestra claramente la progresión de los conjuntos de resultados.

2

La cláusula where en el primer ejemplo es en realidad solo azúcar sintáctica para la cláusula Where en su segundo método. De hecho, puedes escribir tu propia clase que no tenga nada que ver con Linq o IQueryable y con solo tener un método Where, puedes usar ese azúcar sintáctico.Por ejemplo:

public class MyClass 
    { 

     public MyClass Where<T>(Func<MyClass, T> predicate) 
     { 
      return new MyClass { StringProp = "Hello World" }; 
     } 

     public MyClass Select<T>(Func<MyClass, T> predicate) 
     { 
      return new MyClass(); 
     } 



     public string StringProp { get; set; } 
    } 

Esto es obviamente un ejemplo tonto, pero tenga en cuenta que hay un caso de método que sólo devuelve un nuevo MiClase con stringprop ajustado a Hello World. Para demostrar:

MyClass a = new MyClass(); 
      var q = from p in a 
        where p.StringProp == "foo" // doesnt matter what we put here, as we're not really checking the predicate 
        select p; 
      Console.WriteLine(q.StringProp); 

Esto dará como resultado la escritura de "Hello World". Nuevamente, este ejemplo es obviamente inútil, pero prueba el hecho de que la sintaxis "donde" solo busca un método Where en su código que toma un Func.

2

Las expresiones de consulta y los métodos de extensión son dos formas de hacer exactamente lo mismo. Las expresiones de consulta se transforman en métodos de extensión al compilar: son solo azúcar sintáctico para las personas que se sienten más cómodas con SQL.

Cuando se escribe esto:

var surveyNames = from s in db.Surveys select s.Name; 

El compilador transforma esto en:

IQueryable<string> surveryNames = db.Surveys.Select(s => s.Name); 

Realmente, creo que las expresiones de consulta se acaba de crear por razones de marketing - una construcción del lenguaje similar a SQL para actuar como un punto de atracción cuando se desarrolló LINQ, no es algo que ofrece mucho uso real. Encuentro que la mayoría de la gente simplemente usa los métodos de extensión directamente, ya que resultan en un estilo de codificación más unificado, en lugar de una combinación de C# y SQL.

1

Su Sample1 es una representación de alto nivel de LINQ, es más fácil de leer, y durante la compilación que va a convertir en el árbol de expresión es decir Sample2.

var x = from s in db.Surveys 
    join sq in db.Survey_Questions on s.ID equals sq.Survey_ID 
    join q in db.Questions on sq.Question_ID equals q.ID 
    join qg in db.Question_Groups on q.ID equals qg.Question_ID 
    where s.Type_ID.Equals(typeID) & s.Type.Equals(type) 
    select new { question = sq.Question, status = sq.Status, grp = qg }; 

se puede tratar a continuación código para obtener la expresión de consulta escrita se utilizan

var exp=x.Expression; 

Expresiones cuando la consulta menos complicado

0

Otro punto a destacar es que los métodos de extensión LINQ se adhieren al lenguaje C# mientras que el material de comprensión de consultas está preprocesado como está integrado en el compilador. es decir, puede navegar a la definición de .Elija (x => mientras que no se puede por from ... where ... select

Cuestiones relacionadas