2012-04-02 26 views
24

quiero insertar en mi mesa una columna llamada 'S' que conseguir un poco de valor de cadena basada en un valor que recibe de una columna de tabla.Llamar a un método dentro de una consulta LINQ

Por ejemplo: for each ID (a.z) Quiero recibe su valor de cadena almacenada en otra mesa. El valor de cadena se devuelve desde otro método que lo obtiene a través de una consulta Linq.

  • ¿Es posible llamar a un método desde Linq?
  • ¿Debo hacer todo en la misma consulta?

Esta es la estructura de la información que necesito para obtener:

a.z is the ID in the first square in table #1, from this ID I get another id in table #2, and from that I can get my string value that I need to display under column 'S'.
enter image description here

var q = (from a in v.A join b in v.B 
    on a.i equals b.j 
    where a.k == "aaa" && a.h == 0 
    select new {T = a.i, S = someMethod(a.z).ToString()}) 
    return q; 

La línea S = someMethod(a.z).ToString() causando el error siguiente:

Unable to cast object of type 'System.Data.Linq.SqlClient.SqlColumn' to type 'System.Data.Linq.SqlClient.SqlMethodCall'.

+0

su pregunta es bastante claro (para mí de todos modos) - qué tablas se está refiriendo ? ¿Esto es Linq para Entidades o Linq para Objetos? Los nombres de propiedades y tablas más significativos también podrían ser útiles. – BrokenGlass

+0

Lo siento, soy nuevo en Linq, ¿qué quiere decir con Linq para Entidades o Linq para Objetos? – user990635

+0

Su mensaje de error indica que utiliza Linq en SQL: así es como accede a la base de datos – BrokenGlass

Respuesta

41

Usted tiene que ejecutar su llamada a un método en Linq-to-Objects contexto, porque en el lado de la base de datos que el método de llamada no se tiene sentido - usted puede hacer esto utilizando AsEnumerable() - básicamente el resto de la consulta a continuación, se evaluará como en la recolección de memoria utilizando Linq-to-Objects y se puede utilizar el método llama como se esperaba:

var q = (from a in v.A join b in v.B 
     on a.i equals b.j 
     where a.k == "aaa" && a.h == 0 
     select new {T = a.i, Z = a.z }) 
     .AsEnumerable() 
     .Select(x => new { T = x.T, S = someMethod(x.Z).ToString() }) 
+0

Respuesta excelente, gracias – EgyEast

+0

Solo quiero asegurarme, por lo que itera el Enumerable dos veces, ¿no es así? Primero, antes de '.AsEnumerable()' y en segundo lugar, después de '.AsEnumerable()'? –

8

Usted querrá dividirla hasta en dos declaraciones. Devuelva los resultados de la consulta (que es lo que afectará a la base de datos) y luego enumere los resultados por segunda vez en un paso separado para transformar la traducción en la nueva lista de objetos. Esta segunda "consulta" no afectará a la base de datos, por lo que podrá usar el someMethod() dentro de ella.

Linq-to-Entities es un poco extraño, porque hace que la transición a consultar la base de datos desde C# sea extremadamente fluida: pero siempre hay que recordarse a sí mismo: "Este C# va a traducirse a SQL " Y como resultado, tiene que preguntarse a sí mismo: "¿Se puede ejecutar realmente todo este C# como SQL?" Si no puede, si llama al someMethod() dentro de su consulta, su consulta tendrá problemas. Y la solución habitual es dividirlo.

(La otra respuesta de @BrokenGlass, utilizando .AsEnumerable(), es básicamente otra manera de hacer precisamente eso.)

0

Esa es una vieja pregunta, pero Veo que nadie menciona un "truco", que permite cal l métodos durante seleccionar sin reiterar. Idea es usar constructor y en constructor puedes llamar lo que quieras (al menos funciona bien en LINQ con NHibernate, no estoy seguro acerca de LINQ2SQL o EF, pero supongo que debería ser el mismo). A continuación tengo el código fuente para el programa de referencia, parece que reitera enfoque en mi caso es aproximadamente dos veces más lento que el enfoque de constructor y supongo que no es de extrañar - mi lógica de negocio era mínima, así que cosas como asuntos de iteración y de asignación de memoria.

También me hubiese gustado tener una mejor manera de decir, que tal o cual no debería ser juzgado para ejecutar en la base de datos,

// Here are the results of selecting sum of 1 million ints on my machine: 
// Name Iterations  Percent  
// reiterate  294  53.3575317604356%  
// constructor  551  100% 

public class A 
{ 
    public A() 
    {    
    } 

    public A(int b, int c) 
    { 
     Result = Sum(b, c); 
    } 

    public int Result { get; set; } 

    public static int Sum(int source1, int source2) 
    { 
     return source1 + source2; 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var range = Enumerable.Range(1, 1000000).ToList(); 

     BenchmarkIt.Benchmark.This("reiterate",() => 
      { 
       var tst = range 
        .Select(x => new { b = x, c = x }) 
        .AsEnumerable() 
        .Select(x => new A 
        { 
         Result = A.Sum(x.b, x.c) 
        }) 
        .ToList(); 
      }) 
      .Against.This("constructor",() => 
      { 
       var tst = range 
        .Select(x => new A(x, x)) 
        .ToList(); 
      }) 
      .For(60) 
      .Seconds() 
      .PrintComparison(); 

     Console.ReadKey(); 
    } 
} 
Cuestiones relacionadas