我在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.
答案 0 :(得分:25)
您在最终的表达式树中调用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
声明了范围变量,这些变量在每行的范围内。他们必须在服务器上计算。
然而,预测允许您在任务中放置任意代码,然后在客户端上构建结果时执行。这意味着将调用这两种方法,每种方法都会发出自己的查询。