#c# #linq #linq-to-sql
#c# #linq #linq-to-sql
Вопрос:
Я новичок в LINQ, и мне немного сложно понять некоторые потоки преобразования данных, поскольку каждый оператор LINQ соединяется вместе. У меня есть оператор SQL довольно стандартного типа, и мне сложно создать аналогичный оператор LINQ.
Объединение и группировка кажутся довольно простыми, однако, когда я, наконец, пытаюсь запустить оператор Select и поместить все различные поля из обеих таблиц, для меня все, кажется, разваливается. Я надеюсь, что смогу опубликовать некоторый SQL-код, затем мою попытку собрать выражение LINQ вместе, и люди здесь смогут ответить на мои вопросы о том, КАК это в принципе должно работать. Почти уверен, что LINQ ПОЛНОСТЬЮ ИСПОРЧЕН. :-/
У меня есть следующий оператор SQL, который предоставляет мне выбор данных, которые я хотел бы затем использовать и передать в элемент управления grid. (Однако с использованием LINQ для объектов)
Вот инструкция SQL, которую я пытаюсь эмулировать в LINQ:
SELECT s.STRUCTURE_ID, s.TITLE, s.PHOTO, s.PHOTO_LINK, COUNT(s.STRUCTURE_ID)
AS "How Many Activities", MIN(m.START_DATE) AS "START DATE", MAX(m.FINISH_DATE) AS "FINISH DATE"
FROM DB.STRUCTURES s
LEFT OUTER JOIN DB.ACTIVITIES m ON s.STRUCTURE_ID = m.STRUCTURE_ID
WHERE s.PARK = 'Elwood' AND m.CONTRACT_NO IS NOT NULL
GROUP BY s.STRUCTURE_ID, s.TITLE, m.STATUS, s.PHOTO, s.PHOTO_LINK
ORDER BY s.STRUCTURE_ID
DB.Structures — это ОДИН файл
DB.Activities — это МНОЖЕСТВО файлов
Цель выбора — выбрать все структуры, которые имеют действия, соответствуют определенному парку и ДЕЙСТВИТЕЛЬНО имеют контракт. Дополнительный небольшой поворот заключается в получении самых ранних дат начала и окончания связанных действий для каждой структуры.
Результирующие наборы данных должны представлять собой сглаженную коллекцию, которую я могу просто передать своему элементу управления grid в следующем формате:
Structure ID Description Photo Start Date Finish Date
HL-100 Activity Room 100 Yes 6/6/2011 8/26/2011
HS-400A Small Ones Gym No 5/2/2011 6/30/2011
Итак, LINQ, который я собрал, выглядит следующим образом:
var query = from s in db.Structures
join a in db.Activities on s.Structure_ID equals a.Structure_ID into sa
from allStructs in sa.DefaultIfEmpty() // I believe this is how to get the outer join and flatten the selection?
where s.PARK == 'Elwood' amp;amp; allStructs.CONTRACT_NO != ''
orderby s.Structure_ID
group s by s.Structure_ID into g
select new
{
myID = g.Key,
myDesc = //I don't know how to display the s.Title here ,
myPhoto = // I don't know how to display the s.Photo here ,
myStartDate = g.Min(c => c.START_DATE),
myEndDate = g.Max(c => c.FINISH_DATE)
};
Итак, теперь к вопросам:
-
Одна вещь, которая мне не ясна в LINQ, не похоже, что после завершения объединения я получаю единственную коллекцию, содержащую ВСЕ объявленные столбцы, как я бы получил со стандартной инструкцией SQL, возвращающей выделение. Это сбивает меня с толку. Может ли кто-нибудь подсказать мне, правда это или нет? Похоже, я должен быть в состоянии «видеть» все столбцы в объекте ‘allStructs’…но это, очевидно, не тот случай.
-
Другая серьезная проблема, с которой я борюсь, заключается в том, как отобразить столбцы из ОДНОГО файла — я не могу просто найти способ перейти к этим полям. (Какой вид связан с # 1 выше.)
-
Наконец, есть ли какие-нибудь хорошие «трюки» или инструменты, с помощью которых вы можете пошагово просматривать каждую строку в выражении LINQ, как вы можете в отладчике для прямого кода C #? Когда это выражение LINQ попадает в обычный отладчик в VS, оно просто выделяет полное выражение, и вы действительно не можете видеть, что происходит при настройке / выполнении. (Я понимаю, что здесь это может потребовать многого.) В настоящее время я просто использую консоль, чтобы просмотреть что-либо после приведения выражения в действие, например, для выполнения запроса.Count() или что-то в этом роде.
Я был бы искренне признателен за любую помощь в получении лучшего понимания того, как данные преобразуются с помощью этого процесса LINQ. Я много читал здесь, MSDN и купил пару книг, но я не получил того «момента лампочки», который, кажется, все указывают, наступит.
Спасибо всем … 🙂
Ответ №1:
-
После
join
у вас есть доступ кs
(текущей структуре) иsa
группе действий для этогоStructure_ID
. ПослеDefaultIfEmpty()
у вас будет доступ к тому же самомуs
и nowallStructs
, который будет точно соответствоватьm
вашему исходному примеру SQL. Вы никогда не получите единую переменную, которая представляет все столбцы в обеих таблицах, но вы также не получите этого в SQL. -
Я считаю, что LINQ to SQL достаточно умен, чтобы перевести группировку по составному ключу, и в этом случае это то, что вы, вероятно, хотите:
var query = from s in db.Structures join a in db.Activities on s.Structure_ID equals a.Structure_ID into sa from m in sa.DefaultIfEmpty() // LEFT OUTER JOIN where s.PARK == 'Elwood' amp;amp; m.CONTRACT_NO != '' orderby s.Structure_ID group m by new { s.Structure_ID, s.Title, s.Photo } into g select new { myID = g.Key.Structure_ID, myDesc = g.Key.Title, myPhoto = g.Key.Photo, myStartDate = g.Min(c => c.START_DATE), myEndDate = g.Max(c => c.FINISH_DATE) };
Обратите внимание, что я переключился
allStructs
наm
для согласованности с вашим SQL и переключилсяgroup by
на использованиеm
вместоs
.m
Значения — это то, что будет содержаться вg
группах, причемKey
они представляют собой кортеж изStructure_ID
,Title
иPhoto
. -
Для отладки лучше всего включить какое-нибудь ведение журнала (
DataContext.Log
свойство), чтобы увидеть, какой SQL генерируется. Вы также можете использовать SQL profiler. Иногда это помогает логически разобраться с коллекциями в памяти и LINQ to Objects, с оговоркой, что вы можете создавать в памяти вещи, которые вообще не переводятся в SQL.
Комментарии:
1. БОЛЬШОЕ спасибо за помощь и разъяснения по этому поводу. Я никогда раньше не видел эту команду ‘group m by new’, и для меня это было недостающей частью. Наилучшие пожелания … 🙂
Ответ №2:
Чтобы ответить на ваш второй вопрос, я думаю, вы можете сделать следующее:
myDesc = g.First().Title
myPhoto = g.First().Photo
Комментарии:
1. Привет, спасибо за это. Я пробовал это в нескольких местах, тестируя, чтобы увидеть, как это работает, и он действительно получает информацию, как вы описали! Наилучшие пожелания … 🙂