방금 아주 이상한 디버그 경험을했습니다. 그것은 인정하기에 다소 당황 스럽지만, Linq 쿼리가 추가 Where 절을 추가 할 때 더 많은 결과를 산출한다고 믿게합니다.왜 Linq Where 절은 적은 양이 아닌 많은 결과를 산출합니까?
나는 그것이 가능하지 알고, 그래서 난 내 기분을 상하게하는 기능을 더한로에 속하는 단위 테스트 리팩토링했습니다 나는 LoadUserBySearchString 기능을 디버깅하고 주장한다
[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();
}
을 그 함수의 두 번째 호출 실제로 where 대신 하나의 절이있는 linq 쿼리를 생성합니다. 그래서 추가 where 절이 결과의 양을 늘리는 것 같습니다.
무엇이 더 이상한가요? LoadUserBySearchString 함수는 손으로 (데이터베이스의 실제 사용자와 함께) 테스트 할 때 훌륭하게 작동합니다. 단위 테스트를 실행할 때 이상한 행동 만 보여줍니다.
나는 약간의 수면 (또는 심지어 연장 된 휴가)이 필요하다고 생각한다. 누군가가이 문제에 관해 어떤 생각을 밝히도록 도와 줄 수 있다면, 나는 내 정신을 묻지 않고 일하러 돌아갈 수있다.
감사합니다,
아드리안
편집 (내가 지금까지 이동 여러 가지 응답에 명확히하기 위해) : 나는 그것이 나 절처럼 보이는 알고 있지만 unfortuantely는 그렇게 간단하지 않다. LoadUserBySearchString은 검색 문자열을 여러 문자열로 분할하고 각각에 대해 Where 절을 첨부합니다. "Skywalker"는 루크와 레이아와 일치하지만 "공주"는 레이아와 만 일치합니다.
이 "공주"검색 문자열에 대한 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>}
그리고 이것은 단지, 상기와
+ 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>}
같은 "공주 스카이 워커"검색 문자열에 대한 Linq에 절입니다 하나의 추가적인 where 절이 있습니다.
고마워요! 내 하루를 만들었습니다 :-) –
+1, 지역 변수를 사용하면 보통 클로저 문제를 푸는데 도움이됩니다. LINQ에서 클로저 사용에 대한 추가 정보 : http://diditwith.net/2007/09/25/LINQClosuresMayBeHazardousToYourHealth.aspx – Lucas