2010-06-09 9 views
7

Tenemos un DLL de terceros que puede operar en una DataTable de información de origen y generar algunos valores útiles, y estamos tratando de conectarlo a través de SQLCLR para que se pueda llamar como un UDF con valores de tabla en SQL Server 2008.Pase la tabla como parámetro a SQLCLR TV-UDF

Llevando el concepto here un paso más allá, me gustaría programar un CLR Table-Valued Function que opere en una tabla de datos fuente de la base de datos.

Estoy bastante seguro de que entiendo lo que debe suceder en el lado T-SQL de las cosas; pero, ¿cómo debería ser la firma del método en el código .NET (C#)? ¿Cuál sería el tipo de datos del parámetro para "datos de tabla de SQL Server?"

p. Ej.

/* 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) */ 

El lat/lon -> distance thing es un ejemplo tonto que, por supuesto, debería manejarse mejor en SQL; pero espero que ilustre la intención general de table-in -> table-out a través de una UDF con valores de tabla vinculada a un ensamblado SQLCLR.

No estoy seguro de que esto sea posible; ¿Cómo sería la firma del método SQLCLRInitMethod en C#?

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

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

Si no es posible, sé que puedo usar una "conexión de contexto = true" conexión de SQL dentro del código C# para have the CLR component query for the necessary data dado las llaves correspondientes; pero eso es sensible a los cambios en el esquema DB. Así que espero que SQL agrupe todos los datos fuente y los pase a la función.

Pregunta de bonificación: suponiendo que esto funcione en absoluto, ¿también podría funcionar con más de una tabla de entrada?

+0

posible duplicado de [Pasar la tabla como parámetro en el servidor sql UDF] (http://stackoverflow.com/questions/1609115/pass-table-as-parameter-into-sql-server-udf) - La respuesta de Lukasz Lysik es la solución a su pregunta: debe usar tipos de tabla definidos por el usuario. –

+0

Correcto, debería aclarar la pregunta un poco. Estoy preguntando específicamente sobre cómo implementar el componente CLR de esto. Soy consciente de lo que debe suceder en el lado T-SQL de las cosas (o creo que lo estoy): el código t-SQL de ejemplo se está publicando para mostrar cómo supongo que esto debe funcionar en ese lado, en caso de que lo esté cometer errores allí); pero, ¿cómo debería ser la firma del método en C#? ¿Cuáles son los parámetros del método para "datos de tabla de SQL Server"? – Skeolan

+1

para probarlo, permite un objeto y devuelve su nombre de tipo :) –

Respuesta

7

Resulta que hay una lista fija de entradas válidas en una función SQLCLR, determinado por el mapping between .NET datatypes and SQL datatypes

SQL "mesa" de tipos de datos disponibles se llama explícitamente por tener ninguna asignación a través del CLR.

Ergo, no es posible pasar datos con valores de tabla INTO una función CLR con valores de tabla como parámetros del método.

Alternativas

Parece posible obtener datos tabulares en select ... for xml a través de contorsiones para alimentar en un parámetro SqlXml.

He utilizado con éxito SqlConnection conn = new SqlConnection("context connection = true"); en el código .NET para permitir que TVF consulte la base de datos DB para los datos tabulares que necesita.

2

Esta pregunta parece ser (en su mayoría) un duplicado de:

CLR Table-valued function with array argument

Como una nota rápida, en esa pregunta me recomendó: lista delimitada, XML o CLR UDT.

También existe la opción de llenar una tabla y cargar la DataTable en la función.No es recomendable utilizar una Tabla real, ya que requeriría un esfuerzo extra para hacerlo "seguro para hilos" (para no cruzar datos con otros SPID) y requeriría un proceso de limpieza adicional ya que la Función no podría hacer un LMD declaración para limpiarlo una vez que se hizo con los datos. En ciertas situaciones, tal vez se prefiera, pero probablemente no para este caso en particular. Afortunadamente, las tablas temporales son accesibles dentro de las funciones SQLCLR (como de solo lectura, pero no son accesibles en absoluto en las funciones de T-SQL). El uso de tablas temporales tendría las mismas ventajas que usar tablas permanentes, pero no las desventajas de las colisiones con otros SPID o la necesidad de limpiarlas por separado. El único requisito es que utilice la conexión de contexto ya que es la única forma de acceder a objetos basados ​​en sesión (es decir, tablas temporales).

Por lo tanto, para este caso en particular, recomendaría probar la Tabla Temp o las opciones XML.

Cuestiones relacionadas