仅在LINQ to Entities

时间:2019-01-22 03:19:06

标签: c# entity-framework linq

最近,当我在我们的项目中发现问题时,我一直在重构一些笨拙而不工作的LINQ查询。这是一个让我陷入困境的人。我必须承认,我是一个使用实体框架弹入C#的Android开发人员,所以我并不真正了解这里发生的事情。不过,这些查询对我而言几乎相同(在此处撒上子查询,在此处撒上新的联接)。第一个方法将返回无错误:

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分钟的时间才能将数据填充到另一个表上,而现在它们在<1ms内完成。

这里是替换方法,除了现在包含一个子查询外,应该返回所有相同的方法。它还不再设置无数列表,而仅使用数据库上下文处理查询。这将引发错误,指出:

仅当未指定修剪字符作为参数时,LINQ to Entities中才支持方法'System.String TrimStart(Char [])'。

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 :(得分:0)

  • 一个正在使用的内存数据(存储库代码(长叹气))

  • 另一种将投影推回数据库的状态,这是正在破坏的数据库

引发此异常的全部原因是因为数据库不了解string.Trim()的概念,而Split也将引发

但是,我们可以使用任何String Canonical Functions ..,尽管最简单的方法只是项目,因为您要处理内存中需要事后处理的字符串操作

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

请注意,我们可以将LTRIM用作EntityFunctions,但是只会修剪空间。再次看到String Canonical Functions