2008-12-02 5 views
19

ich habe dies in meinem BlogRepositoryeinfache LINQ to SQL hat keine unterstützte Übersetzung

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

und

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

und wenn ich aplly dieser Filter

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

}

to SQL

all dies ist in den gleichen Namen Tempo, wenn diese Hilfe Namespace Subnus.MVC.Data

wenn ich versuche, dieses

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

, die im Namensraum Subnus.MVC.Service zu tun es den Fehler wirft

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

Antwort

22

Sie rufen GetCommentsByPostId innerhalb, was schließlich ein Ausdrucksbaum ist. Dieser Baum wird, wenn er in BlogService.GetPublicPosts verfasst ist, in SQL konvertiert.

Während dieser Konvertierung ist es nur ein Methodenaufruf, nichts mehr. Linq to Sql versteht bestimmte Methodenaufrufe, und deins gehört nicht dazu. Daher der Fehler.

Auf der Oberfläche scheint dies wie es funktionieren sollte. Sie schreiben wiederverwendbare Abfragen und erstellen sie aus anderen Abfragen. Was Sie jedoch tatsächlich sagen: "Rufen Sie diese Methode während der Verarbeitung jeder Zeile auf dem Datenbankserver auf", was sie offensichtlich nicht kann. Die Tatsache, dass es eine IQueryable<T> nimmt und eine IQueryable<T> zurückgibt, macht es nicht besonders.

Denken Sie darüber nach: Sie übergeben postId zu GetCategoriesByPostId. Sie können diese Methode erst aufrufen, wenn Sie eine postId haben, und Sie haben keine davon, bis Sie sich auf dem Server in der Abfrage befinden.

Sie müssten wahrscheinlich gemeinsame Expression<> Instanzen für die Unterabfragen definieren und diese in der Zusammensetzung verwenden. Ich habe nicht darüber nachgedacht, wie das aussehen würde, aber es ist sicherlich machbar.

Edit:

Wenn Sie

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

mit

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

ersetzen die Abfrage nicht mehr eine Ausnahme werfen.

Dies liegt daran, let deklariert Bereichsvariablen, die für jede Zeile im Bereich sind. Sie müssen auf dem Server berechnet werden.

Mit Projektionen können Sie jedoch beliebigen Code in Zuordnungen einfügen, der dann beim Erstellen von Ergebnissen auf dem Client ausgeführt wird. Dies bedeutet, dass beide Methoden aufgerufen werden, von denen jede eine eigene Abfrage ausgibt.

+0

, wenn ich den Filter der Fehler immer noch nach der Änderung – Nesizer

+0

kommt anwenden Versuchen Sie, die WherePublicIsTrue Anruf in GetPublicPosts entfernen (nur sehen). –

+0

Versuchen Sie, .Where (post => post.Public) –

2

Upadate 2: das funktioniert

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

wenn ich diese erstellen

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

im BlogRepository es aber das funktioniert, ist nur die mich zu wiederholen ich es denke, weil ich schaffen ich meine auf Klasse und nicht die Linq zu SQL erstellt Klasse

UPDATE: denn dann wird es Linq zum Objekt und Linq nicht
auf SQL, wenn ich tun:

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