Como usar funções definidas pelo usuário SQL em .NET?
-
20-08-2019 - |
Pergunta
Eu criei uma função escalar no DB
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
Agora eu quero para executá-lo dentro do meu código .NET C # ou VB.NET.
Eu uso o Entity Framework, tentei mapeá-lo com mapeamento de função e eu não fez sucesso. eu não me importo de fazê-lo com simples DbCommand, o problema é que eu não obter nenhum resultado (a função existe na classe Entidades):
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;
}
Existe alguma solução? Mensagens em qualquer C # ou VB.NET será welcommed.
Solução
Parece que o direito maneira, neste caso, é usar a funcionalidade da estrutura de entidade para definir uma função .NET e mapear isso para sua UDF, mas eu acho que eu vejo por que você não' t obter o resultado que você espera quando você usa ADO.NET para fazê-lo - você está dizendo que você está chamando um procedimento armazenado, mas você está realmente chamar uma função.
Tente isto:
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
}
}
Outras dicas
Isto é muito semelhante à resposta acima, mas o código abaixo permite que você chamar uma UDF com qualquer número de parâmetros e qualquer tipo de retorno. Isto pode ser útil como uma solução mais geral. Isso também não foi testado completamente ... Eu acho que vai ter alguns problemas com varchars.
public class MyDBAccess
{
private SqlConnection sqlConnection = new SqlConnection("databaseconnectionstring");
public int GetUserIdByUsername(string username)
{
int userID = CallUDF<int>("dbo.fn_GetUserId_Username", new SqlParameter("@Username", username));
return userID;
}
internal static T1 CallUDF<T1>(string strUDFName, params SqlParameter[] aspParameters)
{
using (SqlConnection scnConnection = sqlConnection)
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 SqlDbType TypeToSqlDbType<T1>()
{
if (typeof(T1) == typeof(bool))
{
return SqlDbType.Bit;
}
else if (typeof(T1) == typeof(int))
{
return SqlDbType.Int;
}
//
// ... add more types here
//
else
{
throw new ArgumentException("No mapping from type T1 to a SQL data type defined.");
}
}
}