2011-04-07 10 views
6

Lo que sucede detrás de las cortinas cuando se incluyo una función en mi consulta compilada, como hago con DataConvert.ToThema() para convertir un objeto de tabla en mi costumbre objeto de negocio:incluyendo el código de "fuera de línea" en querys compilados

public static class Queries 
{ 
    public static Func<MyDataContext, string, Thema> GetThemaByTitle 
    { 
     get 
     { 
      var func = CompiledQuery.Compile(
       (MyDataContext db, string title) => 
        (from th in elan.tbl_Thema 
        where th.Titel == title 
        select DataConvert.ToThema(th)).Single() 
        ); 
      return func; 
     } 
    } 
} 

public static class DataConvert 
{ 
    public static Thema ToThema(tbl_Thema tblThema) 
    { 
     Thema thema = new Thema(); 

     thema.ID = tblThema.ThemaID; 
     thema.Titel = tblThema.Titel; 
     // and some other stuff 

     return thema; 
    } 
} 

y llamarlo como esto

Thema th = Queries.GetThemaByTitle.Invoke(db, "someTitle"); 

al parecer, la función no se traduce en SQL o algo (¿cómo podría), sino que además no se sostiene cuando me puse un punto de interrupción allí en VS2010.

Funciona sin problemas, pero no entiendo cómo ni por qué. ¿Qué pasa exactamente allí?

Respuesta

2

Su método estático DataConvert.ToThema() simplemente está creando una instancia de un tipo que tiene un constructor predeterminado, y establecer varias propiedades, ¿es correcto? Si es así, no es muy diferente de:

(from th in elan.tbl_Thema 
where th.Titel == title 
select new Thema{ID=th.ThemaID, Titel=th.Titel, etc...} 
).Single()); 

Cuando se llama a Queries.GetThemaByTitle, se está compilando una consulta. (Por cierto, la forma en que lo llama, puede o no proporcionarle algún beneficio de la compilación previa). Ese 'Query' es en realidad un árbol de expresión de código, del cual solo una parte pretende generar código SQL que se envía a la base de datos.

Otras partes generarán código IL que está tomando lo que se devuelve de la base de datos y ponerlo en alguna forma para su consumo. LINQ (EF o L2S) es lo suficientemente inteligente como para poder tomar su llamada de método estático y generar la IL a partir de ella para hacer lo que quiera, y tal vez lo haga con un delegate interno o algo así. Pero, en última instancia, no necesita ser (muy) diferente de lo que se generaría a partir de la sustitución anterior.

Pero tenga en cuenta que esto sucede independientemente de qué tipo es el que recibe; en algún lugar, se está generando un código IL que pone valores DB en un objeto CLR. Esa es la otra parte de esos árboles de expresión.


Si desea una visión más detallada de los árboles de expresión y lo que participan, que tendría que cavar para ti, pero no estoy seguro de su pregunta si eso es lo que busca.

+0

LINQ to EF no puede hacer esto. –

1

Permítanme comenzar señalando que no importa si compila o no su consulta. Observaría los mismos resultados incluso si no compiló previamente.

Técnicamente, como ha señalado Andrew, hacer este trabajo no es tan complicado. Cuando se evalúa su expresión LINQ, un árbol de expresiones se construye internamente. Su función aparece como un nodo en este árbol de expresiones. No hay magia aquí. Podrás escribir esta expresión tanto en L2S como en L2E y se compilará y ejecutará correctamente. Eso es hasta que intentes ejecutar realmente la consulta SQL real contra la base de datos. Aquí es donde comienza la diferencia. L2S parece feliz de ejecutar esta tarea, mientras que L2E falla con NotSupportedException e informa que no sabe cómo convertir ToThema en la consulta de la tienda.

¿Qué está pasando dentro? En L2S, como ha explicado Andrew, el compilador de consultas entiende que su función se puede ejecutar por separado desde que se haya ejecutado la consulta de la tienda. Por lo tanto, emite llamadas a su función en el conducto de lectura de objetos (donde los datos leídos de SQL se transforman en los objetos que se devuelven como resultado de su llamada).

Una vez que Andrew no estaba del todo bien, es que importa lo que hay dentro de su método estático.No creo que lo haga

Si coloca un punto de interrupción en el depurador de su función, verá que se llama una vez por cada fila devuelta. En el seguimiento de la pila verá "Función de peso ligero", que, en realidad, significa que el método se emitió en tiempo de ejecución. Así que así es como funciona para Linq a Sql.

El equipo de Linq to Entity parecía ir por una ruta diferente. No sé cuál fue el razonamiento por el que decidieron prohibir todas las expresiones de invocación de las consultas L2E. Quizás estos fueron motivos de rendimiento, o pueden ser el hecho de que necesitan admitir todo tipo de proveedores, no solo SQL Server, para que los lectores de datos puedan comportarse de manera diferente. O simplemente pensaron que la mayoría de la gente no se daría cuenta de que algunos de ellos se ejecutan por fila devuelta y prefirió mantener esta opción cerrada.

Sólo mis pensamientos. Si alguien tiene algo más de información, ¡por favor entra!

Cuestiones relacionadas