Risposte:
Devi capovolgerlo in termini di modo in cui ci stai pensando. Invece di fare "in" per trovare i diritti utente dell'articolo corrente in un set predefinito di diritti utente applicabili, stai chiedendo a un set predefinito di diritti utente se contiene il valore applicabile dell'articolo corrente. Questo è esattamente lo stesso modo in cui troveresti un elemento in un normale elenco in .NET.
Esistono due modi per eseguire questa operazione utilizzando LINQ, uno utilizza la sintassi della query e l'altro utilizza la sintassi del metodo. Essenzialmente, sono uguali e potrebbero essere usati in modo intercambiabile a seconda delle tue preferenze:
Sintassi della query:
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;
}
Sintassi del metodo:
var selected = users.Where(u => new[] { "Admin", "User", "Limited" }.Contains(u.User_Rights));
foreach(user u in selected)
{
//Do stuff on each selected user;
}
La mia preferenza personale in questo caso potrebbe essere la sintassi del metodo perché invece di assegnare la variabile, potrei fare la foreach su una chiamata anonima come questa:
foreach(User u in users.Where(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
//Do stuff on each selected user;
}
Sintatticamente questo sembra più complesso, e devi capire il concetto di espressioni lambda o delegati per capire davvero cosa sta succedendo, ma come puoi vedere, questo condensa il codice un discreto importo.
Tutto dipende dal tuo stile di codifica e dalle tue preferenze: tutti e tre i miei esempi fanno la stessa cosa in modo leggermente diverso.
Un modo alternativo non usa nemmeno LINQ, puoi usare la stessa sintassi del metodo sostituendo "where" con "FindAll" e ottenere lo stesso risultato, che funzionerà anche in .NET 2.0:
foreach(User u in users.FindAll(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
//Do stuff on each selected user;
}
Questo dovrebbe bastare al tuo scopo. Confronta due raccolte e verifica se una raccolta ha i valori corrispondenti a quelli dell'altra raccolta
fea_Features.Where(s => selectedFeatures.Contains(s.feaId))
Se stai usando VS2008 / .net 3.5, vedi il consiglio n. 8 di Alex James: http://blogs.msdn.com/alexj/archive/2009/03/26/tip-8-writing-where-in-style -queries-con-LINQ-to-entities.aspx
Altrimenti basta usare il metodo array.Contains (someEntity.Member).
Proverò Inner Join in questo contesto. Se avessi usato contiene, ripeterebbe 6 volte nonostante il fatto che ci sia una sola corrispondenza.
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();
Supponiamo di avere due oggetti elenco.
List 1 List 2
1 12
2 7
3 8
4 98
5 9
6 10
7 6
Usando Contiene, cercherà ogni elemento della Lista 1 nella Lista 2, il che significa che l'iterazione avverrà 49 volte !!!
Ho anche provato a lavorare con una cosa simile a SQL-IN: interrogare un Entity Data Model . Il mio approccio è un generatore di stringhe per comporre una grande espressione OR. È terribilmente brutto, ma temo che sia l'unico modo per andare adesso.
Bene, sembra così:
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());
}
}
Lavorare con i GUID in questo contesto : come puoi vedere sopra, c'è sempre la parola "GUID" prima del GUID se stesso nei frammenti della stringa di query. Se non lo aggiungi, ObjectQuery<T>.Where
genera la seguente eccezione:
I tipi di argomento 'Edm.Guid' e 'Edm.String' non sono compatibili con questa operazione., Quasi uguale a espressione, riga 6, colonna 14.
Trovato questo nei forum MSDN, potrebbe essere utile tenere a mente.
Matthias
... in attesa della prossima versione di .NET ed Entity Framework, quando tutto andrà meglio. :)
Un metodo alternativo alla risposta di BenAlabaster
Prima di tutto, puoi riscrivere la query in questo modo:
var matches = from Users in people
where Users.User_Rights == "Admin" ||
Users.User_Rights == "Users" ||
Users.User_Rights == "Limited"
select Users;
Certamente questo è più "prolisso" e un dolore da scrivere ma funziona lo stesso.
Quindi, se avessimo un metodo di utilità che facilitasse la creazione di questo tipo di espressioni LINQ, saremmo in affari.
con un metodo di utilità in atto puoi scrivere qualcosa del genere:
var matches = ctx.People.Where(
BuildOrExpression<People, string>(
p => p.User_Rights, names
)
);
Questo crea un'espressione che ha lo stesso effetto di:
var matches = from p in ctx.People
where names.Contains(p.User_Rights)
select p;
Ma cosa più importante in realtà funziona con .NET 3.5 SP1.
Ecco la funzione idraulica che lo rende possibile:
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);
}
Non proverò a spiegare questo metodo, oltre a dire che essenzialmente crea un'espressione predicata per tutti i valori usando valueSelector (cioè p => p.User_Rights) e OR quei predicati insieme per creare un'espressione per il completo predicato
Vero esempio:
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;
Sul serio? Non avete mai usato
where (t.MyTableId == 1 || t.MyTableId == 2 || t.MyTableId == 3)
Checks = NumValues * NumRows
. Poiché si tratta di un calcolo del tipo M * N, se uno dei due è piccolo, anche il tempo per eseguire ciascun controllo richiesto sarà ridotto. Ho aggiunto il vincolo in modo che cjm30305 sappia come impostare un ambiente di test in cui mostrare perché la sua soluzione è scadente.
where new[] { 1, 2, 3 }.Contains(x)
fa meno confronti allora where (x == 1 || x == 2 || x == 3)
?