Usando el ejemplo simple a continuación, ¿cuál es la mejor manera de devolver resultados de múltiples tablas usando Linq a SQL?
Digamos que tengo dos tablas:
Dogs: Name, Age, BreedId
Breeds: BreedId, BreedName
Quiero devolver todos los perros con sus BreedName
. Debo hacer que todos los perros usen algo como esto sin problemas:
public IQueryable<Dog> GetDogs()
{
var db = new DogDataContext(ConnectString);
var result = from d in db.Dogs
join b in db.Breeds on d.BreedId equals b.BreedId
select d;
return result;
}
Pero si quiero perros con razas y pruebo esto, tengo problemas:
public IQueryable<Dog> GetDogsWithBreedNames()
{
var db = new DogDataContext(ConnectString);
var result = from d in db.Dogs
join b in db.Breeds on d.BreedId equals b.BreedId
select new
{
Name = d.Name,
BreedName = b.BreedName
};
return result;
}
Ahora me doy cuenta de que el compilador no me permite devolver un conjunto de tipos anónimos, ya que espera perros, pero ¿hay alguna manera de devolver esto sin tener que crear un tipo personalizado? ¿O tengo que crear mi propia clase DogsWithBreedNames
y especificar ese tipo en la selección? ¿O hay otra manera más fácil?
c#
linq
linq-to-sql
Jonathan S.
fuente
fuente
foreach (var cust in query) Console.WriteLine("id = {0}, City = {1}", cust.CustomerID, cust.City);
Respuestas:
Tiendo a ir por este patrón:
Significa que tiene una clase adicional, pero es rápida y fácil de codificar, fácilmente extensible, reutilizable y segura.
fuente
Usted puede regresar tipos anónimos, pero en realidad no es bastante .
En este caso, creo que sería mucho mejor crear el tipo apropiado. Si solo se va a usar desde el tipo que contiene el método, conviértalo en un tipo anidado.
Personalmente, me gustaría que C # obtenga "tipos anónimos con nombre", es decir, el mismo comportamiento que los tipos anónimos, pero con nombres y declaraciones de propiedades, pero eso es todo.
EDITAR: otros sugieren perros que regresan, y luego acceder al nombre de la raza a través de una ruta de propiedad, etc. Ese es un enfoque perfectamente razonable, pero IME conduce a situaciones en las que ha realizado una consulta de una manera particular debido a los datos que desea use, y esa metainformación se pierde cuando regresa
IEnumerable<Dog>
, la consulta puede esperar que use (digamos) enBreed
lugar deOwner
debido a algunas opciones de carga, etc., pero si olvida eso y comienza a usar otras propiedades, su aplicación puede funcionar, pero no tan eficientemente como lo había previsto originalmente. Por supuesto, podría estar hablando basura, o sobre optimizando, etc.fuente
Solo para agregar el valor de mis dos centavos :-) Recientemente aprendí una forma de manejar objetos anónimos. Solo se puede usar cuando se dirige al marco .NET 4 y solo cuando se agrega una referencia a System.Web.dll, pero es bastante simple:
Para poder agregar una referencia a System.Web.dll, deberá seguir los consejos de rushonerok : Asegúrese de que el marco de destino [del proyecto] sea ".NET Framework 4" y no ".NET Framework 4 Client Profile".
fuente
No, no puede devolver tipos anónimos sin pasar por algunos trucos.
Si no estuviera usando C #, lo que estaría buscando (devolver datos múltiples sin un tipo concreto) se llama Tupla.
Hay muchas implementaciones de tuplas C #, usando la que se muestra aquí , su código funcionaría así.
Y en el sitio de llamadas:
fuente
... select Tuple.Create(d, b)
.Podrías hacer algo como esto:
fuente
ToList()
Primero debe usar el método para tomar filas de la base de datos y luego seleccionar elementos como una clase. Prueba esto:Entonces, el truco es primero
ToList()
. Inmediatamente realiza la consulta y obtiene los datos de la base de datos. El segundo truco consiste en seleccionar elementos y usar el inicializador de objetos para generar nuevos objetos con elementos cargados.Espero que esto ayude.
fuente
¡En C # 7 ahora puede usar tuplas! ... lo que elimina la necesidad de crear una clase solo para devolver el resultado.
Aquí hay un código de muestra:
Sin embargo, es posible que deba instalar el paquete Nuget System.ValueTuple.
fuente
Ahora me doy cuenta de que el compilador no me permite devolver un conjunto de tipos anónimos, ya que espera perros, pero ¿hay alguna manera de devolver esto sin tener que crear un tipo personalizado?
Use use object para devolver una lista de tipos anónimos sin crear un tipo personalizado. Esto funcionará sin el error del compilador (en .net 4.0). Devolví la lista al cliente y luego la analicé en JavaScript:
fuente
Simplemente seleccione perros, luego use
dog.Breed.BreedName
, esto debería funcionar bien.Si tiene muchos perros, use DataLoadOptions.LoadWith para reducir la cantidad de llamadas db.
fuente
No puede devolver tipos anónimos directamente, pero puede recorrerlos a través de su método genérico. Lo mismo ocurre con la mayoría de los métodos de extensión LINQ. No hay magia allí, aunque parece que devolverían tipos anónimos. Si el parámetro es anónimo, el resultado también puede ser anónimo.
Debajo de un ejemplo basado en el código de la pregunta original:
fuente
Bueno, si regresas a Dogs, harías:
Si desea la Raza cargada de entusiasmo y no de carga perezosa, simplemente use la construcción de DataLoadOptions adecuada .
fuente
BreedId
en laDog
tabla es obviamente una clave foránea para la fila correspondiente en laBreed
tabla. Si tiene su base de datos configurada correctamente, LINQ to SQL debería crear automáticamente una asociación entre las dos tablas. La clase de perro resultante tendrá una propiedad de raza, y la clase de raza debe tener una colección de perros. Al configurarlo de esta manera, aún puede regresarIEnumerable<Dog>
, que es un objeto que incluye la propiedad de raza. La única advertencia es que debe precargar el objeto de raza junto con los objetos de perro en la consulta para que se pueda acceder después de que se haya eliminado el contexto de datos y (como ha sugerido otro póster) ejecutar un método en la colección que causará el consulta que se realizará de inmediato (ToArray en este caso):Entonces es trivial acceder a la raza para cada perro:
fuente
Si la idea principal es hacer que la instrucción de selección SQL enviada al servidor de la base de datos tenga solo los campos requeridos, y no todos los campos de la entidad, entonces puede hacer esto:
fuente
Pruebe esto para obtener datos dinámicos. Puede convertir el código para la Lista <>
fuente
Si tiene una configuración de relación en su base de datos con una restricción de clave extranjera en BreedId, ¿no lo tiene ya?
Entonces ahora puedo llamar:
Y en el código que llama eso:
Entonces, en su caso, llamaría algo así como dog.Breed.BreedName, como dije, esto se basa en que su base de datos se configure con estas relaciones.
Como otros han mencionado, DataLoadOptions ayudará a reducir las llamadas a la base de datos si eso es un problema.
fuente
Esto no responde exactamente a su pregunta, pero Google me llevó aquí en función de las palabras clave. Así es como puede consultar un tipo anónimo de una lista:
fuente