Ошибка SQLiteException и SQLite рядом с "(": синтаксическая ошибка с Subsonic ActiveRecord
Я столкнулся с интересной ошибкой со следующим запросом LiNQ с использованием LiNQPad и при использовании Subsonic 3.0.x w/ActiveRecord в моем проекте и хотел поделиться этой ошибкой и разрешением для всех, кто сталкивался с ней.
Оператор linq ниже предназначен для группировки записей в коллекции tblSystemsValues в их соответствующую систему, а затем для извлечения системы с самым высоким ID.
from ksf in KeySafetyFunction where ksf.Unit == 2 && ksf.Condition_ID == 1
join sys in tblSystems on ksf.ID equals sys.KeySafetyFunction
join xval in (from t in tblSystemsValues
group t by t.tblSystems_ID into groupedT
select new
{
sysId = groupedT.Key,
MaxID = groupedT.Max(g=>g.ID),
MaxText = groupedT.First(gt2 => gt2.ID ==
groupedT.Max(g=>g.ID)).TextValue,
MaxChecked = groupedT.First(gt2 => gt2.ID ==
groupedT.Max(g=>g.ID)).Checked
}) on sys.ID equals xval.sysId
select new {KSFDesc=ksf.Description, sys.Description, xval.MaxText, xval.MaxChecked}
Сам по себе подзапрос для группировки в groupedT работает отлично, и запрос на сопоставление KeySafetyFunctions с их Системой в tblSystems также прекрасно работает сам по себе.
Однако, пытаясь выполнить завершенный запрос в linqpad или в моем проекте, я продолжал сталкиваться с SQLiteException SQLite Error Near "("
Сначала я попытался разделить запросы внутри своего проекта, потому что знал, что при необходимости могу просто запустить цикл foreach для результатов. Однако я продолжал получать то же исключение!
В конце концов я разделил запрос на три части, прежде чем понял, что меня убивает ленивое выполнение запросов. Затем стало ясно, что добавление спецификатора.ToList() после запроса myProtectedSystem, приведенного ниже, является ключом к тому, чтобы избежать ленивого выполнения после объединения и оптимизации запроса и получения результатов, несмотря на проблемы, с которыми я столкнулся при использовании драйвера SQLite.
// determine the max Text/Checked values for each system in tblSystemsValue
var myProtectedValue = from t in tblSystemsValue.All()
group t by t.tblSystems_ID into groupedT
select new {
sysId = groupedT.Key,
MaxID = groupedT.Max(g => g.ID),
MaxText = groupedT.First(gt2 => gt2.ID ==groupedT.Max(g => g.ID)).TextValue,
MaxChecked = groupedT.First(gt2 => gt2.ID ==groupedT.Max(g => g.ID)).Checked};
// get the system description information and filter by Unit/Condition ID
var myProtectedSystem = (from ksf in KeySafetyFunction.All()
where ksf.Unit == 2 && ksf.Condition_ID == 1
join sys in tblSystem.All() on ksf.ID equals sys.KeySafetyFunction
select new {KSFDesc = ksf.Description, sys.Description, sys.ID}).ToList();
// finally join everything together AFTER forcing execution with .ToList()
var joined = from protectedSys in myProtectedSystem
join protectedVal in myProtectedValue on protectedSys.ID equals protectedVal.sysId
select new {protectedSys.KSFDesc, protectedSys.Description, protectedVal.MaxChecked, protectedVal.MaxText};
// print the gratifying debug results
foreach(var protectedItem in joined)
{
System.Diagnostics.Debug.WriteLine(protectedItem.Description + ", " + protectedItem.KSFDesc + ", " + protectedItem.MaxText + ", " + protectedItem.MaxChecked);
}
1 ответ
Избегайте ленивых вычислений, форсируя раннее выполнение с помощью.ToList() для одного из компонентов окончательного запроса. Результаты будут сохранены в памяти, поэтому постарайтесь убедиться, что вы выбираете небольшой набор данных, и не вводите неограниченный запрос или гигантский запрос в список.