简单的LINQ to SQL没有支持转换为SQL [英] simple linq to sql has no supported translation to SQL

查看:334
本文介绍了简单的LINQ to SQL没有支持转换为SQL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个在我BlogRepository

 公开的IQueryable< Subnus.MVC.Data.Model.Post> GetPosts()
    {
        VAR的查询=从p在db.Posts
                    让类别= GetCategoriesByPostId(p.PostId)
                    让评论= GetCommentsByPostId(p.PostId)
                    选择新Subnus.MVC.Data.Model.Post
                    {
                        分类=新LazyList<类别>(分类),
                        评论=新LazyList<注释>(评论),
                        PostId = p.PostId,
                        弹头= p.Slug,
                        标题= p.Title,
                        CreatedBy = p.CreatedBy,
                        CreatedOn = p.CreatedOn,
                        车身= p.Body
                    };
        返回查询;
    }
 

 公开的IQueryable< Subnus.MVC.Data.Model.Comment> GetCommentsByPostId(INT postId)
    {
        VAR的查询=从C在db.Comments
                    其中,c.PostId == postId
                    选择新Subnus.MVC.Data.Model.Comment
                    {
                        车身= c.Body,
                        的EMail = c.EMail,
                        日期= c.CreatedOn,
                        网页= c.Website,
                        名称= c.Name
                    };

        返回查询;
    }

私人的IQueryable< Subnus.MVC.Data.Model.Category> GetCategoriesByPostId(INT postId)
    {
        VAR的查询=从C在db.Categories
                    加入PCM在db.Post_Category_Maps上c.CategoryId等于pcm.CategoryId
                    其中,pcm.PostId == postId
                    选择新Subnus.MVC.Data.Model.Category
                    {
                        的CategoryId = c.CategoryId,
                        名称= c.Name
                    };
        返回查询;
    }
 

当我aplly此过滤器

 命名空间Subnus.MVC.Data
{
 公共静态类BlogFilters
 {
    公共静态的IQueryable<邮政> WherePublicIs(这IQueryable的<邮政和GT; QRY,布尔州)
    {

        从对在QRY返回
               其中,p.IsPublic ==状态
               选择磷;
    }
 }
 

}

这一切都是在同一个命名空间,如果这种帮助的命名空间Subnus.MVC.Data

当我试图做到这一点

 公共类BlogService:IBlogService
{
...
    公众的IList<邮政> GetPublicPosts()
    {
         返回repository.GetPosts()WherePublicIs(真).ToList()。
    }
 ...
 }
 

这是命名空间Subnus.MVC.Service 它抛出错误

 法System.Linq.IQueryable`1 [Subnus.MVC.Data.Model.Comment] GetCommentsByPostId(Int32)在没有支持转换为SQL。
 

解决方案

正在调用 GetCommentsByPostId 中的哪些是最终的前pression树。那棵树,当 BlogService.GetPublicPosts 组成,被转换成SQL。

在此转换,它仅仅是一个方法调用,仅此而已。 LINQ to SQL的了解一定的方法调用,而你是不是其中之一。因此,错误。

从表面上看,这似乎像它应该工作。你写的可重复使用的查询和其他查询撰写他们。然而,你实际上说的是:在数据库服务器上每一行的处理过程中,调用此方法,它显然无法做到。事实上,它需要一个的IQueryable&LT; T&GT; 并返回的IQueryable&LT; T&GT; 并不能使它特别<。 / P>

想想这样说:你逝去的 postId GetCategoriesByPostId 。直到你有你无法调用方法 postId ,而你没有其中的一个,直到你在查询服务器上。

您可能会需要定义共同防爆pression&LT;&GT; 的子查询实例,并使用这些组合物中。我没有想过这是什么会是什么样子,但它肯定是可行的。

编辑:

如果您更换

 让类别= GetCategoriesByPostId(p.PostId)
让评论= GetCommentsByPostId(p.PostId)
...
分类=新LazyList&LT;类别&GT;(分类),
评论=新LazyList&LT;注释&GT;(评论),
 

 分类=新LazyList&LT;类别&GT;(GetCategoriesByPostId(p.PostId)),
评论=新LazyList&LT;注释&GT;(GetCommentsByPostId(p.PostId)),
 

查询将不再抛出异常。

这是因为声明范围变量,在范围上的每一行。他们的必须来计算在服务器上。

预测,但是,让你把任意code的任务,然后同时建立在客户端上的执行结果。这意味着这两种方法将被调用,其每一个将发出其自己的查询。

i have this in my 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;
    }

and

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

and when i aplly this 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;
    }
 }

}

all this is in the same namespace if that help namespace Subnus.MVC.Data

when i try to do this

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

that is in the namespace Subnus.MVC.Service it throws the error

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

解决方案

You are calling GetCommentsByPostId within what is ultimately an expression tree. That tree, when composed in BlogService.GetPublicPosts, is converted to SQL.

During that conversion, it is just a method call, nothing more. Linq to Sql understands certain method calls, and yours is not one of them. Hence the error.

On the surface, this seems like it should work. You write reusable queries and compose them from other queries. However, what you are actually saying is: "during the processing of each row on the database server, call this method", which it obviously can't do. The fact that it takes an IQueryable<T> and returns an IQueryable<T> does not make it special.

Think about it this way: you are passing postId to GetCategoriesByPostId. You can't call that method until you have a postId, and you don't have one of those until you are on the server in the query.

You would probably need to define common Expression<> instances for the sub-queries and use those in the composition. I haven't thought about what this would look like but it's certainly doable.

Edit:

If you replace

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

with

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

the query will no longer throw an exception.

This is because let declares range variables, which are in scope for each row. They must be calculated on the server.

Projections, however, allow you to put arbitrary code in assignments, which is then executed while building results on the client. This means both methods will be called, each of which will issue its own query.

这篇关于简单的LINQ to SQL没有支持转换为SQL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆