Respostas:
Você precisa invertê-lo em termos da maneira como pensa sobre isso. Em vez de "entrar" para encontrar os direitos de usuário do item atual em um conjunto predefinido de direitos de usuário aplicáveis, você está solicitando a um conjunto predefinido de direitos de usuário se ele contém o valor aplicável do item atual. É exatamente da mesma maneira que você encontraria um item em uma lista regular no .NET.
Há duas maneiras de fazer isso usando o LINQ, um usa a sintaxe da consulta e o outro usa a sintaxe do método. Essencialmente, eles são iguais e podem ser usados alternadamente, dependendo da sua preferência:
Sintaxe da consulta:
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;
}
Sintaxe do método:
var selected = users.Where(u => new[] { "Admin", "User", "Limited" }.Contains(u.User_Rights));
foreach(user u in selected)
{
//Do stuff on each selected user;
}
Minha preferência pessoal nesse caso pode ser a sintaxe do método, porque, em vez de atribuir a variável, eu poderia fazer o foreach em uma chamada anônima como esta:
foreach(User u in users.Where(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
//Do stuff on each selected user;
}
Sintaticamente, isso parece mais complexo, e você precisa entender o conceito de expressões ou delegados lambda para realmente descobrir o que está acontecendo, mas, como você pode ver, isso condensa o código em uma quantidade razoável.
Tudo se resume ao seu estilo e preferência de codificação - todos os três exemplos fazem a mesma coisa de maneira um pouco diferente.
Uma maneira alternativa nem usa o LINQ, você pode usar a mesma sintaxe de método substituindo "where" por "FindAll" e obter o mesmo resultado, que também funcionará no .NET 2.0:
foreach(User u in users.FindAll(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
//Do stuff on each selected user;
}
Isso deve bastar para o seu propósito. Ele compara duas coleções e verifica se uma coleção tem os valores correspondentes aos da outra coleção
fea_Features.Where(s => selectedFeatures.Contains(s.feaId))
Se você estiver usando o VS2008 / .net 3.5, consulte a dica 8 de Alex James: http://blogs.msdn.com/alexj/archive/2009/03/26/tip-8-writing-where-in-style -queries-using-linq-to-entity.aspx
Caso contrário, basta usar o método array.Contains (someEntity.Member).
Eu irei para o Inner Join neste contexto. Se eu tivesse usado contém, ele iria repetir 6 vezes, apesar do fato de haver apenas uma correspondência.
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();
Suponha que eu tenha dois objetos de lista.
List 1 List 2
1 12
2 7
3 8
4 98
5 9
6 10
7 6
Usando Contém, ele procurará cada item da Lista 1 na Lista 2, o que significa que a iteração ocorrerá 49 vezes !!!
Também tentei trabalhar com algo semelhante ao SQL-IN - consultando um modelo de dados de entidade . Minha abordagem é um construtor de strings para compor uma grande expressão OR. Isso é terrivelmente feio, mas receio que seja o único caminho a seguir agora.
Agora, bem, isso é assim:
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());
}
}
Trabalhando com GUIDs neste contexto : Como você pode ver acima, sempre há a palavra "GUID" antes do GUID se nos fragmentos de string de consulta. Se você não adicionar isso, ObjectQuery<T>.Where
lança a seguinte exceção:
Os tipos de argumento 'Edm.Guid' e 'Edm.String' são incompatíveis para esta operação., Quase igual à expressão, linha 6, coluna 14.
Encontrou isso nos fóruns do MSDN, pode ser útil ter em mente.
Matthias
... ansioso pela próxima versão do .NET e Entity Framework, quando tudo melhorar. :)
Um método alternativo para a resposta do BenAlabaster
Primeiro de tudo, você pode reescrever a consulta assim:
var matches = from Users in people
where Users.User_Rights == "Admin" ||
Users.User_Rights == "Users" ||
Users.User_Rights == "Limited"
select Users;
Certamente isso é mais 'prolixo' e uma dor de escrever, mas funciona da mesma forma.
Portanto, se tivéssemos algum método utilitário que facilitasse a criação desse tipo de expressão LINQ, estaríamos nos negócios.
com um método utilitário no lugar, você pode escrever algo como isto:
var matches = ctx.People.Where(
BuildOrExpression<People, string>(
p => p.User_Rights, names
)
);
Isso cria uma expressão que tem o mesmo efeito que:
var matches = from p in ctx.People
where names.Contains(p.User_Rights)
select p;
Mas o que é mais importante, na verdade, funciona no .NET 3.5 SP1.
Aqui está a função de encanamento que torna isso possível:
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);
}
Não vou tentar explicar esse método, exceto dizer que ele basicamente constrói uma expressão de predicado para todos os valores usando o valueSelector (ou seja, p => p.User_Rights) e ORs esses predicados juntos para criar uma expressão para o completo predicado
Exemplo real:
var trackList = Model.TrackingHistory.GroupBy(x => x.ShipmentStatusId).Select(x => x.Last()).Reverse();
List<int> done_step1 = new List<int>() {2,3,4,5,6,7,8,9,10,11,14,18,21,22,23,24,25,26 };
bool isExists = trackList.Where(x => done_step1.Contains(x.ShipmentStatusId.Value)).FirstOrDefault() != null;
Seriamente? Vocês nunca usaram
where (t.MyTableId == 1 || t.MyTableId == 2 || t.MyTableId == 3)
Checks = NumValues * NumRows
. Como esse é um cálculo do tipo M * N, se um for pequeno, o tempo para executar cada verificação necessária também será pequeno. Eu adicionei a restrição para que o cjm30305 soubesse como configurar um ambiente de teste onde mostrasse por que sua solução é ruim.
where new[] { 1, 2, 3 }.Contains(x)
faz menos comparações, então where (x == 1 || x == 2 || x == 3)
?