2008-12-02 8 views
19

i ceci dans ma BlogRepositoryLINQ simple à SQL n'a pas de traduction pris en charge pour 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; 
    } 

et

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; 
    } 

et quand je aplly ce filtre

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; 
    } 
} 

}

tout cela est au même nom rythme si cet espace de noms d'aide Subnus.MVC.Data

lorsque je tente de faire

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

qui se trouve dans l'espace de noms Subnus.MVC.Service il jette l'erreur

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

Répondre

22

Vous appelez GetCommentsByPostId dans ce qui est finalement un arbre d'expression. Cet arbre, lorsqu'il est composé en BlogService.GetPublicPosts, est converti en SQL.

Lors de cette conversion, ce n'est qu'un appel de méthode, rien de plus. Linq to Sql comprend certains appels de méthodes, et le vôtre n'en fait pas partie. D'où l'erreur.

Sur la surface, cela semble fonctionner. Vous écrivez des requêtes réutilisables et les composez à partir d'autres requêtes. Cependant, ce que vous dites en réalité est: "pendant le traitement de chaque ligne sur le serveur de base de données, appelez cette méthode", ce qui ne peut évidemment pas être fait. Le fait qu'il prend un IQueryable<T> et renvoie un IQueryable<T> ne le rend pas spécial. Pensez-y de cette façon: vous passez postId à GetCategoriesByPostId. Vous ne pouvez pas appeler cette méthode tant que vous n'avez pas postId et que vous n'en possédez pas tant que vous n'êtes pas sur le serveur dans la requête.

Vous devrez probablement définir des instances communes Expression<> pour les sous-requêtes et utiliser celles de la composition. Je n'ai pas pensé à quoi cela ressemblerait, mais c'est certainement faisable.

Edit:

Si vous remplacez

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

avec

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

la requête ne jetteront plus une exception. Cela s'explique par le fait que let déclare des variables de plage, qui sont incluses dans la portée de chaque ligne. Ils doit être être calculé sur le serveur. Cependant, les projections permettent de mettre du code arbitraire dans des affectations, qui sont ensuite exécutées lors de la création de résultats sur le client. Cela signifie que les deux méthodes seront appelées, chacune produisant sa propre requête.

+0

quand j'appliquer le filtre l'erreur est toujours après le changement – Nesizer

+0

Essayez de retirer l'appel WherePublicIsTrue à GetPublicPosts (juste à voir). –

+0

Essayez de faire .Where (post => post.Public) –

2

Upadate 2: cela fonctionne

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

si je crée cette

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; 
    } 

dans le BlogRepository il fonctionne, mais qui est juste que je pense que le me répéter parce que je crée i mon sur la classe et pas le linq à sql créé classe

MISE À JOUR: parce qu'alors il devient LINQ à l'objet et non LINQ to SQL
si je fais:

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