Come utilizzare le funzioni definite dall'utente SQL in .NET?
-
20-08-2019 - |
Domanda
Ho creato una funzione scalare nel 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
Ora voglio eseguirlo nel mio codice .NET C # o VB.NET.
Uso Entity Framework, ho provato a mapparlo con il mapping delle funzioni e non ci sono riuscito. non mi interessa farlo con DbCommand semplice, il problema è che non ottengo risultati (la funzione esiste nella classe 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'è qualche soluzione? I post in C # o VB.NET saranno i benvenuti.
Soluzione
Sembra che il modo giusto in questo caso sia usare la funzionalità del framework di entità per definire una funzione .NET e mapparla sul tuo UDF, ma penso di vedere perché non t ottieni il risultato che ti aspetti quando usi ADO.NET per farlo - stai dicendo che stai chiamando una procedura memorizzata, ma stai davvero chiamando una funzione.
Prova questo:
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
}
}
Altri suggerimenti
Questo è molto simile alla risposta sopra, ma il codice seguente consente di chiamare un UDF con qualsiasi numero di parametri e qualsiasi tipo di ritorno. Questo potrebbe essere utile come soluzione più generale. Anche questo non è stato testato a fondo ... Penso che avrà qualche problema con 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.");
}
}
}