Метод «System.String TrimStart (Char [])» поддерживается только в LINQ to Entities - PullRequest
0 голосов
/ 22 января 2019

В последнее время я выполняю рефакторинг некоторых наших неуклюжих и не работающих запросов LINQ, когда нахожу проблемы в нашем проекте. Вот тот, который бросает меня за петлю. Должен признаться, я разработчик Android, катапультировавшийся в C # со структурой сущностей, поэтому я не совсем понимаю, что здесь происходит. Тем не менее эти запросы выглядят для меня почти одинаково (добавьте сюда подзапрос и добавьте новое соединение). Первый метод вернется без ошибок:

public virtual IQueryable<ScratchGameDetailsModel> GetScratchGameDetails(string reconGUID)
    {
        var lotteryReconHeader = _lotteryReconHeaderRepository.GetAll().AsEnumerable(); // Changed on Nov 7,2017
        var lotteryReconDetails = _lotteryReconDetailRepository.GetAll().Where(s => s.ReconGUID == reconGUID).AsEnumerable();
        var lotteryGames = _lotteryGameRepository.GetAll().AsEnumerable();
        var lotteryActivations = _lotteryActivationRepository.GetAll().AsEnumerable();


        var response = (from ltrd in lotteryReconDetails
                        join lg in lotteryGames on ltrd.GameGUID equals lg.GameGUID
                        join la in lotteryActivations on lg.GameGUID equals la.GameGUID into LotteryActivations_join
                        from la in LotteryActivations_join.DefaultIfEmpty()
                        join ltrh in lotteryReconHeader on ltrd.ReconGUID equals ltrh.ReconGUID // Added on Nov 7,2017
                        select new ScratchGameDetailsModel()
                        {
                            ReconGUID = ltrd.ReconGUID,
                            GameGUID = ltrd.GameGUID,
                            GameNumber = lg.GameNumber ?? Constants.Zero,
                            GameName = lg.GameName ?? String.Empty,
                            GameUPC = lg.GameUPC ?? string.Empty,
                            GameBin = lg.GameBin ?? Constants.Zero,
                            StartCount = ltrd.StartCount,
                            EndCount = ltrd.EndCount,
                            CashierSales = ltrd.CashierSales,
                            ExpectedStartCount = ltrd.ExpectedStartCount,
                            QtyOnRoll = lg.QtyOnRoll ?? Constants.Zero,
                            BookNumber = (la == null || la.BookNumber == null ? string.Empty : la.BookNumber.Split(new char[] { '-' }, 2).ElementAt(1).TrimStart('-')),
                            ReconTimeStamp = ltrh.ReconTimeStamp    // Added on Nov 7,2017
                        });

        return response.AsQueryable();
    }

Вы, вероятно, можете сказать, почему мне не нравится этот метод, 3 из этих бесчисленных списков являются полными дампами таблиц БД, к которым позже присоединяются. Когда БД растет, время запроса этих переменных увеличивается. Полная трата ресурсов, если вы спросите меня. Я уже исправил некоторые методы, которые заняли более 5 минут для заполнения данных в другой таблице из-за объявления больших переменных, и теперь они выполняются за <1 мс. </p>

Вот метод замены, который должен возвращать все то же самое, за исключением того, что теперь есть вложенный запрос. Он также больше не устанавливает бесчисленные списки и просто обрабатывает запрос, используя контекст БД. Это выдает ошибку, заявляющую:

Метод 'System.String TrimStart (Char [])' поддерживается только в LINQ to Entities, если в качестве аргументов не указаны символы усечения.

public virtual IQueryable<ScratchGameDetailsModel> GetScratchGameDetailsNew(string reconGUID)
    {
        var newResponse = (from ltrd in _context.LotteryReconDetail
                           join lg in _context.LotteryGame on ltrd.GameGUID equals lg.GameGUID
                           join la in _context.LotteryActivation
                                on new
                                {
                                    lg.GameGUID,
                                    BookNumber =
                                    ((from la in _context.LotteryActivation
                                      where la.GameGUID == lg.GameGUID
                                      orderby la.row_id descending
                                      select new { la.BookNumber }).FirstOrDefault().BookNumber)
                                }
                                equals new { la.GameGUID, la.BookNumber } into la_join
                           from la in la_join.DefaultIfEmpty()
                           join ltrh in _context.LotteryReconHeader on ltrd.ReconGUID equals ltrh.ReconGUID
                           where ltrd.ReconGUID == reconGUID
                           select new ScratchGameDetailsModel()
                           {
                               ReconGUID = ltrd.ReconGUID,
                               GameGUID = ltrd.GameGUID,
                               GameNumber = lg.GameNumber ?? Constants.Zero,
                               GameName = lg.GameName ?? String.Empty,
                               GameUPC = lg.GameUPC ?? string.Empty,
                               GameBin = lg.GameBin ?? Constants.Zero,
                               StartCount = ltrd.StartCount,
                               EndCount = ltrd.EndCount,
                               CashierSales = ltrd.CashierSales,
                               ExpectedStartCount = ltrd.ExpectedStartCount,
                               QtyOnRoll = lg.QtyOnRoll ?? Constants.Zero,
                               BookNumber = (la == null || la.BookNumber == null ? string.Empty : la.BookNumber.Split(new char[] { '-' }, 2).ElementAt(1).TrimStart('-')),
                               ReconTimeStamp = ltrh.ReconTimeStamp
                           });

        return newResponse.AsQueryable();
    }

При использовании моего метода, если я использую те же операции (например, установка переменных) и использую их для запроса, я получаю «Ссылка на объект не установлена ​​на экземпляр объекта». Эврика! Но почему? Этот же необработанный запрос SQL не имеет проблем, и мне бы очень хотелось узнать, в чем отличие LINQ при использовании контекста БД по сравнению с контекстом запроса / перечисления.

Я также изменил эти объявления переменных и использовал AsQueryable () вместо AsEnumerable (), чтобы весь список не выводился, а использовался как контекст БД в запросе. Если я не ошибаюсь, это заметная разница между перечислимым и запрашиваемым.

Это было решено, как указал @TheGeneral. Назначение вызова было обновлено для обработки усечения значения по мере необходимости.

BookNumber = (la == null || la.BookNumber == null ? string.Empty : la.BookNumber),

Затем обновил вызывающий метод для обработки обрезки

var scratchGameDetails = _lotteryReconService.GetScratchGameDetailsNew(reconGUID).ToList().Select(s => new
            {
                s.ReconGUID,
                s.GameGUID,
                s.GameNumber,
                s.GameName,
                s.GameUPC,
                s.GameBin,
                s.StartCount,
                s.EndCount,
                s.CashierSales,
                s.ExpectedStartCount,
                RangeStart = gameStartCount,
                RangeEnd = useBaseZero ? (s.QtyOnRoll - 1) : s.QtyOnRoll,
                BookNumber = (s.BookNumber == string.Empty ? string.Empty : s.BookNumber.Split(new char[] { '-' }, 2).ElementAt(1).TrimStart('-')),
                s.ReconTimeStamp
            }).OrderByDescending(x => x.ReconTimeStamp).Distinct();

1 Ответ

0 голосов
/ 22 января 2019
  • Один использует в памяти данные (код хранилища ( мега вздох ))

  • Другой отталкивает проекцию обратно от базы данных, которая является той, которая ломается

Причина, по которой он генерирует это исключение, заключается в том, что база данных не понимает концепцию string.Trim(), также Split также будет выбрасывать

Тем не менее, мы можем использовать любую из строковых канонических функций .. хотя самый простой способ - просто проецировать, поскольку вы имеете дело с манипуляциями со строками, которые вам требуются после факта в памяти

BookNumber = (la == null || la.BookNumber == null ? string.Empty : la.BookNumber,

Обратите внимание, что мы можем использовать LTRIM как EntityFunctions, однако это только урезает пробел. Еще раз смотрите Строковые канонические функции

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...