2008-12-02 16 views
19

tengo esto en mi BlogRepositorysencilla LINQ to SQL no tiene traducción apoyado a SQL

public IQueryable<Subnus.MVC.Data.Model.Post> GetPosts() 
    { 
     var query = from p in db.Posts 
        let categories = GetCategoriesByPostId(p.PostId) 
        let comments = GetCommentsByPostId(p.PostId) 
        select new Subnus.MVC.Data.Model.Post 
        { 
         Categories = new LazyList<Category>(categories), 
         Comments = new LazyList<Comment>(comments), 
         PostId = p.PostId, 
         Slug = p.Slug, 
         Title = p.Title, 
         CreatedBy = p.CreatedBy, 
         CreatedOn = p.CreatedOn, 
         Body = p.Body 
        }; 
     return query; 
    } 

y

public IQueryable<Subnus.MVC.Data.Model.Comment> GetCommentsByPostId(int postId) 
    { 
     var query = from c in db.Comments 
        where c.PostId == postId 
        select new Subnus.MVC.Data.Model.Comment 
        { 
         Body = c.Body, 
         EMail = c.EMail, 
         Date = c.CreatedOn, 
         WebSite = c.Website, 
         Name = c.Name 
        }; 

     return query; 
    } 

private IQueryable<Subnus.MVC.Data.Model.Category> GetCategoriesByPostId(int postId) 
    { 
     var query = from c in db.Categories 
        join pcm in db.Post_Category_Maps on c.CategoryId equals pcm.CategoryId 
        where pcm.PostId == postId 
        select new Subnus.MVC.Data.Model.Category 
        { 
         CategoryId = c.CategoryId, 
         Name = c.Name 
        }; 
     return query; 
    } 

y cuando aplly este filtro

namespace Subnus.MVC.Data 
{ 
public static class BlogFilters 
{ 
    public static IQueryable<Post> WherePublicIs(this IQueryable<Post> qry,bool state) 
    { 

     return from p in qry 
       where p.IsPublic == state 
       select p; 
    } 
} 

}

todo esto tiene los mismos nombres ritmo si eso ayuda espacio de nombres Subnus.MVC.Data

cuando intento hacer esto

public class BlogService : IBlogService 
{ 
... 
    public IList<Post> GetPublicPosts() 
    { 
     return repository.GetPosts().WherePublicIs(true).ToList(); 
    } 
... 
} 

que está en el espacio de nombres Subnus.MVC.Service que arroja el error

Method 'System.Linq.IQueryable`1[Subnus.MVC.Data.Model.Comment] GetCommentsByPostId(Int32)' has no supported translation to SQL. 

Respuesta

22

Usted están llamando al GetCommentsByPostId dentro de lo que finalmente es un árbol de expresiones. Ese árbol, cuando se compone en BlogService.GetPublicPosts, se convierte a SQL.

Durante esa conversión, es solo una llamada a un método, nada más. Linq to Sql entiende ciertas llamadas a métodos, y la tuya no es una de ellas. De ahí el error.

En apariencia, parece que debería funcionar. Escribe consultas reutilizables y las redacta a partir de otras consultas. Sin embargo, lo que en realidad está diciendo es: "durante el procesamiento de cada fila en el servidor de la base de datos, llame a este método", lo que obviamente no puede hacer. El hecho de que tome un IQueryable<T> y devuelva un IQueryable<T> no lo hace especial.

Piénsalo de esta manera: está pasando postId a GetCategoriesByPostId. No puede llamar a ese método hasta que tenga un postId, y no tiene uno de esos hasta que esté en el servidor de la consulta.

Probablemente necesite definir instancias Expression<> comunes para las subconsultas y usarlas en la composición. No he pensado en cómo se vería esto, pero es ciertamente factible.

Editar:

Si reemplaza

let categories = GetCategoriesByPostId(p.PostId) 
let comments = GetCommentsByPostId(p.PostId) 
... 
Categories = new LazyList<Category>(categories), 
Comments = new LazyList<Comment>(comments), 

con

Categories = new LazyList<Category>(GetCategoriesByPostId(p.PostId)), 
Comments = new LazyList<Comment>(GetCommentsByPostId(p.PostId)), 

la consulta ya no lanzar una excepción.

Esto se debe a que let declara las variables de rango, que están en el alcance de cada fila. Ellos deben calcularse en el servidor.

Las proyecciones, sin embargo, le permiten poner código arbitrario en las asignaciones, que luego se ejecuta al generar resultados en el cliente. Esto significa que se llamarán ambos métodos, cada uno de los cuales emitirá su propia consulta.

+0

cuando aplico el filtro el error aún se produce después de que el cambio – Nesizer

+0

Prueba a eliminar la llamada WherePublicIsTrue en GetPublicPosts (justo para ver). –

+0

Intenta hacer .Where (post => post.Public) –

2

upadate 2: esto funciona

var query = from p in repository.GetPosts() 
      where p.Slug == slug 
     select p; 
return query.SingleOrDefault(); 

Si creo este

public IQueryable<Post> GetPublicPosts() 
    { 
     var query = from p in db.Posts 
        where p.IsPublic==true 
        select new Subnus.MVC.Data.Model.Post 
        { 
         Categories = new LazyList<Category>(GetCategoriesByPostId(p.PostId)), 
         Comments = new LazyList<Comment>(GetCommentsByPostId(p.PostId)), 

         PostId = p.PostId, 
         Slug = p.Slug, 
         Title = p.Title, 
         CreatedBy = p.CreatedBy, 
         CreatedOn = p.CreatedOn, 
         Body = p.Body 
        }; 
     return query; 
    } 

en el BlogRepository funciona pero eso es sólo el mismo repitiendo creo que ya puedo crear Yo mi clase y no el linq a sql creado clase

ACTUALIZACIÓN: porque entonces se convierte en LINQ a objetar y no LINQ to SQL
si lo hago:

public IQueryable<Post> GetPublicPosts() 
    { 
     var query = from p in GetPosts() 
        where p.IsPublic==true 
        select p; 
     return query; 
    }