Передать таблицу в качестве параметра в SQLCLR TV-UDF

У нас есть сторонняя DLL, которая может работать с DataTable исходной информации и генерировать некоторые полезные значения, и мы пытаемся подключить ее через SQLCLR, чтобы ее можно было вызывать как табличную определяемую пользователем функцию в SQL Server 2008.

Принимая концепцию здесь еще на один шаг, я хотел бы запрограммировать табличную функцию CLR, которая работает с таблицей исходных данных. из БД.

Я почти уверен, что понимаю, что должно происходить на стороне T-SQL; но как должна выглядеть сигнатура метода в коде .NET (C#)? Какой будет тип данных параметра для "табличных данных из SQL Server?"

e.g.

/* Setup */
CREATE TYPE InTableType 
AS TABLE (LocationName VARCHAR(50), Lat FLOAT, Lon FLOAT)
GO 

CREATE TYPE OutTableType 
AS TABLE (LocationName VARCHAR(50), NeighborName VARCHAR(50), Distance FLOAT)
GO

CREATE ASSEMBLY myCLRAssembly 
FROM 'D:\assemblies\myCLR_UDFs.dll' 
WITH PERMISSION_SET = EXTERNAL_ACCESS
GO
CREATE FUNCTION GetDistances(@locations InTableType)
RETURNS OutTableType
AS 
EXTERNAL NAME myCLRAssembly.GeoDistance.SQLCLRInitMethod
GO

/* Execution */

DECLARE @myTable InTableType
INSERT INTO @myTable(LocationName, Lat, Lon) VALUES('aaa', -50.0, -20.0)
INSERT INTO @myTable(LocationName, Lat, Lon) VALUES('bbb', -20.0, -50.0)
SELECT * FROM @myTable

DECLARE @myResult OutTableType
INSERT INTO @myResult
GetDistances @myTable /* SQLCLR Call: GeoDistance.SQLCLRInitMethod(@myTable) */

Широта/долгота -> расстояние - это глупый пример, который, конечно, лучше полностью обрабатывать в SQL; но я надеюсь, что это иллюстрирует общее назначение table-in -> table-out через UDF с табличным значением, привязанный к сборке SQLCLR.

Я не уверен, что это возможно; как будет выглядеть сигнатура метода SQLCLRInitMethod в C#?

public class GeoDistance
{
    [SqlFunction(FillRowMethodName = "FillRow")]
    public static IEnumerable SQLCLRInitMethod(<appropriateType> myInputData)
    {
      //...
    }

    public static void FillRow(...)
    {
      //...
    }
}

Если это невозможно, я знаю, что могу использовать SQL-соединение "context connection=true" в коде C# для запросить компонент CLR необходимые данные с учетом соответствующих ключей; но это чувствительно к изменениям в схеме БД. Поэтому я надеюсь, что SQL просто упакует все исходные данные и передаст их функции.

Дополнительный вопрос: если это вообще работает, будет ли он работать с более чем одной входной таблицей?


person Skeolan    schedule 09.06.2010    source источник
comment
возможный дубликат Передать таблицу в качестве параметра в UDF сервера sql - Ответ Лукаша Лисика - это решение вашего вопроса: вам нужно использовать пользовательские типы таблиц.   -  person OMG Ponies    schedule 09.06.2010
comment
Хорошо, я должен немного уточнить вопрос. Я конкретно спрашиваю о том, как реализовать компонент CLR. Я знаю, что должно произойти на стороне T-SQL (или думаю, что знаю - пример кода t-SQL публикуется, чтобы показать, как я предполагаю, что это должно работать на этой стороне, в случае, если я делать там ошибки); но как должна выглядеть сигнатура метода в С#? Каковы параметры метода для табличных данных из SQL Server?   -  person Skeolan    schedule 09.06.2010
comment
чтобы проверить это, разрешите объект и верните его имя типа :)   -  person Tim Mahy    schedule 09.06.2010
comment
@Tim: ХОРОШЕЕ предложение, спасибо. Я посмотрю, что произойдет с этим.   -  person Skeolan    schedule 09.06.2010
comment
@Tim: Однако никаких игральных костей: когда я выполняю приведенный выше оператор CREATE FUNCTION GetDistances, SQL Server отвечает ошибкой: «Сбой CREATE FUNCTION для GetDistances, поскольку типы T-SQL и CLR для параметров @locations не совпадают» — явно спрашивая Функция CLR для обработки ввода как объекта недостаточна для требований SQL.   -  person Skeolan    schedule 10.06.2010


Ответы (2)


Оказывается, существует фиксированный список допустимых входных данных для функции SQLCLR, определяемый доступным сопоставление между типами данных .NET и типами данных SQL

Тип данных SQL "table" явно вызывается как не имеющий отсутствия сопоставления через CLR.

Следовательно, невозможно передать табличные данные В функцию CLR с табличным значением в качестве параметров метода.

Альтернативы

Кажется возможным получить табличные данные с помощью select ... for xml искажений для подачи в SqlXml параметр.

Я успешно использовал SqlConnection conn = new SqlConnection("context connection = true"); в коде .NET, чтобы позволить TVF запрашивать у БД необходимые табличные данные.

person Skeolan    schedule 17.06.2010

Этот вопрос кажется (в основном) дубликатом:

Табличная функция CLR с аргументом-массивом

В качестве краткого примечания в этом вопросе я рекомендовал: список с разделителями, XML или CLR UDT.

Также есть возможность заполнения таблицы и загрузки из нее DataTable в функцию. Использование реальной таблицы, скорее всего, не рекомендуется, так как потребуются дополнительные усилия, чтобы сделать ее «потокобезопасной» (чтобы не пересекать данные с другими SPID), и потребуется дополнительный процесс очистки, поскольку функция не сможет выполнять DML. заявление, чтобы очистить его, как только это будет сделано с данными. В определенных ситуациях, возможно, это предпочтительнее, но, вероятно, не для этого конкретного случая. К счастью, временные таблицы доступны в функциях SQLCLR (только для чтения, но они вообще недоступны в функциях T-SQL). Использование временных таблиц будет иметь те же преимущества, что и использование постоянных таблиц, но не будет иметь недостатков, связанных с коллизиями с другими SPID или необходимостью отдельной очистки. Единственное требование состоит в том, чтобы вы использовали контекстное соединение, поскольку это единственный способ доступа к объектам на основе сеанса (например, к временным таблицам).

Поэтому для этого конкретного случая я бы рекомендовал попробовать либо временную таблицу, либо параметры XML.

person Solomon Rutzky    schedule 22.01.2011