У меня есть эти данные в одной таблице, и я пытаюсь выполнить цикл или рекурсивный метод. Мне нужно получить базу результатов, используя идентификатор встречи. Если я использую идентификатор встречи 1, он вернет 2,3. Если я выполню MeetingID 2, я получу 1,3, а если сделаю 3, я получу 1,2. У меня есть этот метод, но мне нужно много раз звонить, и я хотел знать, есть ли лучший способ. Я считаю, что мне нужен linq для прохождения цепочки родительских/предыдущих встреч и цепочки дочерних/продолжительных встреч.
MeetingId ContinuedMeetingId
---------- -------------
1 2
2 3
3 null
ЭФ/Линк:
var y = (from m in Meetings
where m.MeetingId == MeetingId
select new
{
ContinuedMeetingsId = db.Meetings
.Where(s => s.MeetingId == m.MeetingId)
.Select(s => s.ContinuedMeetingId).FirstOrDefault()
}).FirstOrDefault();
@MakePeaceGreatAgain Я думаю, им нужен такой метод, как GetRelatedMeetings(meetingId)
.
И почему вы дважды возвращаете встречу? Один раз с объекта Meetings
и один раз с db.Meetings
? Другими словами: m
уже является Meeting
, нет необходимости запрашивать его снова у db.Meetings
.
Это можно сделать в SQL с помощью двух рекурсивных CTE — одного, который пересекает цепочку родительских/предыдущих собраний, и другой, который пересекает цепочку дочерних/продолжительных собраний. (Исходная встреча исключается из обоих списков.) Тогда остается просто нажать UNION ALL
и (при желании) STRING_AGG()
, чтобы создать окончательный список, разделенный запятыми.
Эту логику можно обернуть в определяемую пользователем функцию, которую затем можно добавить в модель Entity Framework и вызывать из вашего приложения.
CREATE FUNCTION GetRelatedMeetings (@MeetingId INT)
RETURNS VARCHAR(MAX)
AS BEGIN
DECLARE @RelatedMeetings VARCHAR(MAX);
WITH PriorMeetings AS (
SELECT M.MeetingId
FROM Meetings M
WHERE M.ContinuedMeetingId = @MeetingId
UNION ALL
SELECT M.MeetingId
FROM PriorMeetings PM
JOIN Meetings M
ON M.ContinuedMeetingId = PM.MeetingId
),
ContinuedMeetings AS (
SELECT M.ContinuedMeetingId AS MeetingId
FROM Meetings M
WHERE M.MeetingId = @MeetingId
UNION ALL
SELECT M.ContinuedMeetingId AS MeetingId
FROM ContinuedMeetings CM
JOIN Meetings M
ON M.MeetingId = CM.MeetingId
),
RelatedMeetings AS (
SELECT PM.MeetingId
FROM PriorMeetings PM
UNION ALL
SELECT CM.MeetingId
FROM ContinuedMeetings CM
)
SELECT @RelatedMeetings =
STRING_AGG(RM.MeetingId, ',')
WITHIN GROUP(ORDER BY RM.MeetingId)
FROM RelatedMeetings RM;
RETURN @RelatedMeetings
END
Приведенная выше логика предполагает, что цепочка встреч является линейной с отношениями родитель/потомок 1 к 1. Если бы отношения встреч могли быть «многие ко многим», обход графа был бы гораздо более сложным.
Хотя аналогичная логика может быть реализована в C#, я не знаю способа написать эквивалентный рекурсивный оператор LINQ, который бы отображал выполнение одного запроса SQL. Собственная реализация LINQ, скорее всего, будет зацикливаться и выполнять несколько запросов. (Я считаю, что существуют некоторые надстройки, которые обеспечивают ограниченную поддержку CTE, но я не знаю, поддерживают ли они рекурсию или будут ли они адаптированы к этому решению. Это потребует дополнительного исследования.)
Результаты (с некоторыми дополнительными данными испытаний):
См. эту db<>fiddle для демонстрации.
Честно говоря, я до сих пор не уверен, что вы хотите сделать. и вы только что отредактировали свой вопрос, скопировав и вставив некоторые ключевые слова из первого полученного ответа.
Поэтому я просто предполагаю, что предыдущий ответ более или менее соответствует тому, что вы ищете.
Также ваш var y = (from m in Meetings where m.MeetingId == MeetingId select new{}).FirstOrDefault()
можно упростить, используя Meetings.FirstOrDefault(m => m.MeetingId == MeetingId)
.
Чтобы написать цикл while или рекурсивный метод в Csharp, вы можете попробовать следующий код:
var meetings = new List<Meeting>
{
new Meeting {MeetingId = "1", ContinuedMeetingId = "2"},
new Meeting {MeetingId = "2", ContinuedMeetingId = "3"},
new Meeting {MeetingId = "3", ContinuedMeetingId = null}
};
var selectedMeetingId = "1";
var nextMeetingIds = new List<string>();
var priorMeetingIds = new List<string>();
var nextMeeting = meetings.FirstOrDefault(m => m.MeetingId == selectedMeetingId);
var priorMeeting = meetings.FirstOrDefault(m => m.ContinuedMeetingId == selectedMeetingId);
while (true)
{
if (nextMeeting == null && priorMeeting == null)
{
break;
}
if (nextMeeting != null)
{
var nextMeetingId = nextMeeting.ContinuedMeetingId;
nextMeetingIds.Add(nextMeetingId);
nextMeeting = meetings.FirstOrDefault(m => m.MeetingId == nextMeetingId);
}
if (priorMeeting != null)
{
var priorMeetingId = priorMeeting.MeetingId;
priorMeetingIds.Add(priorMeetingId);
priorMeeting = meetings.FirstOrDefault(m => m.ContinuedMeetingId == priorMeetingId);
}
}
Так в чем именно здесь заключается правило? Выберите
MeetingId
, который вы не запрашивали? Вам нужно немного подробнее рассказать о том, что вы хотите сделать.