Использование параметров для элемента управления ObjectDataSource

Visual Studio 2010

Обновлен: Ноябрь 2007

Элемент управления ObjectDataSource вызывает методы бизнес-объекта на основе имени метода, определенного в свойстве SelectMethod, InsertMethod, UpdateMethod или DeleteMethod, а также имен параметров, которые составляют подписи методов бизнес-объекта. При создании методов в бизнес-объекте необходимо убедиться, что имена параметров и типы, принятые методом бизнес-объекта, соответствуют именам параметров и типам, которые были переданы элементом управления ObjectDataSource. (Порядок параметров не имеет значения.)

Как и все элементы управления источников данных, элемент управления ObjectDataSource принимает входные параметры во время выполнения и управляет ими в коллекции параметров. Для каждой операции данных существует связанная коллекция параметров. Для операций выбора можно использовать коллекцию SelectParameters; для обновлений можно использовать коллекцию UpdateParameters; и так далее.

Для каждого параметра можно задать имя, тип, направление и значение по умолчанию. Для параметров, которые получают значения от конкретного объекта, например, от элемента управления, переменной сеанса или профиля пользователя, необходимо задать дополнительные свойства. Например, для объекта ControlParameter необходимо задать свойство ControlID, чтобы определить элемент управления, который примет значение параметра, и задать свойство PropertyName, чтобы определить свойство, содержащее значение параметра. Дополнительные сведения см. в разделе Использование параметров с элементами управления источников данных.

В следующем примере кода демонстрируется метод выбора, который может быть вызван элементом управления ObjectDataSource. Метод принимает параметр и выбирает одну запись из источника данных.

[DataObjectMethod(DataObjectMethodType.Select)]
public static DataTable GetEmployee(int EmployeeID)
{
  if (!_initialized) { Initialize(); }

  SqlConnection conn = new SqlConnection(_connectionString);
  SqlDataAdapter da  = 
    new SqlDataAdapter("SELECT EmployeeID, LastName, FirstName, Address, City, Region, PostalCode FROM Employees WHERE EmployeeID = @EmployeeID", conn); 
  da.SelectCommand.Parameters.Add("@EmployeeID", SqlDbType.Int).Value = EmployeeID;

  DataSet ds =  new DataSet(); 

  try
  {
    conn.Open();
    da.Fill(ds, "Employees");
  }
  catch (SqlException e)
  {
    // Handle exception.
  }
  finally
  {
    conn.Close();
  }

  if (ds.Tables["Employees"] != null)
    return ds.Tables["Employees"];

  return null;
}


Элемент управления ObjectDataSource определяет метод, который будет выполнять вызов операций вставки, обновления и удаления, на основе коллекций InsertParameters, UpdateParameters и DeleteParameters соответственно. Кроме того, элемент управления ObjectDataSource автоматически создает параметры на основе значений, переданных элементом управления привязки данных, например, элементом управления GridView или FormView, который поддерживает автоматические операции обновления, вставки и удаления. Дополнительные сведения см. в разделе Создание параметров для полей, привязанных к данным, элементом управления источником данных.

В следующем примере кода демонстрируется метод, который может вызываться элементом управления ObjectDataSource. Метод выполняет обновление информации о сотрудниках в базе данных «Борей».

[DataObjectMethod(DataObjectMethodType.Update)]
public static bool UpdateEmployee(int EmployeeID, string FirstName, string LastName, 
                                  string Address, string City, string Region, string PostalCode)
{
  if (String.IsNullOrEmpty(FirstName))
    throw new ArgumentException("FirstName cannot be null or an empty string.");
  if (String.IsNullOrEmpty(LastName))
    throw new ArgumentException("LastName cannot be null or an empty string.");

  if (Address    == null) { Address    = String.Empty; }
  if (City       == null) { City       = String.Empty; }
  if (Region     == null) { Region     = String.Empty; }
  if (PostalCode == null) { PostalCode = String.Empty; }

  if (!_initialized) { Initialize(); }

  SqlConnection conn = new SqlConnection(_connectionString);
  SqlCommand    cmd  = new SqlCommand("UPDATE Employees " + 
                                      "  SET FirstName=@FirstName, LastName=@LastName, " + 
                                      "  Address=@Address, City=@City, Region=@Region, " +
                                      "  PostalCode=@PostalCode " +
                                      "  WHERE EmployeeID=@EmployeeID", conn);  

  cmd.Parameters.Add("@FirstName",  SqlDbType.VarChar, 10).Value = FirstName;
  cmd.Parameters.Add("@LastName",   SqlDbType.VarChar, 20).Value = LastName;
  cmd.Parameters.Add("@Address",    SqlDbType.VarChar, 60).Value = Address;
  cmd.Parameters.Add("@City",       SqlDbType.VarChar, 15).Value = City;
  cmd.Parameters.Add("@Region",     SqlDbType.VarChar, 15).Value = Region;
  cmd.Parameters.Add("@PostalCode", SqlDbType.VarChar, 10).Value = PostalCode;
  cmd.Parameters.Add("@EmployeeID", SqlDbType.Int).Value = EmployeeID;

  try
  {
    conn.Open();

    if (cmd.ExecuteNonQuery() == 0)
      return false;
  }
  catch (SqlException e)
  {
    // Handle exception.
  }
  finally
  {
    conn.Close();
  }

  return true;
}


Данный пример предполагает, что свойству ConflictDetection элемента управления ObjectDataSource присвоено значение OverwriteChanges. Если свойству ConflictDetection присвоено значение CompareAllValues, метод бизнес-объекта должен принять параметры для исходных значений полей данных. Можно отличать параметры для текущих и исходных значений при помощи свойства OldValuesParameterFormatString. Определяется свойство OldValuesParameterFormatString для строкового выражения, которое используется для форматирования имен параметров исходных значений, где символы {0} представляют имя поля. Например, если свойству OldValuesParameterFormatString присвоено значение original_{0}, текущее значение поля с именем «FirstName» должно быть передано в параметр с именем «FirstName», а исходное значение для поля передается в параметр с именем «original_FirstName».

Помимо указания объектов SelectParameters для метода Select бизнес-объекта, можно также включать параметры для сортировки и разбивки по страницам. Это дает возможность сортировать данные в объекте источника данных, а также ограничивать результаты, возвращаемые объектом источника данных, запрошенной страницей данных.

Определение параметра сортировки

Можно задать параметр сортировки для метода Select бизнес-объекта с помощью свойства SortParameterName элемента управления ObjectDataSource. Свойство SortParameterName определяет имя параметра, используемого для передачи имен столбцов сортировки в метод бизнес-объекта. Данный параметр относится к строковому типу.

Определенные элементы управления привязки данных, например, элемент управления GridView могут автоматически передавать параметры сортировки элементу управления ObjectDataSource. В случае, когда элемент управления привязки данных, который поддерживает сортировку, связан с элементом управления ObjectDataSource, элемент управления привязки данных передает выражение сортировки, которое определяет столбцы данных, которые будут использоваться при сортировке результатов. Например, элемент управления GridView передает значения сортировки в свое свойство SortExpression. Элемент управления ObjectDataSource устанавливает значение параметра, определенного свойством SortParameterName на основе переданного ему выражения сортировки. Выражением сортировки можно задавать более одного столбца; в этом случае имена столбцов разделяются запятыми. Чтобы задать сортировку по убыванию, выражение сортировки может включать имена столбцов сортировки, за которыми следует модификатор DESC. Например, выражение сортировки, которое определяет столбцы «LastName» и «FirstName» как столбцы для использования при сортировке, должно выглядеть следующим образом: «LastName, FirstName» для сортировки по возрастанию и «LastName, FirstName DESC» для сортировки по убыванию.

Определение параметров разбивки по страницам

Можно указать дополнительные параметры для метода Select, которые указывают возвращаемую страницу данных. Элемент управления ObjectDataSource поддерживает два свойства, которые определяют параметры разбивки по страницам:

  • Свойство StartRowIndexParameterName определяет имя параметра в методе выборки бизнес-объекта, используемого для указания начальной строки страницы данных.

  • Свойство MaximumRowsParameterName определяет имя параметра в методе выборки бизнес-объекта, используемого для указания числа строк на странице данных.

Оба параметра, определенные свойствами StartRowIndexParameterName иMaximumRowsParameterName, относятся к типу Int32.

Следующий пример кода демонстрирует элемент управления ObjectDataSource, настроенный на передачу параметров сортировки и разбивки по страницам в метод Select указанного бизнес-объекта:

<asp:ObjectDataSource 
  ID="EmployeesObjectDataSource" 
  runat="server" 
  TypeName="Samples.AspNet.Controls.NorthwindEmployee" 
  SortParameterName="SortColumns"
  EnablePaging="true"
  StartRowIndexParameterName="StartRecord"
  MaximumRowsParameterName="MaxRecords" 
  SelectMethod="GetAllEmployees" >
</asp:ObjectDataSource>


Следующий пример кода демонстрирует метод Select бизнес-объекта, вызов которого показан в предыдущем примере. Метод бизнес-объекта возвращает страницу данных из базы данных «Борей», отсортированных в заданном порядке.

public static void Initialize()
{
  // Initialize data source. Use "Northwind" connection string from configuration.

  if (ConfigurationManager.ConnectionStrings["Northwind"] == null ||
      ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString.Trim() == "")
  {
    throw new Exception("A connection string named 'Northwind' with a valid connection string " + 
                        "must exist in the <connectionStrings> configuration section for the application.");
  }

  _connectionString = 
    ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;

  _initialized = true;
}


// Select all employees.

[DataObjectMethod(DataObjectMethodType.Select, true)]
public static DataTable GetAllEmployees(string sortColumns, int startRecord, int maxRecords)
{
  VerifySortColumns(sortColumns);

  if (!_initialized) { Initialize(); }

  string sqlCommand = "SELECT EmployeeID, LastName, FirstName, Address, City, Region, PostalCode FROM Employees ";

  if (sortColumns.Trim() == "")
    sqlCommand += "ORDER BY EmployeeID";
  else
    sqlCommand += "ORDER BY " + sortColumns;

  SqlConnection conn = new SqlConnection(_connectionString);
  SqlDataAdapter da  = new SqlDataAdapter(sqlCommand, conn); 

  DataSet ds =  new DataSet(); 

  try
  {
    conn.Open();
    da.Fill(ds, startRecord, maxRecords, "Employees");
  }
  catch (SqlException e)
  {
    // Handle exception.
  }
  finally
  {
    conn.Close();
  }

  if (ds.Tables["Employees"] != null)
    return ds.Tables["Employees"];

  return null;
}


//////////
// Verify that only valid columns are specified in the sort expression to avoid a SQL Injection attack.

private static void VerifySortColumns(string sortColumns)
{
  if (sortColumns.ToLowerInvariant().EndsWith(" desc"))
    sortColumns = sortColumns.Substring(0, sortColumns.Length - 5);

  string[] columnNames = sortColumns.Split(',');

  foreach (string columnName in columnNames)
  {
    switch (columnName.Trim().ToLowerInvariant())
    {
      case "employeeid":
        break;
      case "lastname":
        break;
      case "firstname":
        break;
      case "":
        break;
      default:
        throw new ArgumentException("SortColumns contains an invalid column name.");
        break;
    }
  }
}


По умолчанию все параметры для методов бизнес-объекта являются входными параметрами. Если метод бизнес-объекта включает выходные параметры, которые возвращают значение элементу управления ObjectDataSource, необходимо явно задать параметр с направлением параметра, как показано в разделе Использование параметров с элементами управления источников данных.

В следующем примере кода демонстрируется элемент управления ObjectDataSource, настроенный для принятия выходного параметра, относящегося к типу Int32. Выходные параметры возвращают автоматически созданное значение первичного ключа из метода, заданного свойством InsertMethod.

<asp:ObjectDataSource 
  ID="EmployeeDetailsObjectDataSource" 
  runat="server" 
  TypeName="Samples.AspNet.Controls.NorthwindEmployee" 
  SelectMethod="GetEmployee" 
  UpdateMethod="UpdateEmployee"
  DeleteMethod="DeleteEmployee"
  InsertMethod="InsertEmployee" 
  OnInserted="EmployeeDetailsObjectDataSource_OnInserted" >
  <SelectParameters>
    <asp:Parameter Name="EmployeeID" />  
  </SelectParameters>
  <InsertParameters>
    <asp:Parameter Name="NewEmployeeID" Direction="Output" 
                   Type="Int32" DefaultValue="0" />
  </InsertParameters>
</asp:ObjectDataSource>


В следующем примере кода демонстрируется метод Insert бизнес-объекта, который возвращает значение первичного ключа как выходной параметр:

[DataObjectMethod(DataObjectMethodType.Insert)]
public static bool InsertEmployee(out int NewEmployeeID, string FirstName, string LastName, 
                                  string Address, string City, string Region, string PostalCode)
{
  if (String.IsNullOrEmpty(FirstName))
    throw new ArgumentException("FirstName cannot be null or an empty string.");
  if (String.IsNullOrEmpty(LastName))
    throw new ArgumentException("LastName cannot be null or an empty string.");

  if (Address    == null) { Address    = String.Empty; }
  if (City       == null) { City       = String.Empty; }
  if (Region     == null) { Region     = String.Empty; }
  if (PostalCode == null) { PostalCode = String.Empty; }

  if (!_initialized) { Initialize(); }

  NewEmployeeID = -1;

  SqlConnection conn = new SqlConnection(_connectionString);
  SqlCommand    cmd  = new SqlCommand("INSERT INTO Employees " + 
                                      "  (FirstName, LastName, Address, City, Region, PostalCode) " +
                                      "  Values(@FirstName, @LastName, @Address, @City, @Region, @PostalCode); " +
                                      "SELECT @EmployeeID = SCOPE_IDENTITY()", conn);  

  cmd.Parameters.Add("@FirstName",  SqlDbType.VarChar, 10).Value = FirstName;
  cmd.Parameters.Add("@LastName",   SqlDbType.VarChar, 20).Value = LastName;
  cmd.Parameters.Add("@Address",    SqlDbType.VarChar, 60).Value = Address;
  cmd.Parameters.Add("@City",       SqlDbType.VarChar, 15).Value = City;
  cmd.Parameters.Add("@Region",     SqlDbType.VarChar, 15).Value = Region;
  cmd.Parameters.Add("@PostalCode", SqlDbType.VarChar, 10).Value = PostalCode;
  SqlParameter p = cmd.Parameters.Add("@EmployeeID", SqlDbType.Int);
  p.Direction = ParameterDirection.Output;

  try
  {
    conn.Open();

    cmd.ExecuteNonQuery();

    NewEmployeeID = (int)p.Value;
  }
  catch (SqlException e)
  {
    // Handle exception.
  }
  finally
  {
    conn.Close();
  }

  return true;
}


По умолчанию все параметры для методов бизнес-объекта относятся к типу Object. Если метод бизнес-объекта включает параметры различных типов, необходимо явно задать строго типизированные параметры. Дополнительные сведения см. в разделе Использование параметров с элементами управления источников данных.

Большинство подписей метода бизнес-объекта принимает параметры типа String или Int32. Тем не менее, можно работать с методом бизнес-объекта, который принимает один или несколько параметров, относящихся к сложному или пользовательскому типу. При работе со сложными или пользовательскими типами параметров можно использовать свойство DataObjectTypeName элемента управления ObjectDataSource.

В бизнес-объекте, создание методов с длинными списками параметров, которые сопоставляют по одному значения элементов управления со значениями хранилища данных, может привести к тому, что код нельзя будет использовать многократно. Рекомендуется вместо этого помещать данные в настраиваемый класс, а затем передать экземпляр класса в качестве параметра. Таким образом, данные, которые составляют экземпляр класса, например, запись о сотруднике, могут изменяться, не требуя изменения открытых интерфейсов, предоставленных объектом источника данных. В следующем примере кода демонстрируется класс с именем NorthwindExployee, который определяет данные о сотруднике, и может быть переданы в качестве параметра бизнес-объекту.

public class NorthwindEmployee {
    public NorthwindEmployee() { }
    private int _empId;
    private string _firstName;
    public int EmpId {
      get { return _empId; }
      set { _empId = value; }
    }
    public string FirstName {
      get { return _firstName; }
      set { _firstName = value; }
    }
    // Additional code for the class.
}

Чтобы принять экземпляр описанного класса в качестве параметра, метод бизнес-объекта UpdateEmployeeInfo должен быть определен с помощью следующей подписи:

public void UpdateEmployeeInfo(NorthwindEmployee emp) {
}

Хотя нельзя присвоить значение Type параметра для имени настраиваемого класса, можно задать свойство DataObjectTypeName элемента управления ObjectDataSource для имени настраиваемого пользовательского типа, например, класса NorthwindEmployee, а затем передать экземпляр типа методу данных бизнес-объекта. Чтобы передать пользовательские объекта объекту источника данных, должны быть выполнены следующие условия:

  • Пользовательский тип должен содержать конструктор по умолчанию (конструктор, который не принимает параметров).

  • Пользовательский тип должен определять открытые свойства, имена которых соответствуют именам записей словаря, переданных элементу управления источника данных из элементов управления привязки к данным, например, GridView или DetailsView. Подробные сведения о данных словарях см. в разделе Использование параметров с элементами управления источников данных.

  • Открытые свойства объектов источников данных должны предоставлять оба метода доступа: и GET, и SET.

В следующем примере демонстрируется элемент управления ObjectDataSource, который выполняет операцию обновления путем вызова метода UpdateEmployeeInfo бизнес-объекта с именем EmployeeLogic. Элемент управления ObjectDataSource настроен для передачи экземпляра класса NorthwindEmployee в метод обновления.

<asp:objectdatasource
  runat="server"
  id="ObjectDataSource1"
  typename="EmployeeLogic"
  selectmethod="GetAllEmployees"
  updatemethod="UpdateEmployeeInfo"
  dataobjecttypename="NorthwindEmployee" />

В некоторых случаях метод бизнес-объекта содержит список параметров, который содержит несколько сложных типов параметров. В этом случае можно использовать элемент управления ObjectDataSource, но необходимо добавить параметры в элемент управления ObjectDataSource программными средствами. Для этого следует обработать событие, возникшее до выполнения операций с данными, например, Inserting, Updating или Deleting, а также задать значения в коллекции InputParameters, представленной классом ObjectDataSourceMethodEventArgs.

Показ: