c# - ¿Cuál es el aspecto más difícil o más mal entendido de LINQ?
c#-3.0 (30)
Antecedentes: Durante el próximo mes, daré tres charlas sobre o al menos LINQ
a LINQ
en el contexto de C#
. Me gustaría saber a qué temas vale la pena prestarles una gran atención, en función de lo que a las personas les resulta difícil de entender o de lo que pueden dar una impresión equivocada. No LINQ
específicamente sobre LINQ
to SQL
o Entity Framework, excepto como ejemplos de cómo se pueden ejecutar consultas de forma remota utilizando árboles de expresión (y generalmente IQueryable
).
Entonces, ¿qué has encontrado difícil acerca de LINQ
? ¿Qué has visto en términos de malentendidos? Algunos ejemplos pueden ser los siguientes, ¡pero no se limite!
- Cómo el compilador de
C#
trata las expresiones de consulta - Expresiones lambda
- Arboles de expresion
- Metodos de extension
- Tipos anónimos
-
IQueryable
- Ejecución diferida vs inmediata
- Streaming vs ejecución en búfer (por ejemplo, OrderBy está diferido pero en búfer)
- Variables locales tipificadas implícitamente
- Lectura de firmas genéricas complejas (por ejemplo, Enumerable.Join )
Consultas compiladas
El hecho de que no se pueda encadenar a IQueryable
porque son llamadas de método (¡aunque no sea nada más que SQL traducible!) Y que es casi imposible solucionarlo es sorprendente y crea una gran violación de DRY. Necesito mi IQueryable
''s para ad-hoc en el que no tengo consultas compiladas (solo tengo consultas compiladas para los escenarios pesados), pero en las consultas compiladas no puedo usarlas y, en cambio, necesito escribir la sintaxis de las consultas nuevamente. . Ahora estoy haciendo las mismas subconsultas en 2 lugares, debo recordar actualizar tanto si algo cambia, y así sucesivamente. Una pesadilla.
Algo de lo que no me di cuenta originalmente era que la sintaxis de LINQ no requiere que IEnumerable<T>
o IQueryable<T>
funcionen, LINQ se trata solo de la coincidencia de patrones.
texto alt http://bartdesmet.info/images_wlw/QIsIQueryabletheRightChoiceforMe_13478/image_thumb_3.png
Aquí está la respuesta (no, no escribí ese blog, lo hizo Bart De Smet, y es uno de los mejores bloggers sobre LINQ que he encontrado).
Algunos de los mensajes de error, especialmente de LINQ a SQL pueden ser bastante confusos. mueca
He sido mordido por la ejecución diferida un par de veces como todos los demás. Creo que lo más confuso para mí ha sido el proveedor de consultas de SQL Server y lo que puede y no puede hacer con él.
Todavía estoy sorprendido por el hecho de que no se puede hacer una suma () en una columna decimal / dinero que a veces está vacía. Usar DefaultIfEmpty () simplemente no funcionará. :(
Carga lenta.
Como dijo la mayoría de la gente, creo que la parte más incomprendida es asumir que LINQ es solo un reemplazo para T-SQL. Mi gerente, que se considera a sí mismo como un gurú de TSQL, no nos dejaría usar LINQ en nuestro proyecto e incluso odia a MS por lanzar una cosa así.
Como dijo la mayoría de la gente, creo que la parte más incomprendida es asumir que LINQ es solo un reemplazo para T-SQL. Mi gerente, que se considera a sí mismo como un gurú de TSQL, no nos dejaría usar LINQ en nuestro proyecto e incluso odia a MS por lanzar una cosa así.
Como se mencionó, carga diferida y ejecución diferida.
Cómo LINQ to Objects y LINQ to XML (IEnumerable) son diferentes de LINQ to SQL (IQueryable)
CÓMO crear una capa de acceso a datos, una capa de negocios y una capa de presentación con LINQ en todas las capas ... y un buen ejemplo.
Creo que la parte mal entendida de LINQ es que es una extensión de lenguaje , no una extensión o construcción de base de datos.
LINQ
es mucho más que LINQ to SQL
.
Ahora que la mayoría de nosotros hemos usado LINQ
en las colecciones, ¡NUNCA volveremos!
LINQ
es la característica más importante para .NET desde Generics en 2.0 y Tipos anónimos en 3.0.
¡Y ahora que tenemos Lambda''s, no puedo esperar para la programación paralela!
Creo que el hecho de que una expresión Lambda
pueda resolver tanto en un árbol de expresiones como en un delegado anónimo, puede pasar la misma expresión lambda
declarativa tanto a los métodos de extensión IQueryable<T>
métodos de extensión IEnumerable<T>
.
Creo que la idea errónea # 1 sobre LINQ to SQL es que TODAVÍA TIENE QUE SABER SQL para poder hacer un uso efectivo de ella.
Otra cosa mal entendida acerca de Linq to Sql es que aún tiene que reducir la seguridad de su base de datos hasta el punto de absurdo para que funcione.
Un tercer punto es que el uso de Linq to Sql junto con las clases dinámicas (lo que significa que la definición de la clase se crea en tiempo de ejecución) provoca una enorme cantidad de compilación justo a tiempo. Lo que absolutamente puede matar el rendimiento.
Creo que una gran cosa para cubrir en LINQ es cómo puede meterse en problemas en cuanto al rendimiento. Por ejemplo, usar el recuento de LINQ como condición de bucle no es realmente inteligente.
Ejecución retrasada
En LINQ to SQL veo constantemente que las personas no entienden el DataContext, cómo se puede usar y cómo se debería usar. Demasiadas personas no ven el DataContext por lo que es, un objeto de Unidad de Trabajo, no un objeto persistente.
He visto muchas ocasiones en las que las personas intentan individualizar un DataContext / session it / etc en lugar de hacer una nueva hora para cada operación.
Y luego está desechando el DataContext antes de que el IQueryable haya sido evaluado, pero eso es más bien un problema con las personas que no entienden IQueryable que el DataContext.
El otro concepto con el que veo mucha confusión es con Sintaxis de consulta frente a Sintaxis de expresión. Usaré el que sea más fácil en ese momento, a menudo con la sintaxis de expresión. Muchas personas aún no se dan cuenta de que producirán lo mismo al final, después de todo, Query se compila en Expression.
Entendiendo cuando la abstracción entre los proveedores de Linq se filtra. Algunas cosas funcionan con objetos pero no con SQL (por ejemplo, .TakeWhile). Algunos métodos pueden traducirse a SQL (ToUpper) mientras que otros no pueden. Algunas técnicas son más eficientes en objetos donde otras son más efectivas en SQL (diferentes métodos de unión).
Lo fácil que es anidar un bucle es algo que no creo que todos entiendan.
Por ejemplo:
from outerloopitem in outerloopitems
from innerloopitem in outerloopitem.childitems
select outerloopitem, innerloopitem
Me tomó demasiado tiempo darme cuenta de que muchos métodos de extensión LINQ como Single()
, SingleOrDefault()
etc. tienen sobrecargas que llevan lambdas.
Tu puedes hacer :
Single(x => x.id == id)
y no necesito decir esto, lo cual me dio la costumbre de hacer algún tutorial malo.
Where(x => x.id == id).Single()
No sé si califica como incomprendido, pero para mí, simplemente desconocido.
Me complació aprender sobre DataLoadOptions y cómo puedo controlar qué tablas se unen cuando realizo una consulta en particular.
Vea aquí para más información: MSDN: DataLoadOptions
OK, debido a la demanda, he escrito algunas de las cosas de Expression. No estoy 100% satisfecho con la forma en que el blogger y LiveWriter han conspirado para formatearlo, pero por ahora lo hará ...
De todos modos, aquí va ... Me encantaría cualquier comentario, especialmente si hay áreas donde la gente quiere más información.
Aquí está , me gusta o lo odias ...
Por mi parte, me gustaría saber si necesito saber qué son los árboles de expresiones y por qué.
Que IQueryable acepte ambos, Expression<Func<T1, T2, T3, ...>>
y Func<T1, T2, T3, ...>
, sin dar una pista sobre la degradación del rendimiento en el segundo caso.
Aquí está el ejemplo del código, que demuestra lo que quiero decir:
[TestMethod]
public void QueryComplexityTest()
{
var users = _dataContext.Users;
Func<User, bool> funcSelector = q => q.UserName.StartsWith("Test");
Expression<Func<User, bool>> expressionSelector = q => q.UserName.StartsWith("Test");
// Returns IEnumerable, and do filtering of data on client-side
IQueryable<User> func = users.Where(funcSelector).AsQueryable();
// Returns IQuerible and do filtering of data on server side
// SELECT ... FROM [dbo].[User] AS [t0] WHERE [t0].[user_name] LIKE @p0
IQueryable<User> exp = users.Where(expressionSelector);
}
Que hay más que solo LINQ
to SQL
y las características son más que un simple analizador de SQL
incrustado en el lenguaje.
Sé que el concepto de ejecución diferida ya debería estar dentro de mí, pero este ejemplo realmente me ayudó a comprenderlo:
static void Linq_Deferred_Execution_Demo()
{
List<String> items = new List<string> { "Bob", "Alice", "Trent" };
var results = from s in items select s;
Console.WriteLine("Before add:");
foreach (var result in results)
{
Console.WriteLine(result);
}
items.Add("Mallory");
//
// Enumerating the results again will return the new item, even
// though we did not re-assign the Linq expression to it!
//
Console.WriteLine("/nAfter add:");
foreach (var result in results)
{
Console.WriteLine(result);
}
}
El código anterior devuelve lo siguiente:
Before add:
Bob
Alice
Trent
After add:
Bob
Alice
Trent
Mallory
Soy bastante nuevo en LINQ. Aquí están las cosas con las que tropecé en mi primer intento
- Combinando varias consultas en una sola.
- Depuración efectiva de las consultas LINQ en Visual Studio.
Todavía tengo problemas con el comando "dejar" (para el cual nunca he encontrado un uso) y con SelectMany (que he usado, pero no estoy seguro de haberlo hecho bien)
Transacciones (sin usar TransactionScope)
Un par de cosas.
- Gente pensando en Linq como Linq a SQL.
- Algunas personas piensan que pueden comenzar a reemplazar todas las consultas foreach / logic con las consultas de Linq sin tener en cuenta estas implicaciones de rendimiento.
Yo diría que el aspecto más incomprendido (¿o debería ser no entendido?) De LINQ es IQueryable y los proveedores de LINQ personalizados .
He estado usando LINQ por un tiempo y me siento completamente cómodo en el mundo de IEnumerable, y puedo resolver la mayoría de los problemas con LINQ.
Pero cuando comencé a leer y leer sobre IQueryable, y los proveedores de Expressions y linq personalizados, me hizo dar vueltas. Eche un vistazo a cómo funciona LINQ to SQL si desea ver una lógica bastante compleja.
Espero entender ese aspecto de LINQ ...
Gran notación de O LINQ hace que sea increíblemente fácil escribir algoritmos O (n ^ 4) sin darse cuenta, si no sabes lo que estás haciendo.
group by
todavía hace girar mi cabeza.
Cualquier confusión sobre la ejecución diferida debería poder resolverse al pasar por un código simple basado en LINQ y jugar en la ventana del reloj.
¿Qué representa var cuando se ejecuta una consulta?
Es iQueryable
, iSingleResult
, iMultipleResult
, o cambia en función de la implementación. Existe cierta especulación sobre el uso de (lo que parece ser) la tipificación dinámica frente a la tipificación estática estándar en C #.