Ich hatte gerade die seltsamste Debug-Erfahrung in einer sehr langen Zeit. Es ist ein bisschen peinlich zuzugeben, aber es führt mich zu der Annahme, dass meine Linq-Abfrage MEHR Ergebnisse erzeugt, wenn ich eine zusätzliche Where-Klausel hinzufüge.Warum produziert meine Linq Where-Klausel mehr Ergebnisse statt weniger?
Ich weiß es nicht möglich ist, so habe ich meine säumige Funktion plus der Unit-Test, um es in dieser Zugehörigkeit Refactoring:
[Test]
public void LoadUserBySearchString()
{
//Setup
var AllUsers = new List<User>
{
new User
{
FirstName = "Luke",
LastName = "Skywalker",
Email = "[email protected]"
},
new User
{
FirstName = "Leia",
LastName = "Skywalker",
Email = "[email protected]"
}
};
//Execution
List<User> SearchResults = LoadUserBySearchString("princess", AllUsers.AsQueryable());
List<User> SearchResults2 = LoadUserBySearchString("princess Skywalker", AllUsers.AsQueryable());
//Assertion
Assert.AreEqual(1, SearchResults.Count); //test passed!
Assert.AreEqual(1, SearchResults2.Count); //test failed! got 2 instead of 1 User???
}
//search CustID, fname, lname, email for substring(s)
public List<User> LoadUserBySearchString(string SearchString, IQueryable<User> AllUsers)
{
IQueryable<User> Result = AllUsers;
//split into substrings and apply each substring as additional search criterium
foreach (string SubString in Regex.Split(SearchString, " "))
{
int SubStringAsInteger = -1;
if (SubString.IsInteger())
{
SubStringAsInteger = Convert.ToInt32(SubString);
}
if (SubString != null && SubString.Length > 0)
{
Result = Result.Where(c => (c.FirstName.Contains(SubString)
|| c.LastName.Contains(SubString)
|| c.Email.Contains(SubString)
|| (c.ID == SubStringAsInteger)
));
}
}
return Result.ToList();
}
ich die LoadUserBySearchString Funktion ausgetestet haben und behauptet, dass der zweite Aufruf der Funktion erzeugt tatsächlich eine linq-Abfrage mit zwei where-Klauseln anstelle von eins. So scheint es, dass die zusätzliche where-Klausel die Anzahl der Ergebnisse erhöht.
Was noch seltsamer ist, funktioniert die LoadUserBySearchString-Funktion gut, wenn ich es manuell testen (mit echten Benutzern aus der Datenbank). Es zeigt nur dieses seltsame Verhalten beim Ausführen des Komponententests.
Ich denke, ich brauche nur etwas Schlaf (oder sogar einen längeren Urlaub). Wenn irgendjemand mir helfen könnte, etwas Licht in diese Sache zu bringen, könnte ich aufhören, meine geistige Gesundheit in Frage zu stellen und wieder an die Arbeit gehen.
Danke,
Adrian
Edit (auf mehrere Antworten zu klären, ich so weit gehen): Ich weiß, es sieht aus wie es die oder Klausel, aber Unfortuantely ist es nicht so einfach. LoadUserBySearchString teilt die Suchzeichenfolge in mehrere Zeichenfolgen und fügt für jede von ihnen eine Where-Klausel an. "Skywalker" passt zu Luke und Leia, aber "Princess" passt nur zu Leia.
Dies ist die Linq-Abfrage für den Suchbegriff „Prinzessin“:
+ Result {System.Collections.Generic.List`1[TestProject.Models.User].Where(c => (((c.FirstName.Contains(value(TestProject.Controllers.SearchController+<>c__DisplayClass1).SubString) || c.LastName.Contains(value(TestProject.Controllers.SearchController+<>c__DisplayClass1).SubString)) || c.Email.Contains(value(TestProject.Controllers.SearchController+<>c__DisplayClass1).SubString)) || (c.ID = value(TestProject.Controllers.SearchController+<>c__DisplayClass3).SubStringAsInteger)))} System.Linq.IQueryable<TestProject.Models.User> {System.Linq.EnumerableQuery<TestProject.Models.User>}
Und das ist die Linq-Klausel für den Suchtext „Prinzessin Skywalker“
+ Result {System.Collections.Generic.List`1[TestProject.Models.User].Where(c => (((c.FirstName.Contains(value(TestProject.Controllers.SearchController+<>c__DisplayClass1).SubString) || c.LastName.Contains(value(TestProject.Controllers.SearchController+<>c__DisplayClass1).SubString)) || c.Email.Contains(value(TestProject.Controllers.SearchController+<>c__DisplayClass1).SubString)) || (c.ID = value(TestProject.Controllers.SearchController+<>c__DisplayClass3).SubStringAsInteger))).Where(c => (((c.FirstName.Contains(value(TestProject.Controllers.SearchController+<>c__DisplayClass1).SubString) || c.LastName.Contains(value(TestProject.Controllers.SearchController+<>c__DisplayClass1).SubString)) || c.Email.Contains(value(TestProject.Controllers.SearchController+<>c__DisplayClass1).SubString)) || (c.ID = value(TestProject.Controllers.SearchController+<>c__DisplayClass3).SubStringAsInteger)))} System.Linq.IQueryable<TestProject.Models.User> {System.Linq.EnumerableQuery<TestProject.Models.User>}
Wie oben, nur mit einer zusätzlichen where-Klausel.
Vielen Dank! Du hast meinen Tag gemacht :-) –
+1, die Verwendung einer lokalen Variable hilft normalerweise, Schließungsprobleme zu lösen. Weitere Informationen über die Verwendung von Verschlüssen in LINQ: http://diditwith.net/2007/09/25/LINQClosuresMayBeHazardousToYourHealth.aspx – Lucas