Импорт Entity Framework и функции хранимой процедуры с обнуляемыми параметрами

#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, если в качестве параметра не было указано значение.