У меня только что был самый странный опыт отладки за очень долгое время. Это немного стыдно признать, но это заставило меня поверить, что мой запрос Linq дает БОЛЬШЕ результатов при добавлении дополнительного предложения Where.
Я знаю, что это невозможно, поэтому я реорганизовал свою функцию-нарушитель, а также относящийся к ней модульный тест:
[Test]
public void LoadUserBySearchString()
{
//Setup
var AllUsers = new List<User>
{
new User
{
FirstName = "Luke",
LastName = "Skywalker",
Email = "luke@jedinet.org"
},
new User
{
FirstName = "Leia",
LastName = "Skywalker",
Email = "faeryprincess@winxmail.com"
}
};
//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();
}
Я отлаживал функцию LoadUserBySearchString и утверждал, что второй вызов функции фактически создает запрос linq с двумя предложениями where вместо одного. Таким образом, кажется, что дополнительное условие where увеличивает количество результатов.
Что еще более странно, функция LoadUserBySearchString прекрасно работает, когда я тестирую ее вручную (с реальными пользователями из базы данных). Это показывает только странное поведение при запуске модульного теста.
Полагаю, мне просто нужно немного поспать (или даже продлить отпуск). Если бы кто-нибудь мог помочь мне пролить свет на это, я мог бы прекратить сомневаться в своем здравомыслии и вернуться к работе.
Спасибо
Адриан
Редактировать (чтобы уточнить несколько ответов, я дошел до сих пор) : Я знаю, что это выглядит как предложение или, но, к сожалению, не все так просто. LoadUserBySearchString разбивает строку поиска на несколько строк и присоединяет предложение Where для каждой из них. «Скайуокер» соответствует Люку и Лее, но «принцесса» - только Лее.
Это запрос Linq для строки поиска "принцесса":
+ 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>}
И это предложение Linq для строки поиска "принцесса Скайуокер"
+ 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>}
То же, что и выше, только с одним дополнительным предложением where.