.net - 我如何查詢實體框架中的空值?




entity-framework ado.net (13)

我無法評論divega的文章,但在這裡介紹的不同解決方案中,divega的解決方案產生了最好的SQL。 表現明智和長度明智。 我剛剛查看了SQL Server Profiler並查看了執行計劃(使用“SET STATISTICS PROFILE ON”)。

我想執行這樣的查詢

   var result = from entry in table
                     where entry.something == null
                     select entry;

並獲得一個IS NULL生成。

編輯:在前兩個答案後,我覺得有必要澄清,我使用實體框架,而不是LINQ到SQL。 object.Equals()方法在EF中似乎不起作用。

編輯2:上述查詢按預期工作。 它正確地生成IS NULL 。 然而我的產品代碼是

value = null;
var result = from entry in table
                         where entry.something == value
                         select entry;

並且生成的SQL是something = @p; @p = NULL something = @p; @p = NULL 。 看起來EF正確地翻譯了常量表達式,但是如果涉及一個變量,它就像正常的比較一樣對待它。 實際上有意義。 我會解決這個問題


var result = from entry in table    
             where entry.something == value||entry.something == null                   
              select entry;

使用它


處理空比較使用Object.Equals()而不是==

檢查這個reference


有一個適用於LINQ to Entities的稍簡單的解決方法:

var result = from entry in table
         where entry.something == value || (value == null && entry.something == null)
         select entry;

正如AZ注意到的,這適用於LINQ to Entities特殊情況x == null(即與null常量相等的比較)並將其轉換為x IS NULL。

目前我們正在考慮改變這種行為,以便在平等的兩邊都可以為空時自動引入補償比較。 但是有一些挑戰:

  1. 這可能會破壞已經取決於現有行為的代碼。
  2. 即使很少使用空參數,新翻譯也會影響現有查詢的性能。

無論如何,我們是否能夠在這方面開展工作將取決於我們客戶分配給它的相對優先級。 如果您關心此問題,我鼓勵您在我們的新功能建議網站https://data.uservoice.com上為其投票。


看起來Linq2Sql也有這個“問題”。 看起來,由於ANSI NULL是ON還是OFF,導致此行為存在一個合理的原因,但它令人驚訝,為什麼直接的“== null”實際上會如您所期望的那樣工作。


Linq-to-SQL的解決方法:

var result = from entry in table
             where entry.something.Equals(value)
             select entry;

針對Linq-to-Entities(ouch!)的解決方法:

var result = from entry in table
             where (value == null ? entry.something == null : entry.something == value)
             select entry;

這是一個令我討厭的錯誤,它幾次讓我感到困擾。 如果此錯誤也影響到您,請訪問UserVoice上錯誤報告,並讓Microsoft知道此錯誤也影響了您。

編輯: 這個錯誤正在EF 4.5中修復 ! 感謝大家提升這個bug!

為了向後兼容,它將被選中 - 您需要手動啟用設置才能使entry == value工作。 目前還沒有關於這個設置的信息。 敬請關注!

編輯2:根據EF團隊的這篇文章這個問題已經在EF6中修復了! 哇噢!

我們改變了EF6的默認行為來補償三值邏輯。

這意味著依賴於舊行為的現有代碼null != null ,但僅在與變量進行比較時)需要更改為不依賴於該行為,或將UseCSharpNullComparisonBehavior設置為false以使用舊的中斷行為。


var result = from entry in table
                     where entry.something == null
                     select entry;

上述查詢按預期工作。 它正確地生成IS NULL。 然而我的產品代碼是

var value = null;
var result = from entry in table
                         where entry.something == value
                         select entry;

並且生成的SQL是= @p; @p = NULL。 看起來EF正確地翻譯了常量表達式,但是如果涉及一個變量,它就像正常的比較一樣對待它。 實際上有意義。


從Entity Framework 5.0開始,您可以使用以下代碼來解決您的問題:

public abstract class YourContext : DbContext
{
  public YourContext()
  {
    (this as IObjectContextAdapter).ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior = true;
  }
}

這應該可以解決你的問題,因為Entity Framerwork將使用'C#''null'比較。


如果它是可以為空的類型,也許嘗試使用HasValue屬性?

var result = from entry in table
                 where !entry.something.HasValue
                 select entry;

雖然沒有任何EF在這裡測試...只是一個建議=)



就個人而言,我更喜歡:

var result = from entry in table    
             where (entry.something??0)==(value??0)                    
              select entry;

過度

var result = from entry in table
             where (value == null ? entry.something == null : entry.something == value)
             select entry;

因為它可以防止重複 - 雖然這在數學上不是確切的,但它適合大多數情況。


不幸的是在實體框架5 DbContext中問題仍然沒有解決。

我使用了這種解決方法(適用於MSSQL 2012,但ANSI NULLS設置可能會在任何未來的MSSQL版本中被棄用)。

public class Context : DbContext
{

    public Context()
        : base("name=Context")
    {
        this.Database.Connection.StateChange += Connection_StateChange;
    }

    void Connection_StateChange(object sender, System.Data.StateChangeEventArgs e)
    {
        // Set ANSI_NULLS OFF when any connection is opened. This is needed because of a bug in Entity Framework
        // that is not fixed in EF 5 when using DbContext.
        if (e.CurrentState == System.Data.ConnectionState.Open)
        {
            var connection = (System.Data.Common.DbConnection)sender;
            using (var cmd = connection.CreateCommand())
            {
                cmd.CommandText = "SET ANSI_NULLS OFF";
                cmd.ExecuteNonQuery();
            }
        }
    }
}

應該指出,這是一個骯髒的解決方法,但它可以非常快速地執行並適用於所有查詢。


我對實體框架的體驗一直不如恆星。 首先,你必須從EF基類繼承,所以請告訴POCO。 你的設計必須圍繞EF進行。 有了LinqtoSQL,我可以使用現有的業務對象。 此外,沒有延遲加載,你必須自己實現。 有一些工作要使用POCOs和延遲加載,但它們存在恕我直言,因為EF尚未準備好。 我打算在4.0之後回來





.net entity-framework ado.net