#entity-framework #entity-framework-4 #linq-to-entities #entity
#entity-framework #entity-framework-4 #linq-to-entities #сущность
Вопрос:
Я заметил, что когда Entity Framework генерирует метод для хранимой процедуры (импорт функции), он проверяет, равен ли параметр null, и принимает решение, подобное этому:
if (contactID.HasValue)
{
contactIDParameter = new ObjectParameter("contactID", contactID);
}
else
{
contactIDParameter = new ObjectParameter("contactID", typeof(global::System.Int32));
}
Я не понимаю, что он пытается сделать, передавая тип параметра в качестве параметра, когда параметр равен null? Как именно выполняется хранимая процедура / функция в этом случае?
Я сам провел тестирование с помощью SQL Profiler и заметил, что когда я намеренно передаю null в качестве параметра (вызывая что-то вроде context.MyProcedure(null) ), null просто передается в качестве параметра хранимой процедуре SQL server.
Хотелось бы получить некоторые разъяснения по этому поведению.
Ответ №1:
Меня заинтересовал этот вопрос, поэтому я провел некоторое расследование.
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, потому что вы не можете просто передать null — это вызовет исключение. PopulateFunctionEntityCommandParameters
Использует информацию о типе для создания корректного DbParameter
для вызова хранимой процедуры. Значение этого параметра равно DBNull.Value
.
Так что вам не придется иметь с этим дело. Это просто инфраструктура.
Ответ №2:
Когда вы просматриваете код класса ObjectParameter
constructors
public ObjectParameter (string name, object value)
public ObjectParameter (string name, Type type)
Вы можете видеть, что ObjectParameter
содержит 3 важных закрытых поля:
_name
(имя параметра, не нулевое и неизменяемое), _type
(тип CLR параметра, не нулевой и неизменяемый), _value
(значение параметра, может быть изменено и обнуляется)
При использовании первого конструктора все эти поля инициализируются. Во втором конструкторе _value
поле оставлено равным null
.
В ExecuteFunction
EF используется частный метод CreateEntityCommandForFunctionImport
, который вызывает другой, еще более глубокий частный метод PopulateFunctionImportEntityCommandParameters
, который присоединяет параметры объекта.
Внутри PopulateFunctionImportEntityCommandParameters
экземпляр EntityParameter
, который представляет параметр в EntityCommand
, будет сопоставлен со свойствами имени и значения ObjectParameter
.
Эта инструкция все объясняет:
entityParameter.Value = objectParameter.Value ?? DBNull.Value;
Мы передаем DBNull
в EF, если в качестве параметра не было указано значение.