Dot-Net

simple linq to sql 不支持對 SQL 的轉換

  • December 2, 2008

我的 BlogRepository 中有這個

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

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

當我應用這個過濾器時

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

}

如果幫助命名空間 Subnus.MVC.Data,所有這些都在同一個命名空間中

當我嘗試這樣做時

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

即在命名空間 Subnus.MVC.Service 中它會引發錯誤

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

GetCommentsByPostId你在最終是一個表達式樹中呼叫。該樹在 中組成時BlogService.GetPublicPosts,將轉換為 SQL。

在該轉換期間,它只是一個方法呼叫,僅此而已。Linq to Sql 了解某些方法呼叫,而您的方法呼叫不是其中之一。因此錯誤。

從表面上看,這似乎應該奏效。您編寫可重用的查詢並從其他查詢中組合它們。但是,您實際上是在說:“在數據庫伺服器上處理每一行的過程中,呼叫此方法”,這顯然是做不到的。它接受一個IQueryable<T>並返回一個的事實IQueryable<T>並沒有使它特別。

這樣想:你正在傳遞postIdGetCategoriesByPostId. 在您擁有 之前,您無法呼叫該方法postId,並且在您位於查詢中的伺服器上之前,您沒有其中之一。

您可能需要Expression<>為子查詢定義公共實例並在組合中使用這些實例。我沒有想過這會是什麼樣子,但它肯定是可行的。

編輯:

如果你更換

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

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

查詢將不再拋出異常。

這是因為let聲明了範圍變數,它們在每一行的範圍內。它們必須在伺服器上計算。

然而,投影允許您將任意程式碼放入分配中,然後在客戶端上建構結果時執行。這意味著將呼叫這兩個方法,每個方法都會發出自己的查詢。

引用自:https://stackoverflow.com/questions/332670