非常に奇妙なデバッグ経験がありました。これは少し恥ずかしいですが、それは私の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();
}
をその関数への2回目の呼び出し実際にはwhere句の代わりに2つのwhere句を持つlinqクエリを生成します。だから、追加のwhere節が結果の量を増やしているようです。
さらに奇妙なことですが、LoadUserBySearchString関数は、実際にデータベースを使ってテストするとうまく動作します。単体テストを実行すると、この奇妙な動作しか示されません。
私はちょうど睡眠(または延長された休暇)が必要だと思います。もし誰かが私にこれについて少しの光を当てるのを助けてくれたら、私は自分の正気を問うことをやめ、仕事に戻ることができます。
おかげで、
エイドリアン
編集(私がこれまで行って、いくつかの回答に明確にする):私はそれがまたは句であるように見えるけど、unfortuantelyそれは簡単ではありません。 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>}
そして、これは単に、上記のように
+ 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の句であります1つの追加のwhere節があります。
ありがとう!あなたは私の一日を作りました:-) –
+1、ローカル変数を使用すると、通常はクロージャの問題を解決するのに役立ちます。 LINQでのクロージャの使用についてさらに読む:http://diditwith.net/2007/09/25/LINQClosuresMayBeHazardousToYourHealth.aspx – Lucas