我在BlogRepository中有这个
public IQueryableGetPosts() { 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 (categories), Comments = new LazyList (comments), PostId = p.PostId, Slug = p.Slug, Title = p.Title, CreatedBy = p.CreatedBy, CreatedOn = p.CreatedOn, Body = p.Body }; return query; }
和
public IQueryableGetCommentsByPostId(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 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 IQueryableWherePublicIs(this IQueryable qry,bool state) { return from p in qry where p.IsPublic == state select p; } }
}
如果该帮助命名空间Subnus.MVC.Data,则所有这些都位于相同的命名空间中
当我尝试这样做
public class BlogService : IBlogService { ... public IListGetPublicPosts() { 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.
Bryan Watts.. 25
你GetCommentsByPostId
在最终的表达树中调用.组成时BlogService.GetPublicPosts
,该树将转换为SQL.
在转换期间,它只是一个方法调用,仅此而已.Linq to Sql理解某些方法调用,而你的不是其中之一.因此错误.
从表面上看,这似乎应该有效.您编写可重用查询并从其他查询中编写它们.但是,你实际上说的是:"在处理数据库服务器上的每一行时,调用这个方法",这显然是做不到的.它需要一个IQueryable
并返回一个这一事实IQueryable
并不会使它变得特别.
想想这样说:您传递postId
给GetCategoriesByPostId
.在拥有a之前postId
,不能调用该方法,并且在查询服务器上之前没有其中之一.
您可能需要Expression<>
为子查询定义公共实例并使用组合中的实例.我没有想过这会是什么样子,但它肯定是可行的.
编辑:
如果你更换
let categories = GetCategoriesByPostId(p.PostId) let comments = GetCommentsByPostId(p.PostId) ... Categories = new LazyList(categories), Comments = new LazyList (comments),
同
Categories = new LazyList(GetCategoriesByPostId(p.PostId)), Comments = new LazyList (GetCommentsByPostId(p.PostId)),
查询将不再抛出异常.
这是因为let
声明范围变量,它们在每行的范围内.必须在服务器上计算它们.
但是,预测允许您在任务中放置任意代码,然后在客户端上构建结果时执行.这意味着将调用这两种方法,每种方法都会发出自己的查询.
你GetCommentsByPostId
在最终的表达树中调用.组成时BlogService.GetPublicPosts
,该树将转换为SQL.
在转换期间,它只是一个方法调用,仅此而已.Linq to Sql理解某些方法调用,而你的不是其中之一.因此错误.
从表面上看,这似乎应该有效.您编写可重用查询并从其他查询中编写它们.但是,你实际上说的是:"在处理数据库服务器上的每一行时,调用这个方法",这显然是做不到的.它需要一个IQueryable
并返回一个这一事实IQueryable
并不会使它变得特别.
想想这样说:您传递postId
给GetCategoriesByPostId
.在拥有a之前postId
,不能调用该方法,并且在查询服务器上之前没有其中之一.
您可能需要Expression<>
为子查询定义公共实例并使用组合中的实例.我没有想过这会是什么样子,但它肯定是可行的.
编辑:
如果你更换
let categories = GetCategoriesByPostId(p.PostId) let comments = GetCommentsByPostId(p.PostId) ... Categories = new LazyList(categories), Comments = new LazyList (comments),
同
Categories = new LazyList(GetCategoriesByPostId(p.PostId)), Comments = new LazyList (GetCommentsByPostId(p.PostId)),
查询将不再抛出异常.
这是因为let
声明范围变量,它们在每行的范围内.必须在服务器上计算它们.
但是,预测允许您在任务中放置任意代码,然后在客户端上构建结果时执行.这意味着将调用这两种方法,每种方法都会发出自己的查询.