Dot-Net
simple linq to sql 不支持對 SQL 的轉換
我的 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>並沒有使它特別。這樣想:你正在傳遞
postId給GetCategoriesByPostId. 在您擁有 之前,您無法呼叫該方法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聲明了範圍變數,它們在每一行的範圍內。它們必須在伺服器上計算。然而,投影允許您將任意程式碼放入分配中,然後在客戶端上建構結果時執行。這意味著將呼叫這兩個方法,每個方法都會發出自己的查詢。