Одна проблема, которую он решает: Код проще, чем lambda для вызова в конструкторе, который использует функцию выходного параметра для инициализации члена const
Вы можете инициализировать член const вашего класс, с вызовом функции, которая устанавливает его значение, возвращая свой вывод в качестве выходного параметра.
Вам нужно повернуть его на голову с точки зрения того, как вы думаете об этом. Вместо того, чтобы делать «в», чтобы найти права пользователя текущего элемента в предопределенном наборе применимых прав пользователя, вы запрашиваете предопределенный набор прав пользователя, если он содержит применимое значение текущего элемента. Это точно так же, как вы бы нашли элемент в обычном списке в .NET.
Существует два способа сделать это с помощью LINQ, один использует синтаксис запроса, а другой использует синтаксис метода. По существу, они одинаковы и могут использоваться взаимозаменяемо в зависимости от ваших предпочтений:
Синтаксис запроса:
var selected = from u in users
where new[] { "Admin", "User", "Limited" }.Contains(u.User_Rights)
select u
foreach(user u in selected)
{
//Do your stuff on each selected user;
}
Метод Синтаксис:
var selected = users.Where(u => new[] { "Admin", "User", "Limited" }.Contains(u.User_Rights));
foreach(user u in selected)
{
//Do stuff on each selected user;
}
Мое личное предпочтение в этом случае может быть синтаксисом метода, потому что вместо назначения переменной я мог бы сделать foreach над анонимным вызовом, подобным этому:
foreach(User u in users.Where(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
//Do stuff on each selected user;
}
Синтаксически это выглядит более сложным, и вы должны понимать концепцию лямбда-выражений или делегатов, чтобы действительно понять, что происходит, но, как вы можете видеть, это скомпенсирует код с достаточной суммой.
It все сводится к вашему стилю кодировки и предпочтениям - все три моих примера делают то же самое несколько иначе.
Альтернативный способ даже не использует LINQ, вы можете использовать тот же синтаксис метода, который заменяет «где», с «FindAll» и получить тот же результат, который также будет работать в .NET 2.0:
foreach(User u in users.FindAll(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
//Do stuff on each selected user;
}
Серьезно? Вы никогда не пользовались
where (t.MyTableId == 1 || t.MyTableId == 2 || t.MyTableId == 3)
Checks = NumValues * NumRows
. Поскольку это расчет типа M * N, если он мал, тогда время выполнения каждой требуемой проверки также будет небольшим. Я добавил ограничение, поэтому cjm30305 будет знать, как настроить тестовую среду, где показано, почему его решение плохое.
– Trisped
18 September 2016 в 17:59
where new[] { 1, 2, 3 }.Contains(x)
делает меньше сравнений тогда where (x == 1 || x == 2 || x == 3)
?
– tymtam
19 September 2016 в 22:19
Это должно быть достаточно для вашей цели. Он сравнивает две коллекции и проверки, если одна коллекция имеет значения, соответствующие значениям в другой коллекции
fea_Features.Where(s => selectedFeatures.Contains(s.feaId))
Если вы используете VS2008 / .net 3.5, см. подсказку Alex James № 8: http://blogs.msdn.com/alexj/archive/2009/03/26/tip-8-writing -where-in-style-queries-using-linq-to-entities.aspx
В противном случае просто используйте метод array.Contains (someEntity.Member).
Я также пытался работать с подобной SQL-IN-вещью - запросом на модель данных сущности. Мой подход - строковый построитель для создания большого OR-выражения. Это ужасно уродливо, но я боюсь, что это единственный способ пойти прямо сейчас.
Теперь хорошо, это выглядит так:
Queue<Guid> productIds = new Queue<Guid>(Products.Select(p => p.Key));
if(productIds.Count > 0)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}.ProductId = Guid\'{1}\'", entities.Products.Name, productIds.Dequeue());
while(productIds.Count > 0)
{
sb.AppendFormat(" OR {0}.ProductId = Guid\'{1}\'",
entities.Products.Name, productIds.Dequeue());
}
}
Работа с GUID в этом контексте: Как вы можете видеть выше, всегда есть слово «GUID» перед GUID ifself в фрагментах строки запроса. Если вы не добавите это, ObjectQuery<T>.Where
выдает следующее исключение:
Типы аргументов «Edm.Guid» и «Edm.String» несовместимы для этой операции., Near equals expression , строка 6, столбец 14.
blockquote>Обнаружено это в форумах MSDN, может быть полезно иметь в виду.
Matthias
... с нетерпением жду следующей версии .NET и Entity Framework, когда все станет лучше. :)
В этом контексте я поеду на Inner Join. Если бы я использовал contains, он бы итерации 6 раз, несмотря на тот факт, что существует только одно совпадение.
var desiredNames = new[] { "Pankaj", "Garg" };
var people = new[]
{
new { FirstName="Pankaj", Surname="Garg" },
new { FirstName="Marc", Surname="Gravell" },
new { FirstName="Jeff", Surname="Atwood" }
};
var records = (from p in people join filtered in desiredNames on p.FirstName equals filtered select p.FirstName).ToList();
Предположим, у меня есть два объекта списка.
List 1 List 2
1 12
2 7
3 8
4 98
5 9
6 10
7 6
Используя Contains, он будет искать каждый элемент List 1 в списке 2, что означает, что итерация произойдет 49 раз !!!
Это может быть возможный способ непосредственного использования методов расширения LINQ для проверки предложения in
var result = _db.Companies.Where(c => _db.CurrentSessionVariableDetails.Select(s => s.CompanyId).Contains(c.Id)).ToList();
Альтернативный метод ответа BenAlabaster
Прежде всего, вы можете переписать запрос следующим образом:
var matches = from Users in people
where Users.User_Rights == "Admin" ||
Users.User_Rights == "Users" ||
Users.User_Rights == "Limited"
select Users;
Конечно, это более «многословно» и больно писать но он работает все равно.
Итак, если бы у нас был какой-то метод утилиты, который упростил создание таких выражений LINQ, мы бы были в бизнесе.
с помощью метода утилиты на месте вы можете написать что-то вроде этого:
var matches = ctx.People.Where(
BuildOrExpression<People, string>(
p => p.User_Rights, names
)
);
Это создает выражение, которое имеет такой же эффект, как:
var matches = from p in ctx.People
where names.Contains(p.User_Rights)
select p;
Но что более важно, фактически работает с .NET 3.5 SP1.
Вот функция сантехники, которая делает это возможным:
public static Expression<Func<TElement, bool>> BuildOrExpression<TElement, TValue>(
Expression<Func<TElement, TValue>> valueSelector,
IEnumerable<TValue> values
)
{
if (null == valueSelector)
throw new ArgumentNullException("valueSelector");
if (null == values)
throw new ArgumentNullException("values");
ParameterExpression p = valueSelector.Parameters.Single();
if (!values.Any())
return e => false;
var equals = values.Select(value =>
(Expression)Expression.Equal(
valueSelector.Body,
Expression.Constant(
value,
typeof(TValue)
)
)
);
var body = equals.Aggregate<Expression>(
(accumulate, equal) => Expression.Or(accumulate, equal)
);
return Expression.Lambda<Func<TElement, bool>>(body, p);
}
Я не собираюсь пытаться объяснить этот метод, кроме как сказать, что он по существу строит предикат выражение для всех значений с помощью значенияSelector (т.е. p => p.User_Rights) и ORs, которые предикаты вместе создают выражение для полного предиката