Question

I'm trying to create a SQL Function by CRL integration, but I'm having the following error:

CREATE FUNCTION for "GetWSClient" failed because T-SQL and CLR types for return value do not match.

I'm trying to consume a WebService in my dll, then integreate it as an Assembly in SQL Server.

My C# Code is:

namespace InternalLists
{
    public class UserDefinedFunctions
    {

      [Microsoft.SqlServer.Server.SqlFunction(DataAccess = DataAccessKind.Read, Name = "WSClient", FillRowMethodName = "Fill_WSClient",
        TableDefinition = "Name nvarchar(255)")]
       public static DataSet WSClient(SqlString url, SqlString idClient)
       {
           WSInternalList.CLIENTS client = new WSInternalList.CLIENTS();
           client.Url = url.ToString();
           return client.WM_CLIENT(idClient.ToString());
       }

       public static void Fill_WSClient(object ProductObj, out SqlString Name)
       {
           DataRow row = (DataRow)ProductObj;
           Name = new SqlString(row["VWSDN_NAME"].ToString());
       }
    }
}

My SQL Code is:

CREATE FUNCTION [dbo].[GetWSClient](@url nvarchar(255), @idClient nvarchar(255))
RETURNS  TABLE (
Name nvarchar(255) NULL
)
EXTERNAL NAME [InternalLists].[InternalLists.UserDefinedFunctions].[WSClient]
GO

I have seen this answer, but I'm declaring my function as DataSet return type, and I know that my WS is returning a DataSet result.

So, what I'm doing wrong??

Was it helpful?

Solution

You are creating a CLR table-valued function. From the Documentation at http://msdn.microsoft.com/en-us/library/ms131103.aspx, here is a sample:

using System;
using System.Data.Sql;
using Microsoft.SqlServer.Server;
using System.Collections;
using System.Data.SqlTypes;
using System.Diagnostics;

public class TabularEventLog
{
    [SqlFunction(FillRowMethodName = "FillRow")]
    public static IEnumerable InitMethod(String logname)
    {
        return new EventLog(logname).Entries;
    }

    public static void FillRow(Object obj, out SqlDateTime timeWritten, out SqlChars message, out SqlChars category, out long instanceId)
    {
        EventLogEntry eventLogEntry = (EventLogEntry)obj;
        timeWritten = new SqlDateTime(eventLogEntry.TimeWritten);
        message = new SqlChars(eventLogEntry.Message);
        category = new SqlChars(eventLogEntry.Category);
        instanceId = eventLogEntry.InstanceId;
    }
}

You need to return an IEnumerable or IEnumerable<T>. The runtime will take care of enumerating over that IEnumerable, passing each enumerated object to your Fill Row method (as the first argument, Object obj in the example above) and take care of mapping that into something that can be squirted down to the client via TDS, where the client, depending on what it is, will convert it into a result set.

OTHER TIPS

A T-SQL Table data type is not the same as a DataSet data type. The UDF within the SQLCLR assembly needs to return an IEnumerable type, and DataSet does not implement IEnumerable.

You might be able to convert the function to return IListSource.GetList(), which does implement IEnumerable, something like:

return ((IListSource)client.WM_CLIENT(idClient.ToString())).GetList();

Standard caveats apply - not tested - but perhaps that will give you a push in the right direction. Blessings!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top