У меня есть следующий код внутри моего веб-приложения asp.net MVC:
var currentport = tms.TMSSwitchPorts
.Where(a => a.SwitchID == fromID)
.Select(a2 => a2.PortNumber)
.ToList();
if (currentport.Any(tms.TMSSwitchPorts
.Where(a => a.SwitchID == toID)
.Select(a => a.PortNumber)
.ToList()
)
)
{
// do something
}
но я не могу использовать .Any()
таким образом, хотя я выбираю поле PortNumber в обоих списках?
Может ли кто-нибудь посоветовать?
Если ваша цель как jwg описана в его комментарии, вы можете сделать:
var currentportFrom = tms.TMSSwitchPorts
.Where(a => a.SwitchID == fromID)
.Select(a2 => a2.PortNumber)
.ToList();
var currentportTo = tms.TMSSwitchPorts
.Where(a => a.SwitchID == fromID)
.Select(a2 => a2.PortNumber)
.ToList();
if(currentportFrom.Any(cp => currentportTo.Contains(cp))
{
//do something
}
Вы можете это эффективно и полностью использовать в базе данных, используя простой Join
:
var match = tms.TMSSwitchPorts.Where(a => a.SwitchID == fromID)
.Join(tms.TMSSwitchPorts.Where(a => a.SwitchID == toID),
(a) => a.PortNumber,
(b) => b.PortNumber,
(a, b) => true).Any();
if (match) { ... }
Сгенерированный SQL должен выглядеть так:
SELECT
(CASE
WHEN EXISTS(
SELECT NULL AS [EMPTY]
FROM [TMSSwitchPorts] AS [t0]
INNER JOIN [TMSSwitchPorts] AS [t1] ON [t0].[PortNumber] = [t1].[PortNumber]
WHERE ([t0].[SwitchID] = @p0) AND ([t1].[SwitchID] = @p1)
) THEN 1
ELSE 0
END) AS [value]
поэтому у вас нет каких - либо данных ожидают один 1
или 0
движется по проводам, и вы не должны загромождать память приложения.
Код
if (currentport.Any(tms.TMSSwitchPorts
.Where(a => a.SwitchID == toID)
.Select(a => a.PortNumber)
.ToList()
)
не будет работать, потому что Any
ожидает предикат в виде Func<T, bool>
, но вы передаете ему List<Int>
(предполагая, что PortNumber
является int
).
tms
- это запрос к базе данных, а не какой-либо другой источник. Не хочу редактировать, чтобы навязать мой стиль, но я бы хотел, чтобы вы переместили Any()
в его собственную строку :)
На основе комментария jwg вы можете проверить, есть ли совпадение между первым набором портов (From) и вторым набором (to), с использованием соответствия Contains
:
var fromPorts = tms.TMSSwitchPorts
.Where(a => a.SwitchID == fromID)
.Select(a2 => a2.PortNumber);
if (tms.TMSSwitchPorts
.Any(a => a.SwitchID == toID &&
fromPorts.Contains(a.PortNumber)))
Возьмите аналогичный список для SwitchID == toID
.
var alreadyUsed = tms.TMSSwitchPorts
.Where(a => a.SwitchID == toID)
.Select(a2 => a2.PortNumber)
.ToList();
Затем просто проверьте, что ничего не отображается в обоих двух списках.
if (currentPort.Intersect(alreadyUsed).Any())
{ // do something }
Any()
не работает так, как вы думаете. Сам по себе, как используется выше, он проверяет любые элементы в контейнере. Как показано в ответе @BenAaronson (что немного лучше, чем этот ответ), он проверяет, содержит ли IEnumerable
любой элемент, для которого аргумент функции возвращает true.
list1.Any(HasSomeProperty)
где HasSomeProperty
это функция, которая принимает элемент list1
и возвращает логическое значение; или чаще всего с лямбдой:
list1.Any(x => SomePropertyHoldsFor(x))
Я сказал, что ответ @BenAaronson был лучше, потому что он позволяет некоторые "короткие замыкания" оптимизаций, которые я не думал о моем решении. Они упомянуты в комментариях к его ответу. Однако с некоторыми проб и ошибок я обнаружил, что Intersect автоматически выполняет те же самые оптимизации - в частности, он кэширует "вывод" одного IEnumerable для сравнения с каждым элементом другого, а не пересекает его каждый раз. Таким образом, мое решение лучше, так как Intersect
автоматически делает то, что вам нужно немного подумать о методе Бена;) @sloth ответ включает в себя другую автоматическую оптимизацию и гораздо лучше подходит для запроса базы данных с использованием Queryable
который имел в виду айзер,
В этом ответе объясняется, как работает Intersect
- на самом деле это не кеширование, а доступ к каждому IEnumerable
только один раз.
ToList
дляcurrentportTo
, чтобы эти данныеcurrentportTo
только один раз и сохранялись в памяти, но не делатьToList
дляcurrentportFrom
, чтобыAny()
останавливался, как только конфликтующий элемент найден.