LINQ to EntitiesのWhereとFirstに別々に条件を与えると並び順がおかしくなる

こんなコードを書くほうが悪いわけだけど、
var contract = entities.Contract
    .Where(c => c.User.id == user.id)
    .OrderByDescending(c => c.applied_from).ThenByDescending(c => c.created_at).ThenByDescending(c => c.id)
    .FirstOrDefault(c => c.applied_from < dtTo);  // (1)
var contract = entities.Contract
    .Where(c => c.User.id == user.id && c.applied_from < dtTo)
    .OrderByDescending(c => c.applied_from).ThenByDescending(c => c.created_at).ThenByDescending(c => c.id)
    .FirstOrDefault();   // (2)
これらはいずれも以下のSQLの結果と同じになることを期待して書いたものです。
SELECT * FROM contracts
WHERE user_id = 10 AND applied_from < '2009-12-01 00:00:00'
ORDER BY applied_from desc, created_at desc, id desc
LIMIT 1
しかし、両者の返すレコードは異なります。
OrderByDescendingで並べ替えた先頭から一件とりたいのですが、(1)の方はまれに意図したレコードと違うものが返って来ることがあります。なぜ例外がこんなに少ないのか分かりませんが、とにかく保証はできないようです。しかし、以下の(3)は(2)と同じ結果になります。
var contract = entities.Contract
    .Where(c => c.User.id == user.id)
    .OrderByDescending(c => c.applied_from).ThenByDescending(c => c.created_at).ThenByDescending(c => c.id)
    .ToArray()
    .FirstOrDefault(c => c.applied_from < dtTo);  // (3)
こういう場合、最終的にどんなSQLが実行されているのか知りたくなるわけですが、その方法がありません。
ToTraceString()で見られる未完成のSQLでは、最終的なクエリは見えません。
このへんが、Entity Frameworkが駄目なところです。いや、System.Data.SQLiteの問題か?
今回は関係ないですが、ObjectQueryを使い回しする場合には、FirstやToArrayの直前までを変数に格納して、Firstの条件部分だけを変えるという使い方をしていることがあったんですが、これではまずいですね。。。

コメントを残す