2009-04-23 25 views
9

He estado usando Saltee() y .Tomar() los métodos de extensión con LINQ a SQL desde hace un tiempo, sin problemas, pero en todos los casos los he usado siempre lo ha sido durante una sola tabla - tales como:LINQ To SQL Paging

database.Users.Select(c => c).Skip(10).Take(10); 

Mi problema es que ahora estoy proyectando un conjunto de resultados de varias tablas y quiero página en el conjunto global (y aún así obtener el beneficio de paginación en el DB) .

Mi modelo de entidad es el siguiente:

Una campaña [tiene muchos] grupos, un grupo [tiene muchos] contactos

esto se modela a través de una relación en la base de datos como

Campaña -> CampaignToGroupMapping -> Grupo -> GroupToContactMapping -> Contacto

Necesito generar una estructura de datos ho lding los detalles de una campaña y también una lista de cada contacto asociado a la campaña a través de la CampaignToGroupMapping, es decir,

Campaign 
    CampaignName 
    CampaignFrom 
    CampaignDate 
    Recipients 
     Recipient 1 
     Recipient 2 
     Recipient n... 

que había tratado de escribir una consulta LINQ utilizando .SelectMany para proyectar el conjunto de contactos de cada grupo en un conjunto de datos lineales, con la esperanza de que pueda .Skip() .Take() de eso.

Mi intento fue:

var schedule = (from c in database.Campaigns 
       where c.ID == highestPriority.CampaignID 
       select new PieceOfCampaignSchedule 
       { 
        ID = c.ID, 
        UserID = c.UserID, 
        Name = c.Name, 
        Recipients = c.CampaignGroupsMappings.SelectMany(d => d.ContactGroup.ContactGroupMappings.Select(e => new ContactData() { /*Contact Data*/ }).Skip(c.TotalSent).Take(totalRequired)).ToList() 

       }).SingleOrDefault(); 

El problema es que la paginación (en lo que respecta a Skip() y Take()) está sucediendo para cada grupo, no a todo el conjunto de datos.

Esto significa que si utilizo el valor 200 para el parámetro totalRequired (pasado a .Tomar()) y tengo 3 grupos asociados con esta campaña, se tardará 200 de cada grupo - no 200 del total de datos de cada grupo asociado con la campaña.

En SQL, que podría lograr esto con una consulta como:

select * from 
(
    select [t1].EmailAddress, ROW_NUMBER() over(order by CampaignID desc) as [RowNumber] from contacts as [t1] 
    inner join contactgroupmapping as [t2] on [t1].ID = [t2].ContactID 
    inner join campaigngroupsmapping as [t3] on [t3].ContactGroupID = [t2].GroupID 
    where [t3].CampaignID = @HighestPriorityCampaignID 

) as [Results] where [Results].[RowNumber] between 500 and 3000 

Con esta consulta, estoy de paginación sobre el conjunto combinado de contactos de cada grupo asociado con la campaña en particular. Entonces mi pregunta es, ¿cómo puedo lograr esto usando la sintaxis de LINQ To SQL?

Respuesta

0

utilizar una vista para agregar los resultados de las varias tablas y luego utilizar LINQ sobre la vista

+0

Idealmente, estaba buscando una solución que solo utilizara LINQ To SQL. Como mencioné en mi respuesta, podría ejecutar la consulta SQL directamente desde ADO.NET también, pero quería usar LINQ To SQL para coherencia con otro código. Gracias por la sugerencia. – Martin

+1

LINQ to SQL admite vistas. Simplemente arrástralas y sujétalas al diseñador. Entendí que querrías una solución LINQ to SQL. Te sugerí que crees una vista para usar. por el marco de LINQ to SQL. – rguerreiro

4

Para imitar la consulta SQL que ya ha proporcionado usted podría hacer esto:

var schedule = (from t1 in contacts 
       join t2 in contactgroupmapping on t1.ID equals t2.GroupID 
       join t3 in campaigngroupsmapping on t3.ContactGroupID = t2.GroupID 
       where t3.CampaignID = highestPriority.CampaignID 
       select new PieceOfCampaignSchedule 
       { 
        Email = t1.EmailAddress 
       }).Skip(500).Take(2500).ToList() 

¿Estás tratando de página sobre campañas, destinatarios o ambos?

+0

Creo que necesita hacer un pedido antes de usar Omitir y Tomar. Funcionó así para mí. –

0

Creo que su intento es muy estrecha; Tal vez me falta algo, pero creo que sólo tiene que cerrar su SelectMany() antes de que el Salto/Tomar:

Recipients = c.CampaignGroupsMappings.SelectMany(d => d.ContactGroup.ContactGroupMappings.Select(e => new ContactData() { /*Contact Data*/ })).Skip(c.TotalSent).Take(totalRequired).ToList() 

Nota: añadido ")" después de "/ * Datos de Contacto * /})" y eliminado ")" de después ".Take (totalRequired) "