【发布时间】:2019-01-22 03:19:05
【问题描述】:
最近,当我在项目中发现问题时,我一直在重构我们的一些笨重且无法正常工作的 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 分钟以上才能在另一个表上填充数据的方法,现在它们正在
这是一个替换方法,除了现在包含一个子查询外,它应该返回所有相同的方法。它也不再设置 ienumerable 列表,而只是使用 DB 上下文处理查询。这会引发错误说明:
只有在没有指定修剪字符作为参数时,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 中使用 DB 上下文与可查询/可枚举上下文的区别。
我还修改了这些变量声明并使用 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();
【问题讨论】:
-
你认为
AsEnumerable会做什么? -
我的假设是
TrimStart()在 SQL 中被转换为LTRIM,因此无法处理“trimchars”参数的实际值。但这只是一个猜测。这是一个较旧的,但提到了这一点:stackoverflow.com/questions/7936718/… -
@mjwillis,据我了解,它会根据从查询中检索到的数据创建一个枚举列表。之前使用的查询在执行任何其他查询功能之前将整个表转储到内存中。
标签: c# entity-framework linq