Как использовать пользовательские функции SQL в .NET? - PullRequest
9 голосов
/ 29 июня 2009

Я создал скалярную функцию в БД

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[fn_GetUserId_Username]
    (
    @Username varchar(32)
    )
RETURNS int
AS
    BEGIN
    DECLARE @UserId int
    SELECT @UserId = UserId FROM [User] WHERE Username = @Username
    RETURN @UserId
    END

Теперь я хочу запустить его в своем коде .NET C # или VB.NET.

Я использую Entity Framework, я пытался сопоставить его с отображением функций, но у меня ничего не вышло. я не хочу делать это с простым DbCommand, проблема в том, что я не получаю результатов (функция существует в классе Entities):

public int GetUserIdByUsername(string username)
{
    EntityConnection connection = (EntityConnection)Connection;            
    DbCommand com = connection.StoreConnection.CreateCommand();
    com.CommandText = "fn_GetUserId_Username";
    com.CommandType = CommandType.StoredProcedure;
    com.Parameters.Add(new SqlParameter("Username", username));
    if (com.Connection.State == ConnectionState.Closed) com.Connection.Open();
    try
    {
        var result = com.ExecuteScalar(); //always null
    }
    catch (Exception e)
    { 
    }
    return result;
}

Есть ли решение? Сообщения в C # или VB.NET будут приветствоваться.

Ответы [ 2 ]

17 голосов
/ 29 июня 2009

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

Попробуйте это:

public int GetUserIdByUsername(string username)
{
    EntityConnection connection = (EntityConnection)Connection;            
    DbCommand com = connection.StoreConnection.CreateCommand();
    com.CommandText = "select dbo.fn_GetUserId_Username(@Username)";
    com.CommandType = CommandType.Text;
    com.Parameters.Add(new SqlParameter("@Username", username));
    if (com.Connection.State == ConnectionState.Closed) com.Connection.Open();
    try
    {
        var result = com.ExecuteScalar(); // should properly get your value
        return (int)result;
    }
    catch (Exception e)
    {
        // either put some exception-handling code here or remove the catch 
        //   block and let the exception bubble out 
    }
}
3 голосов
/ 28 января 2015

Это очень похоже на ответ выше, но приведенный ниже код позволяет вам вызывать UDF с любым количеством параметров и любым типом возврата.Это может быть полезно в качестве более общего решения.Это также не было тщательно проверено ... Я думаю, что у него будут некоторые проблемы с varchars.

internal static T1 CallUDF<T1>(string strUDFName, params SqlParameter[] aspParameters)
{
    using (SqlConnection scnConnection = GetConnection())
    using (SqlCommand scmdCommand = new SqlCommand(strUDFName, scnConnection))
    {
        scmdCommand.CommandType = CommandType.StoredProcedure;

        scmdCommand.Parameters.Add("@ReturnValue", TypeToSqlDbType<T1>()).Direction = ParameterDirection.ReturnValue;
        scmdCommand.Parameters.AddRange(aspParameters);

        scmdCommand.ExecuteScalar();

        return (T1) scmdCommand.Parameters["@ReturnValue"].Value;
    }
}

private static SqlDbType TypeToSqlDbType<T1>()
{
    if (typeof(T1) == typeof(bool))
    {
        return SqlDbType.Bit;
    }
         .
         .
         .
    else
    {
        throw new ArgumentException("No mapping from type T1 to a SQL data type defined.");
    }
}
...