linq to sql - for - ¿Cómo cargar muchas consultas LINQ?
select linq to sql c# (6)
¡Hurra! Funcionó.
Si alguien tiene el mismo problema, esto es lo que hice:
public IList<Post> GetPosts(int page, int record)
{
var options = new DataLoadOptions();
options.LoadWith<Post>(p => p.PostTags);
options.LoadWith<PostTag>(pt => pt.Tag);
using (var db = new DatabaseDataContext(m_connectionString))
{
var publishDateGmt = (from p in db.Posts
where p.Status != PostStatus.Hidden
orderby p.PublishDateGmt descending
select p.PublishDateGmt)
.Skip(page * record)
.Take(record)
.ToList()
.Last();
db.LoadOptions = options;
return (from p in db.Posts
where p.Status != PostStatus.Closed
&& p.PublishDateGmt >= publishDateGmt
orderby p.PublishDateGmt descending
select p)
.Skip(page * record)
.ToList();
}
}
Esto ejecuta solo dos consultas y carga todas las etiquetas para cada publicación.
La idea es obtener algún valor para limitar la consulta en la última publicación que necesitamos (en este caso, la columna PublishDateGmt será suficiente) y luego limitar la segunda consulta con ese valor en lugar de Take ().
Gracias por su ayuda sirrocco.
Tengo la siguiente estructura de tabla (bastante estándar):
Post <-> PostTag <-> Tag
Supongamos que tengo los siguientes registros:
PostID Title
1, ''Foo''
2, ''Bar''
3, ''Baz''
TagID Name
1, ''Foo''
2, ''Bar''
PostID TagID
1 1
1 2
2 2
En otras palabras, la primera publicación tiene dos etiquetas, la segunda tiene una y la tercera no tiene ninguna.
Me gustaría cargar todas las publicaciones y sus etiquetas en una consulta, pero no he podido encontrar la combinación correcta de operadores. He podido cargar publicaciones solo con etiquetas o publicaciones repetidas cuando hay más de una etiqueta .
Dada la base de datos anterior, me gustaría recibir tres publicaciones y sus etiquetas (si corresponde) en una propiedad de colección de los objetos de publicación . ¿Es posible?
Gracias
Es un poco extraño porque
DataLoadOptions o = new DataLoadOptions ( );
o.LoadWith<Listing> ( l => l.ListingStaffs );
o.LoadWith<ListingStaff> ( ls => ls.MerchantStaff );
ctx.LoadOptions = o;
IQueryable<Listing> listings = (from a in ctx.Listings
where a.IsActive == false
select a);
List<Listing> list = listings.ToList ( );
resultados en una consulta como:
SELECT [t0].*, [t1].*, [t2].*, (
SELECT COUNT(*)
FROM [dbo].[LStaff] AS [t3]
INNER JOIN [dbo].[MStaff] AS [t4] ON [t4].[MStaffId] = [t3].[MStaffId]
WHERE [t3].[ListingId] = [t0].[ListingId]
) AS [value]
FROM [dbo].[Listing] AS [t0]
LEFT OUTER JOIN ([dbo].[LStaff] AS [t1]
INNER JOIN [dbo].[MStaff] AS [t2] ON [t2].[MStaffId] = [t1].[MStaffId]) ON
[t1].[LId] = [t0].[LId] WHERE NOT ([t0].[IsActive] = 1)
ORDER BY [t0].[LId], [t1].[LStaffId], [t2].[MStaffId]
(He acortado los nombres y he añadido * en la selección).
Entonces parece hacer el seleccionar ok.
Lo siento, Eager Loading ejecutará una consulta adicional por etiqueta por publicación.
Probado con este código:
var options = new DataLoadOptions();
options.LoadWith<Post>(p => p.PostTags);
options.LoadWith<PostTag>(pt => pt.Tag);
using (var db = new BlogDataContext())
{
db.LoadOptions = options;
return (from p in db.Posts
where p.Status != PostStatus.Closed
orderby p.PublishDateGmt descending
select p);
}
En la base de datos de ejemplo, ejecutará 4 consultas que no son aceptables en producción. ¿Alguien puede sugerir otra solución?
Gracias
Lo siento. La solución que das funciona, pero descubrí que se rompe al paginar con Take (N). El método completo que estoy usando es el siguiente:
public IList<Post> GetPosts(int page, int records)
{
var options = new DataLoadOptions();
options.LoadWith<Post>(p => p.PostTags);
options.LoadWith<PostTag>(pt => pt.Tag);
using (var db = new BlogDataContext())
{
db.LoadOptions = options;
return (from p in db.Posts
where p.Status != PostStatus.Closed
orderby p.PublishDateGmt descending
select p)
.Skip(page * records)
//.Take(records)
.ToList();
}
}
Con el método Take () comentó que genera una consulta similar a la que publicaste, pero si vuelvo a agregar el Take (), genera 1 + N x M consultas.
Entonces, supongo que mi pregunta ahora es: ¿hay un reemplazo del método Take () para paginar registros?
Gracias
Sé que esta es una publicación anterior, pero he descubierto una forma de utilizar Take () mientras solo realizo una consulta. El truco es realizar el Take () dentro de una consulta anidada.
var q = from p in db.Posts
where db.Posts.Take(10).Contains(p)
select p;
Usar DataLoadOptions con la consulta anterior le dará las primeras diez publicaciones, incluidas sus etiquetas asociadas, todo en una consulta. El SQL resultante será una versión mucho menos concisa de lo siguiente:
SELECT p.PostID, p.Title, pt.PostID, pt.TagID, t.TagID, t.Name FROM Posts p
JOIN PostsTags pt ON p.PostID = pt.PostID
JOIN Tags t ON pt.TagID = t.TagID
WHERE p.PostID IN (SELECT TOP 10 PostID FROM Posts)
He respondido esto en otra publicación: Acerca de la carga ansiosa . En tu caso, probablemente sería algo así como:
DataLoadOptions options = new DataLoadOptions();
options.LoadWith<Post>(p => p.PostTag);
options.LoadWith<PostTag>(pt => pt.Tag);
Aunque tenga cuidado: las DataLoadOptions deben configurarse ANTES DE QUE se envíe cualquier consulta a la base de datos; de lo contrario, se lanza una excepción (no hay idea de por qué es así en Linq2Sql), probablemente se solucione en una versión posterior.