2011-03-23 26 views
10

¿Qué método se consideraría la mejor práctica para analizar una cadena LINQ en una consulta?Analizar cadena en una consulta LINQ

O en otras palabras, qué enfoque tiene más sentido para convertir:

string query = @"from element in source 
        where element.Property = ""param"" 
        select element"; 

en

IEnumerable<Element> = from element in source 
         where element.Property = "param" 
         select element; 

asumiendo que source se refiere a un IEnumerable<Element> o IQueryable<Element> en el ámbito local.

+0

Lamentablemente, esto va a ser difícil. Espero que alguien me sorprenda y demuestre que estoy equivocado, pero no espero que suceda. – Jon

+2

No responde exactamente su pregunta, pero muy cerca http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library .aspx –

+2

Suena como lo que www.linqpad.net haría ... pero no sé CÓMO lo hacen. –

Respuesta

0

Si bien esto no da un ejemplo concreto para responder a su pregunta, habría pensado la mejor práctica sería en general para construir un árbol de expresión de la cadena.

En la pregunta this pregunté cómo filtrar una consulta de linq con una cadena que muestra que se crea una parte de un árbol de expresiones. Sin embargo, este concepto se puede extender para construir un árbol de expresiones completo que represente su cadena.

Ver este artículo de Microsoft.

Probablemente haya otros mensajes mejores por ahí también. Además creo que algo como RavenDB hace esto ya en su base de código para definir índices.

4

Requiere un análisis de texto y un uso intensivo de System.Linq.Expressions. He hecho algunas jugadas con este here y here. El código en el segundo artículo está algo actualizado desde el principio, pero sigue siendo difícil. He seguido jugando con esto en alguna ocasión y tengo una versión más limpia que he querido publicar si le interesa. Lo tengo bastante cerca de admitir un buen subconjunto de ANSI SQL 89.

2

Necesitará un analizador de lenguaje C# (al menos v3.5, posiblemente v4.0, según el idioma C# que tenga) deseo apoyar en LINQ). Tomará esos resultados del analizador y los alimentará directamente en un árbol de Expresión usando un patrón de visitante. Todavía no estoy seguro pero estoy dispuesto a apostar que también necesitará algún tipo de análisis de tipo para generar completamente los nodos de Expresión.

Estoy buscando lo mismo que usted, pero realmente no lo necesito tanto, así que no he buscado mucho ni he escrito ningún código en esta línea.

He escrito algo que toma la entrada de cadena de usuario y la compila en un ensamblado dinámico utilizando la clase de proveedor de compilador Microsoft.CSharp.CSharpCodeProvider. Si solo quiere tomar cadenas de código y ejecutar el resultado, esto le conviene.

Aquí está la descripción de la herramienta de consola que escribí, LinqFilter:

http://bittwiddlers.org/?p=141

Aquí está el repositorio de código fuente. LinqFilter/Program.cs muestra cómo utilizar el compilador para compilar la expresión LINQ:

http://bittwiddlers.org/viewsvn/trunk/public/LinqFilter/?root=WellDunne

+0

Se produce una idea: si era paranoico con que la cadena tuviera que ser una expresión, podría usar el 'CSharpCodeProvider' y generar un código en la línea' Expresión > query = (CÓDIGO LINQ AQUÍ); 'y luego Tendrá el árbol de expresiones creado para usted por el compilador. Solo se trata de una llamada 'Compile()' para recuperar un delegado y ejecutar un reflejo para encontrar el método del ensamblado dinámico que usted generó para que pueda ejecutarlo. Espero que esto tenga sentido; Estoy dando vueltas aquí jajaja. :) –

+0

Perdóneme, tiene que ser un 'Expresión >>' o 'Expresión >>'. En el código generado, puede concatenar de forma segura de la siguiente manera: 'Expresión >> getQuery =() => (consulta linq aquí);' El compilador solo aceptará expresiones válidas que se pueden analizar en un árbol de Expresión. Para C# v3.5, esto excluye declaraciones y expresiones de asignación. –

+0

Para ejecutar la consulta, tome 'getQuery' y' getQuery.Compile()() '. Los dos pares de paréntesis no son un error aquí. Invoca el método 'Compile()' que le devuelve un delegado e invoca a ese delegado que le devuelve su 'IQueryable ' o el tipo de IQueryable/IEnumerable que espera recuperar. –

1

Comenzando con .NET 4.6 se puede utilizar para analizar CSharpScript LINQ también, suponiendo que la expresión que se desea analizar se encuentra en consulta, esto hará que:

string query = "from element in source where element.Property = ""param"" select element"; 
IEnumerable result = null; 
try 
{ 
    var scriptOptions = ScriptOptions.Default.WithReferences(typeof(System.Linq.Enumerable).Assembly).WithImports("System.Linq"); 
    result = await CSharpScript.EvaluateAsync<IEnumerable>(
      query, 
      scriptOptions, 
      globals: global); 
} catch (CompilationErrorException ex) { 
// 
} 

No se olvide de pasar su (Datos) fuente en la que desea trabajar, con las variables globales para tener acceso a ellas desde el script.