none
Problemas al definir alias en LINQ To Entities RRS feed

  • Pregunta

  • Buenas, espero contar con su ayuda, ya que no puedo resolverlo desde ya hace muchos días.

    Utilizo LinQ para recuperar datos desde la base datos, el problema que surge es cuando en la consulta LinQ utilizo alias, para no mostrar los mismos campos de la tabla de la base de datos como encabezado del control DataGridView en una aplicación WinForm. A continuación les muestro una parte del código de mi aplicación.

    Clase POCO:

    public class User
    {
            public int UserId { get; set; }
            public string Nombre { get; set; }
            public string ApellidoPat { get; set; }
            public string ApellidoMat { get; set; }
            public DateTime FechaNac { get; set; }
            public char Sexo { get; set; }
    }

    Método List

    public List<User> List()
    {
                using (context = new CrisofdevContext())
                {
                    var q = from u in context.Users select new User{ UserId = u.UserId, Nombres = u.Nombre, Apellidos = u.ApellidoPat + " " + u.ApellidoMat, FechaNac = u.FechaNac };
                    return q.ToList();
                }
    }

    Errores:

    'Entities.User' does not contain a definition for Nombres

    'Entities.User' does not contain a definition for Apellidos

    jueves, 16 de enero de 2014 18:40

Todas las respuestas

  • Bueno, el mensaje de error tiene toda la razón: Estás pidiendo que te devuelva una instancia de la clase User. Y la clase User tiene los campos que tiene, no se los puedes cambiar en la sentencia Linq. Es decir, si User tiene un campo que se llama "Nombre" no puedes decir en Linq que te meta "Nombres" dentro de User.

    Te debes estar confundiendo con la opción de generar tipos anónimos desde LINQ. En este caso, en el Select se omite el nombre de la clase, y entonces lo que hace es generar una nueva clase (sin nombre, por eso se llama "tipo anónimo") y en esa clase sí que crea las propiedades que tú le hayas dicho con los nombres que quieras:

    var q = from u in context.Users select new { UserId = u.UserId, Nombres = u.Nombre, Apellidos = u.ApellidoPat + " " + u.ApellidoMat, FechaNac = u.FechaNac };

    Editado: Pero Ojo, en este caso no podrás hacer un "return q.ToList()". Tu función declara que devuelve un List<User>, por lo que no puede devolver otros objetos que no sean User. Y en los objetos User no puedes devolver campos que no sean los que se han definido en User, no puedes ponerles alias.

    viernes, 17 de enero de 2014 6:49
  • hola

    es logico que si tu clase define una propiedad no puedas asignar una que no existe, eso imagino esta claro

    public List<dynamic> List()
    {
    	using (context = new CrisofdevContext())
    	{
    		var q = from u in context.Users 
    				select new 
    				{ 
    					UserId = u.UserId, 
    					Nombres = u.Nombre, 
    					Apellidos = u.ApellidoPat + " " + u.ApellidoMat, 
    					FechaNac = u.FechaNac 
    				};
    				
    		return q.ToList();
    	}
    }

    es importante remarcar que necesitas .net 4 o superior para usar dynamic

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina

    viernes, 17 de enero de 2014 12:10
  • Hola Alberto gracias por tu respuesta que me aclaró muchas dudas, pero aun no tengo bien en claro lo siguiente:

    Si trabajo con tipos anónimos que tipo de dato tendría que devolver el método List() ?

    Cual es la forma correcta de trabajar con alias en Linq? Porque no seria correcto mostrar los mismos campos de la base de datos como encabezado de un control DataGridView.

    Gracias espero contar con su ayuda.......

    viernes, 17 de enero de 2014 13:13
  • Si trabajo con tipos anónimos que tipo de dato tendría que devolver el método List() ?

    Si trabajas con tipos anónimos, la única solución elegante consiste en usarlos dentro de la misma subrutina que los genera. Para devolver uno de esos tipos fuera de la subrutina, habría que usar tipos Object o dynamic, lo cual es bastante mala idea porque pierdes la robustez en cuanto a tipos del lenguaje C# (en otras palabras, el llamante de tu subrutina no conoce los tipos reales encapsulados dentro del object o el dynamic, y no los puede comprobar en tiempo de compilación).

    Cual es la forma correcta de trabajar con alias en Linq? Porque no seria correcto mostrar los mismos campos de la base de datos como encabezado de un control DataGridView.

    Para cambiar los encabezados del DataGridView es mejor definirlos dentro del propio DataGridView en lugar de dejar que los genere automáticamente a partir de su DataSource. En su defecto, si no tienes más remedio que inferirlos del DataSource, entonces genera los tipos anónimos en la misma subrutina que asigna el DataSource. Por ejemplo, deja que tu subrutina List devuelva un List<User>, sin poner alias en User, y luego al asignarlo al datasource haz algo parecido a esto:

    DataGridView1.DataSource = from u in List() select new { UserId = u.UserId, Nombres = u.Nombre, Apellidos = u.ApellidoPat + " " + u.ApellidoMat, FechaNac = u.FechaNac };

    O, alternativamente, declara el resultado de la función como Object, y asigna ese Object al DataSource. Aunque antes te he advertido que esto es en general mala idea porque se pierde la robustez de tipos, en este caso particular no tiene importancia porque de todas maneras el DataSource no es robusto en cuanto a tipos (toma un Object y por dentro aplica Reflection para sacar las propiedades).

    viernes, 17 de enero de 2014 14:57
  • Leandro gracias por la respuesta. 

    Estoy trabajando con VS 2013 y el .net framework es 4.5. Estoy utilizando dynamic como me recomendastes:

    public List<dynamic> List()
    {
    	using (context = new CrisofdevContext())
    	{
    		var q = from u in context.Users 
    				select new 
    				{ 
    					UserId = u.UserId, 
    					Nombres = u.Nombre, 
    					Apellidos = u.ApellidoPat + " " + u.ApellidoMat, 
    					FechaNac = u.FechaNac 
    				};
    				
    		return q.ToList();
    	}
    }

    Pero me sale el siguiente error:

    Error : Cannot implicitly convert type 'System.Collections.Generic.List<AnonymousType#1>' to 'System.Collections.Generic.List<dynamic>' D:\CristianQR\Practice\csharp\CodeFirst\Data\UserDAL.cs 20 24 Data
    viernes, 17 de enero de 2014 17:50
  • No, eso no cuela. Un List<A> no se puede convertir en List<B> aunque A se pueda convertir en B. Si quieres la explicación, busca en la red "covariance and contravariance c#". Se han vertido ríos de tinta sobre este asunto.

    Sugiero que declares como Object o dynamic el resultado de la función (pero NO List<object> o List<dynamic>).

    viernes, 17 de enero de 2014 19:05