2

我注意到,當實體框架生成一個存儲過程(函數導入)的方法,它測試,看看參數爲空,並使得這樣的決定:實體框架和存儲過程,函數導入可空參數

if (contactID.HasValue) 
{ 
    contactIDParameter = new ObjectParameter("contactID", contactID); 
} 
else 
{ 
    contactIDParameter = new ObjectParameter("contactID", typeof(global::System.Int32)); 
} 

我不明白它試圖做的是通過傳遞參數的類型作爲參數,當參數爲空?在這種情況下,存儲過程/函數究竟是如何執行的?

我用SQL Profiler自己做了一個測試,並注意到當我故意傳遞null作爲參數時(通過調用類似context.MyProcedure(null)的方法),僅僅將null作爲參數傳遞給SQL服務器的存儲過程。

有關此行爲的一些澄清將不勝感激。

回答

2

我對這個問題感興趣,所以我做了一些調查。

ObjectParameter有兩個重載 - 一個用於傳遞值,另一個用於傳遞類型。如果您將null作爲參數值,則會使用第二個參數,因爲EF內部需要此參數。原因是函數導入必須用ObjectParameters調用,而不是傳遞給包裝方法的普通參數。

內部EF電話:

private EntityCommand CreateEntityCommandForFunctionImport(string functionName, out EdmFunction functionImport, params ObjectParameter[] parameters) 
{ 
    ... 
    for (int i = 0; i < parameters.Length; i++) 
    { 
     if (parameters[i] == null) 
     { 
      throw EntityUtil.InvalidOperation(Strings.ObjectContext_ExecuteFunctionCalledWithNullParameter(i)); 
     } 
    } 
    ... 
    this.PopulateFunctionEntityCommandParameters(parameters, functionImport, command); 
    return command; 
} 

正如你可以看到,即使空值必須表示爲ObjectParameter,因爲你不能簡單地通過空 - 它會拋出異常。 PopulateFunctionEntityCommandParameters使用有關該類型的信息來創建用於調用存儲過程的正確的DbParameter。該參數的值是DBNull.Value

所以你不必處理它。這只是基礎設施。

+0

非常感謝您對水晶般清晰的解釋! – user683202 2011-04-18 00:22:43

1

當你看這個類的代碼ObjectParameter構造

public ObjectParameter (string name, object value) 
public ObjectParameter (string name, Type type) 

你可以看到ObjectParameter有3個重要的私人領域:

_name(參數的名稱,而不是零和不可改變的),_type( CLR類型的參數,非空且不可更改),_value(參數的值,可以更改且爲空)

當第一個結構uctor被使用,這些字段全部被初始化。對於第二個構造函數,_value字段留爲null

在EF的ExecuteFunction中,使用私有方法CreateEntityCommandForFunctionImport,其調用另一個甚至更深的專用方法PopulateFunctionImportEntityCommandParameters,該方法附加實體參數。

PopulateFunctionImportEntityCommandParameters裏面,表示EntityCommand中的參數的EntityParameter的實例將被映射到名稱和值的屬性ObjectParameter

該指令可以解釋這一切:

entityParameter.Value = objectParameter.Value ?? DBNull.Value; 

我們通過DBNull到EF如果沒有值被指定爲一個參數。