Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЛР7.doc
Скачиваний:
16
Добавлен:
05.05.2019
Размер:
851.46 Кб
Скачать

Табличные функции

Перейдем к разбору механизма функционирования табличных функций. Структура и механизм функционирования табличных .NET-функций довольно сложен, поэтому остановимся на этом вопросе подробнее (листинг 4.13).

Листинг 4.13

using System;

using System.Data;

using System.Data.Sql;

using System.Data.SqlClient;

using System.Data.SqlTypes;

using System.Collections;

using Microsoft.SqlServer.Server;

// структура будет представлять строку результирующего набора

public struct rcd

{

public Int32 id;

public String name;

}

//----------------------------------------------------------

public partial class UserDefinedFunctions

{

// атрибут метода TableFunc

[SqlFunction(DataAccess = DataAccessKind.Read,

FillRowMethodName = "FillRow")]

public static IEnumerable TableFunc(SqlInt32 id)

{

// создаем массив результирующих строк

rcd[] rcd1 = new rcd[1];

SqlDataReader rd = null;

SqlConnection conn = new SqlConnection("context connection=true");

// открываем соединение

conn.Open();

SqlCommand cmd = new SqlCommand();

// команда будет выполняться на открытом соединении

cmd.Connection = conn;

cmd.CommandType = System.Data.CommandType.Text;

// выполняемый запрос

cmd.CommandText =

"select id,name from dbo.students where id>" +

(String)id.ToSqlString();

// осуществляем запрос

rd = cmd.ExecuteReader();

Int32 nc = 1;

// теперь результат запроса передается из объекта rd в массив rcd1

// размерность массива динамически увеличиваем

while (rd.Read())

{

rcd1[nc - 1].id = (Int32)rd[0];

rcd1[nc - 1].name = (String)rd[1];

nc++;

// добавляем элемент массива

Array.Resize(ref rcd1, nc);

}

Array.Resize(ref rcd1, nc - 1);

// закрываем соединение

conn.Close();

// возвращаем сформированный массив

return rcd1;

}

// автоматически вызываемый метод

// формирует значение столбцов строки, посылаемой клиенту

public static void FillRow(Object obj, out SqlInt32 id,

out SqlString s)

{

// передаваемый объект obj - это объект из массива rcd1

rcd ss = (rcd)obj;

id = new SqlInt32(ss.id);

s = new SqlString(ss.name);

}

};

В листинге 4.13 представлен полный пример, реализующий табличную функцию на языке С#. Прежде всего обратите внимание на то, что в тексте модуля имеются две функции (два метода). Однако лишь один метод TableFunc объявляется непосредственно как табличная функция (листинг 4.14). Вторая функция FillRow играет вспомогательную роль. Она формирует строку, которая будет отправлена приложению, вызвавшему функцию TableFunc.

Обратим внимание на атрибут, который определяется для метода TableFunc. Свойство DataAccess мы уже знаем. Но в листинге есть еще одно свойство — FillRowMethodName. Оно требуется в определении табличных функций и указывает на второй метод, необходимый для заполнения строк результирующего набора.

Еще один важный момент — тип IEnumerable, который мы определили для метода TableFunc. Это означает, что метод будет возвращать некоторый перечислимый набор данных. Типичным примером такого набора данных является массив. Именно посредством массива мы и возвращаем результирующий набор строк.

Следующим важным моментом является выполнение запроса

rd = cmd.ExecuteReader().

Результат запроса оказывается в объекте rd. И вот теперь этот результат запроса мы помещаем в массив rcd1 (см. листинг 4.13, цикл while). Массив состоит из экземпляров структуры red, которая и призвана представлять таблицу, которую мы будем формировать на основе запроса. Именно этот массив будет возвращен нами из метода TableFunc при помощи команды return.

Рассмотрим функцию FillRow. Функция имеет три параметра. Причем два последних параметра являются выходными. Именно они и возвращают значение полей результирующей таблицы. Первый параметр представляет объект базового класса object. Этот объект является элементом массива, который возвращает метод TableFunc. Соответственно строка

rсd ss = (rсd)obj

осуществляет явное преобразование типов, после чего мы получаем доступ к элементам структуры rсd, другими словами, к строке результирующего набора. Функция FillRow будет вызываться столько раз, сколько элементов в массиве или, что то же самое, сколько строк в результирующем наборе

Листинг 4.14

--удаляем функцию и сборку

drop function dbo. myfunc3

drop assembly sql3

go

--регистрируем сборку

create assembly sql3

from 'F:\sql\sql3\sql3\bin\Release\sql3.dll'

with permission_set = safe

go

--создаем табличную функцию, ссылающуюся на метод TableFunc

create function myfunc3

(

@id int

)

returns table (id int,name nchar(15))

as

external name sql3.UserDefinedFunctions.TableFunc

После создания и трансляции сборки выполняем команды из листинга 4.14. Теперь можно пользоваться полученной функцией, например, так:

select * from dbo.myfunc3(10)