linq to sql - sets - Procedimientos almacenados de Linq a SQL con resultados mĂșltiples
entity framework execute stored procedure return datatable (3)
Scott Guthrie (el chico que dirige los equipos de desarrollo de .Net en MS) explicó cómo hacer esto en su blog hace unos meses mucho mejor de lo que podría hacerlo, enlace aquí . En esa página hay una sección titulada "Manejo de formas de resultados múltiples desde los SPROC". Eso explica cómo manejar resultados múltiples de procs almacenados de diferentes formas (o la misma forma).
Recomiendo suscribirse a su fuente RSS. Él es más o menos LA fuente autorizada en todas las cosas .Net.
Hemos seguido el siguiente enfoque para obtener los datos de resultados múltiples utilizando LINQ to SQL
CREATE PROCEDURE dbo.GetPostByID
(
@PostID int
)
AS
SELECT *
FROM Posts AS p
WHERE p.PostID = @PostID
SELECT c.*
FROM Categories AS c
JOIN PostCategories AS pc
ON (pc.CategoryID = c.CategoryID)
WHERE pc.PostID = @PostID
El método de llamada en la clase heredada de DataContext debería verse así:
[Database(Name = "Blog")]
public class BlogContext : DataContext
{
...
[Function(Name = "dbo.GetPostByID")]
[ResultType(typeof(Post))]
[ResultType(typeof(Category))]
public IMultipleResults GetPostByID(int postID)
{
IExecuteResult result =
this.ExecuteMethodCall(this,
((MethodInfo)(MethodInfo.GetCurrentMethod())),
postID);
return (IMultipleResults)(result.ReturnValue);
}
}
Observe que el método está decorado no solo con el atributo Function que se correlaciona con el nombre del procedimiento almacenado, sino también con los atributos ReturnType con los tipos de los conjuntos de resultados que devuelve el procedimiento almacenado. Además, el método devuelve una interfaz sin tipo de IMultipleResults:
public interface IMultipleResults : IFunctionResult, IDisposable
{
IEnumerable<TElement> GetResult<TElement>();
}
para que el programa pueda usar esta interfaz para recuperar los resultados:
BlogContext ctx = new BlogContext(...);
IMultipleResults results = ctx.GetPostByID(...);
IEnumerable<Post> posts = results.GetResult<Post>();
IEnumerable<Category> categories = results.GetResult<Category>();
En los procedimientos almacenados anteriormente, tuvimos dos consultas de selección 1. Seleccionar consulta sin unirse 2. Seleccionar consulta con Unirse
Pero en la segunda consulta de selección, los datos que se muestran provienen de una de las tablas, es decir, de la tabla Categorías. Pero hemos usado join y queremos mostrar la tabla de datos con los resultados de ambas tablas, es decir, de categorías y postCategorías.
- Por favor, si alguien me puede decir cómo lograr esto usando LINQ to SQL
- ¿Cuál es la compensación de rendimiento si utilizamos el enfoque anterior vis-à-vis para implementar el enfoque anterior con SQL simple?
Heya amigo - ¿esto funciona?
IEnumerable<Post> posts;
IEnumerable<Category> categories;
using (BlogContext ctx = new BlogContext(...))
{
ctx.DeferredLoadingEnabled = false; // THIS IS IMPORTANT.
IMultipleResults results = ctx.GetPostByID(...);
posts = results.GetResult<Post>().ToList();
categories = results.GetResult<Category>().ToList();
}
// Now we need to associate each category to the post.
// ASSUMPTION: Each post has only one category (1-1 mapping).
if (posts != null)
{
foreach(var post in posts)
{
int postId = post.PostId;
post.Category = categories
.Where(p => p.PostId == postId)
.SingleOrDefault();
}
}
De acuerdo. vamos a romper esto.
Primero, una buena conexión dentro de un bloque de uso (por lo que se desecha muy bien).
A continuación, nos aseguramos de que la CARGA DIFERIDA esté desactivada . De lo contrario, cuando intentes y hagas el set (por ejemplo, post.Category == blah
) verá que es nulo, carga los datos (por ejemplo, haz una rountrip en la base de datos) y establece los datos y luego anula lo que fue justo arrastrado hacia abajo desde el db, con el resultado del método Where(..)
. ¡Uf! Resumen: asegúrese de que la carga diferida esté desactivada para el alcance de la consulta.
Por último, para cada publicación, itere y configure la categoría de la segunda lista.
¿Eso ayuda?
EDITAR
Se corrigió para que no arrojara un error de enumeración llamando a los métodos ToList()
.
Solo curiosidad, si un mensaje tiene una o varias categorías, ¿es posible usar el bucle for para cargar Post.PostCategories con la lista de categorías (una para muchas), todo en una sola toma, usando JOIN?
var rslt = from p in results.GetResult<Post>()
join c in results.GetResult<Category>() on p.PostId = c.PostID
...
p.Categories.Add(c)