Как исправить этот запрос linq to sql, который не поддерживает перевод в sql? - PullRequest
1 голос
/ 07 марта 2009

В конце я получил запрос 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 to 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 ]

2 голосов
/ 09 марта 2009

Если вы используете метод расширения, принимающий 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 голос
/ 08 марта 2009

Вы пробовали это:

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, как предложил другой комментатор.

0 голосов
/ 09 марта 2009

У меня была такая же проблема. Проблема в том, что вы не можете использовать методы расширения внутри отложенного выражения 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;
     }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...