如何修复这个linq到没有支持转换为sql的sql查询?

时间:2009-03-07 05:49:56

标签: .net linq-to-sql

我最后得到了一个带有自定义扩展方法的LinqToSql查询。当我尝试linq2sql尝试生成sql语句时,这个扩展方法是错误的。

错误:

  

方法   'System.Collections.Generic.IList 1[System.String] ToListIfNotNullOrEmpty[String](System.Collections.Generic.IEnumerable 1 [System.String])'   没有受支持的SQL翻译。

扩展方法:

public static IList<T> ToListIfNotNullOrEmpty<T>(this IEnumerable<T> value)
{
    return value.IsNullOrEmpty()
               ? null
               : (value is IList<T> ? value as IList<T> : new List<T>(value));
}

样本Linq到sql代码:

public IQueryable<Models.Post> GetPosts()
{
    var dataLoadOptions = new DataLoadOptions();
    dataLoadOptions.LoadWith<Post>(x => x.PostTags);
    dataLoadOptions.LoadWith<PostTag>(x => x.Tag);
    _sqlDatabase.LoadOptions = dataLoadOptions;

    return from p in _sqlDatabase.Posts
        select new Models.Post
        {
            PostId = p.PostId,

            CommentList = (from c in p.Comments
                select new Models.Comment
                {
                    PostId = c.PostId,
                    < ... stuff snipped ... >
                }).ToListIfNotNullOrEmpty(),

            < ... more stuff snipped ... >

            TagList = (from t in p.PostTags
                select t.Tag.Description).ToListIfNotNullOrEmpty(),
        };
}

通常情况下,我最后会有一个ToList()方法,但如果列表为空,我想返回一个空对象。因此我的扩展方法。

有人可以建议我应该如何解决这个问题吗?

3 个答案:

答案 0 :(得分:2)

如果您使用IQueriable<T>代替IEnumerable<T>制作扩展方法,则可以控制查询执行的时间:

    public static IList<T> ToListIfNotNullOrEmpty<T>(this IQueryable<T> value)
    {
        var results = value.Provider.Execute<IEnumerable<T>>(value.Expression);
        return results == null || results .Count() == 0 
                   ? null
                   : results.ToList();
    }

答案 1 :(得分:1)

你试过这个:

return _postRepository.Comments.ToList().ToNullIfEmpty();

使用扩展方法:

public static IList<T> ToNullIfEmpty<T>(this List<T> value)
{
    return value.IsNullOrEmpty() ? null: value;
}

问题是这一点:

TagList = (from t in p.PostTags
            select t.Tag.Description).ToListIfNotNullOrEmpty()

如果你有这个,那么它会起作用:

select new Models.Post
    {
        ....
    }.ToList().ToNullIfEmpty();

或者您可以尝试更改扩展方法以扩展IQueryable,就像其他评论者建议的那样。

答案 2 :(得分:0)

我遇到了同样的问题。问题是您不能在延迟的linq2sql表达式中使用扩展方法。这是因为IQueryable提供程序在执行查询时会尝试将表达式树中的所有方法转换为SQL。它无法区分您的方法和linq2sql原生的方法之间的区别。因此问题。

解决方案是将方法添加到将扩展本机linq2sql类而不是扩展方法的分部类。

编辑:我正在为代码添加建议的更改

public IQueryable<Models.Post> GetPosts()
{    
    var dataLoadOptions = new DataLoadOptions();
    dataLoadOptions.LoadWith<Post>(x => x.PostTags);
    dataLoadOptions.LoadWith<PostTag>(x => x.Tag);
    _sqlDatabase.LoadOptions = dataLoadOptions;

    return from p in _sqlDatabase.Posts
        select new Models.Post
        {
            PostId = p.PostId,
            CommentList = p.GetCommentList(),
            < ... more stuff snipped ... >
            TagList = (from t in p.PostTags
                select t.Tag.Description).ToListIfNotNullOrEmpty()
        };
}

然后我会在部分类

中使用GetCommentList()方法
public partial class Post
{
     public List<Comment> GetCommentList()
     {
           List<Commment> resultList = from this.Comments etc...
           < ... put the select code here ... >
           if(resultList.Count > 0)
                return resultList;

           return null;
     }
}