Antworten:
Sie müssen es in Bezug auf die Art und Weise, wie Sie darüber denken, auf den Kopf stellen. Anstatt "in" zu tun, um die Benutzerrechte des aktuellen Elements in einem vordefinierten Satz anwendbarer Benutzerrechte zu finden, fragen Sie einen vordefinierten Satz von Benutzerrechten, ob er den anwendbaren Wert des aktuellen Elements enthält. Dies ist genau die gleiche Art und Weise, wie Sie ein Element in einer regulären Liste in .NET finden würden.
Es gibt zwei Möglichkeiten, dies mit LINQ zu tun: Die eine verwendet die Abfragesyntax und die andere die Methodensyntax. Im Wesentlichen sind sie gleich und können je nach Ihren Vorlieben austauschbar verwendet werden:
Abfragesyntax:
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;
}
Methodensyntax:
var selected = users.Where(u => new[] { "Admin", "User", "Limited" }.Contains(u.User_Rights));
foreach(user u in selected)
{
//Do stuff on each selected user;
}
Meine persönliche Präferenz in diesem Fall könnte die Methodensyntax sein, da ich anstelle der Zuweisung der Variablen den foreach über einen anonymen Aufruf wie diesen ausführen könnte:
foreach(User u in users.Where(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
//Do stuff on each selected user;
}
Syntaktisch sieht dies komplexer aus, und Sie müssen das Konzept der Lambda-Ausdrücke oder -Delegierten verstehen, um wirklich herauszufinden, was vor sich geht. Wie Sie jedoch sehen können, wird der Code dadurch erheblich komprimiert.
Alles hängt von Ihrem Codierungsstil und Ihren Vorlieben ab - alle drei meiner Beispiele machen dasselbe etwas anders.
Eine alternative Methode verwendet nicht einmal LINQ. Sie können dieselbe Methodensyntax verwenden, indem Sie "where" durch "FindAll" ersetzen und dasselbe Ergebnis erhalten, das auch in .NET 2.0 funktioniert:
foreach(User u in users.FindAll(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
//Do stuff on each selected user;
}
Dies sollte Ihrem Zweck genügen. Es vergleicht zwei Sammlungen und prüft, ob für eine Sammlung die Werte mit denen in der anderen Sammlung übereinstimmen
fea_Features.Where(s => selectedFeatures.Contains(s.feaId))
Wenn Sie VS2008 / .net 3.5 verwenden, lesen Sie Alex James 'Tipp Nr. 8: http://blogs.msdn.com/alexj/archive/2009/03/26/tip-8-writing-where-in-style -queries-using-linq-to-entity.aspx
Verwenden Sie andernfalls einfach die Methode array.Contains (someEntity.Member).
Ich werde mich in diesem Zusammenhang für Inner Join entscheiden. Wenn ich enthält verwendet hätte, würde es 6 Mal iterieren, obwohl es nur eine Übereinstimmung gibt.
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();
Angenommen, ich habe zwei Listenobjekte.
List 1 List 2
1 12
2 7
3 8
4 98
5 9
6 10
7 6
Mit Contains wird nach jedem Element der Liste 1 in Liste 2 gesucht, was bedeutet, dass die Iteration 49 Mal erfolgt !!!
Ich habe auch versucht, mit einer SQL-IN-ähnlichen Sache zu arbeiten - Abfragen gegen ein Entitätsdatenmodell . Mein Ansatz ist ein String-Builder, um einen großen ODER-Ausdruck zu erstellen. Das ist furchtbar hässlich, aber ich fürchte, es ist der einzige Weg, den wir jetzt gehen können.
Nun gut, das sieht so aus:
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());
}
}
Arbeiten mit GUIDs in diesem Zusammenhang : Wie Sie oben sehen können, steht in den Abfragezeichenfolgenfragmenten immer das Wort "GUID" vor der GUID. Wenn Sie dies nicht hinzufügen, wird ObjectQuery<T>.Where
die folgende Ausnahme ausgelöst:
Die Argumenttypen 'Edm.Guid' und 'Edm.String' sind für diese Operation nicht kompatibel. Nahezu gleich Ausdruck, Zeile 6, Spalte 14.
Fand dies in MSDN-Foren, könnte hilfreich sein, daran zu denken.
Matthias
... freuen uns auf die nächste Version von .NET und Entity Framework, wenn alles besser wird. :) :)
Eine alternative Methode zur BenAlabaster-Antwort
Zunächst können Sie die Abfrage folgendermaßen umschreiben:
var matches = from Users in people
where Users.User_Rights == "Admin" ||
Users.User_Rights == "Users" ||
Users.User_Rights == "Limited"
select Users;
Sicherlich ist dies "wortreicher" und ein Schmerz zu schreiben, aber es funktioniert trotzdem.
Wenn wir also eine Dienstprogrammmethode hätten, die es einfach macht, diese Art von LINQ-Ausdrücken zu erstellen, wären wir im Geschäft.
Mit einer vorhandenen Dienstprogrammmethode können Sie Folgendes schreiben:
var matches = ctx.People.Where(
BuildOrExpression<People, string>(
p => p.User_Rights, names
)
);
Dadurch wird ein Ausdruck erstellt, der den gleichen Effekt hat wie:
var matches = from p in ctx.People
where names.Contains(p.User_Rights)
select p;
Aber was noch wichtiger ist, funktioniert tatsächlich gegen .NET 3.5 SP1.
Hier ist die Sanitärfunktion, die dies ermöglicht:
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);
}
Ich werde nicht versuchen, diese Methode zu erklären, außer zu sagen, dass sie im Wesentlichen einen Prädikatausdruck für alle Werte unter Verwendung des valueSelector (dh p => p.User_Rights) erstellt und diese Prädikate zusammen ODER verknüpft, um einen Ausdruck für das Ganze zu erstellen Prädikat
Echtes Beispiel:
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;
Ernsthaft? Ihr Leute habt noch nie benutzt
where (t.MyTableId == 1 || t.MyTableId == 2 || t.MyTableId == 3)
Checks = NumValues * NumRows
. Da es sich um eine Berechnung vom Typ M * N handelt, ist auch die Zeit für die Durchführung jeder erforderlichen Prüfung gering, wenn eine der beiden Berechnungen klein ist. Ich habe die Einschränkung hinzugefügt, damit cjm30305 weiß, wie eine Testumgebung eingerichtet wird, in der gezeigt wird, warum seine Lösung schlecht ist.
where new[] { 1, 2, 3 }.Contains(x)
weniger Vergleiche möglich sind where (x == 1 || x == 2 || x == 3)
?