2011-03-14 9 views
6

Estoy usando EF. Esta es mi consulta LINQ¿Qué pasa con LINQ to EF?

public List<Tuple<int, string>> GetList() 
{ 
    return (from c in DALContext.MST 
      select new Tuple<int, string>(c.CD, c.NAME)).ToList(); 
} 

cuando llamo GetList() lanza una excepción: Solamente los constructores sin parámetros y inicializadores están soportados en LINQ a Entidades

En cambio, cuando vuelvo a escribir esta consulta:

List<Tuple<int, string>> lst = new List<Tuple<int, string>>(); 
var query= (from c in DALContext.MST 
      select new{c.CD, c.NAME}); 
foreach (var item in query) 
{ 
    lst.Add(new Tuple<int,string>(item.CD,item.NAME)); 
} 
return lst; 

Simplemente funciona bien. ¿Qué pasa con mi primera consulta?

Respuesta

11

Las otras respuestas son correctas acerca de lo que está pasando, pero no vi a nadie mencionar la mejor manera de hacer su trabajo código: AsEnumerable()

public List<Tuple<int, string>> GetList() 
    { 
     return (from c in DALContext.MST.AsEnumerable() 
       select Tuple.Create(c.CD, c.NAME)).ToList(); 
    } 

El método AsEnumerable actúa como un límite entre el código que debe ser traducido a SQL y ejecutado en el servidor de la base de datos, y el código que debe ejecutarse en la memoria después de que hayamos recibido una respuesta de la base de datos. Poniéndolo justo después del nombre de la tabla le dice a EF que obtenga todos los registros de la tabla MST, y luego ejecute el siguiente código que crea tuplas a partir de los valores que se devuelven.

He cambiado su new Tuple<int, string> en Tuple.Create principalmente porque no me gusta escribir parámetros de tipo genérico más de lo necesario.

+1

¿Es 'AsEnumerable()' diferente de usar 'ToList()' o 'ToArray()'? – Despertar

+1

@Despertar - 'ToList()' y 'ToArray()' recorren necesariamente los resultados de la consulta para construir la lista o matriz. En el ejemplo de arriba, si reemplaza 'AsEnumerable()' con 'ToList()', está repitiendo los resultados dos veces. Con 'AsEnumerable()' solo estás recorriendo una vez, porque 'AsEnumerable()' no consume la secuencia. –

6

LINQ to EF se ocupa de las consultas de forma un poco diferente que LINQ to SQL. En LINQ a EF, no se puede poner un constructor con parámetros en una expresión LINQ, como lo hizo aquí en el primer bit de código:

from c in DALContext.MST 
select new Tuple<int, string>(c.CD, c.NAME) 

El constructor de tupla se toma dos parámetros, y que no está permitido en LINQ to EF.

La razón se explica here:

En parte, esto es una cuestión de querer LINQ a las entidades a ser más explícitos sobre el límite entre qué partes de la consulta ejecutar en el servidor y qué parte ejecutar en el cliente.

Con LINQ a SQL, por ejemplo, es posible escribir una consulta LINQ, que no sólo implica los datos desde el servidor y funciones en el servidor pero también funciones que sólo se pueden ejecutar en el cliente y mezclarlos en juntos. El proveedor LINQ to SQL hará todo lo posible para desenredar cosas y ejecutar las partes que puede en el servidor y otras partes en el cliente. Esto es bueno porque es es fácil simplemente escribir cualquier consulta que desee y si es posible funcionará. Por otro lado, es no tan bueno si accidentalmente escribe una consulta, donde la única parte que puede ejecutar en el servidor es la cosa más básica que devuelve todos los datos en una o más tablas y luego tener todo el filtrado ocurre en el cliente (con consecuencias de perforación muy desagradables).

Con LINQ to Entities, los límites son más explícitos. Cuando se escribe una consulta LINQ contra un LINQ a Entidades aplicación IQueryable, toda la consulta se ejecuta en el servidor, y si alguna parte de la consulta no se puede ejecuta en el servidor, a continuación, un límite explícito debe ser creado con algo así como ToQueryable() o ToList(). Una vez que se ejecuta esa consulta y los datos recuperados, puede usar LINQ to Objects para refinar aún más la consulta si así lo desea. De esta manera, usted sabe explícitamente dónde están sus límites , y es más fácil rastrear problemas de rendimiento y el como.Una de las limitaciones relacionadas es que la instrucción de selección en LINQ para Entidades puede crear tipos anónimos u otros tipos siempre que tengan un constructor predeterminado y parámetros configurables . Esto minimiza la posibilidad de que la instrucción select tenga los principales efectos secundarios .

1

Su clase debe tener un constructor sin parámetros para LINQ a EF y hay que crear una instancia de esta manera:

public List<Tuple<int, string>> GetList() 
{ 
    return (from c in DALContext.MST 
      select new Tuple<int, string>(){CD = c.CD, Name = c.NAME}).ToList(); 
} 

EDIT:

Si no está en condiciones de añadir una constructor sin parámetros a TUPLE (que es el caso aquí ya que Tuple no es una clase per se) entonces no tiene otra opción con Linq a EF pero para hacer esto como un proceso de dos pasos:

public List<Tuple<int, string>> GetList() 
{ 
    List<MST> mstList = (from c in DALContext.MST 
         select c).ToList(); 

    List<Tuple<int, string>> tupleList = new List<Tuple<int, string>>(); 

    mstList.foreach(c => tupleList.add(new Tuple(c.CD, c.Name))); 

    return tupleList; 
} 
+0

Desafortunadamente eso no funciona, ya que las llaves son simplemente azúcar sintáctico para establecer las propiedades, y las tuplas no tienen un CD asignable o propiedades de nombre (o cualquier propiedad asignable para el caso). –

2

O simplemente puede escribir

var query= (from c in DALContext.MST 
      select new{c.CD, c.NAME}).ToList().Select(x=>new Tuple(x.CD, x.NAME)); 

Esto tiene la ventaja de que sólo trae de la BD las dos columnas que necesita.

+0

Ese es un punto muy bueno acerca de solo seleccionar las dos columnas que necesita, pero aún elegiría 'AsEnumerable' y luego' ToList' sobre la llamada 'ToList' dos veces. –