У меня есть следующий код, который истекает:
using (var ts = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
{
ECWSDataContext dc = new ECWSDataContext();
IQueryable<Ticket> results = dc.Tickets;
Business.TicketStatistic statistic = results
.Select(r => new
{
GroupID = 1,
IsVoided = r.IsVoided ? 1 : 0,
IsWarning = r.TicketFilingTypeID == 5 ? 1 : 0,
TotalFelonies = r.TotalFelonies,
TotalMisdemeanors = r.TotalMisdemeanors,
TotalInfractions = r.TotalInfractions,
TotalOrdinances = r.TotalOrdinances,
TotalWarnings = r.TotalWarnings
})
.GroupBy(t => t.GroupID)
.Select(g => new Business.TicketStatistic()
{
TotalTickets = g.Count(),
TotalVoids = g.Sum(x => x.IsVoided),
TotalTicketWarnings = g.Sum(x => x.IsWarning),
TotalFelonies = g.Sum(x => x.TotalFelonies),
TotalMisdemeanors = g.Sum(x => x.TotalMisdemeanors),
TotalInfractions = g.Sum(x => x.TotalInfractions),
TotalOrdinances = g.Sum(x => x.TotalOrdinances),
TotalOffenseWarnings = g.Sum(x => x.TotalWarnings)
}).FirstOrDefault();
}
Я профилировал SQL с помощью SQL Server Profiler и взял выполненный SQL. Как и ожидалось, он содержит ТОП-1. Когда я запускаю точный SQL в SQL Management Studio, он сразу возвращается. Тем не менее, он продолжает время ожидания в коде. Удивительно, но если поменять его на следующее, это прекрасно работает:
using (var ts = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
{
ECWSDataContext dc = new ECWSDataContext();
IQueryable<Ticket> results = dc.Tickets;
var stats = results
.Select(r => new
{
GroupID = 1,
IsVoided = r.IsVoided ? 1 : 0,
IsWarning = r.TicketFilingTypeID == 5 ? 1 : 0,
TotalFelonies = r.TotalFelonies,
TotalMisdemeanors = r.TotalMisdemeanors,
TotalInfractions = r.TotalInfractions,
TotalOrdinances = r.TotalOrdinances,
TotalWarnings = r.TotalWarnings
})
.GroupBy(t => t.GroupID)
.Select(g => new Business.TicketStatistic()
{
TotalTickets = g.Count(),
TotalVoids = g.Sum(x => x.IsVoided),
TotalTicketWarnings = g.Sum(x => x.IsWarning),
TotalFelonies = g.Sum(x => x.TotalFelonies),
TotalMisdemeanors = g.Sum(x => x.TotalMisdemeanors),
TotalInfractions = g.Sum(x => x.TotalInfractions),
TotalOrdinances = g.Sum(x => x.TotalOrdinances),
TotalOffenseWarnings = g.Sum(x => x.TotalWarnings)
}).ToArray();
Business.TicketStatistic statistic = stats.FirstOrDefault();
}
Я понимаю, что теперь я перечисляю результаты, прежде чем применять FirstOrDefault () к коллекции, находящейся сейчас в памяти. Но кажется странным, что при выполнении одного и того же вывода SQL в первом сценарии непосредственно в SQL Server проблем не было.
Может кто-нибудь объяснить, что здесь происходит? В данном случае это был групповой запрос, который всегда возвращал одну строку независимо. Так что мне повезло, что я могу перечислить перед применением FirstOrDefault (). Но для возможной будущей ссылки, что, если этот запрос вернул тысячи строк, для которых я хотел только TOP 1.
ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ
SQL с использованием .FirstOrDefault ():
SELECT TOP 1 Field1, Field2...
FROM
(
SELECT SUM(Field) as Field1, ...
FROM ...
) SUB
SQL с использованием .ToArray ():
SELECT SUM(Field) as Field1, ...
FROM ...
Выполнение любого из них непосредственно в SQL Mgt Studio привело к одинаковым результатам за то же время. Однако, когда LINQ выполняет первый, я получаю тайм-аут.