2009-06-29 9 views
7

ho creato una funzione scalare nel DBCome utilizzare le funzioni definite dall'utente SQL in .NET?

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 farlo funzionare nel mio NET C# o VB.NET codice.

Uso Entity Framework, ho provato a mapparlo con la funzione mapping e non ho avuto successo. non mi importa di farlo con semplice DbCommand, il problema è che non ottengo risultati (la funzione esiste nella classe Entità):

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 accolti.

risposta

15

Sembra che il modo a destra in questo caso sia quello di utilizzare la funzionalità del framework entità per definire una funzione .NET e mapparla al proprio UDF, ma penso di vedere perché non si ottiene il risultato ti aspetti quando usi ADO.NET per farlo - stai dicendo che stai chiamando una stored procedure, ma in realtà stai 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 
    } 
} 
+0

Risultato: SqlException: 'fn_GetUserId_Username' non è un nome di funzione riconosciuta. – Shimmy

+3

@Shimmy: specifica il nome del proprietario, "dbo" -> "seleziona dbo.fn_GetUserId_Username (@Username)" – Sung

+0

Funzionante, grazie! – Shimmy

3

questo è molto simile alla risposta di cui sopra, ma il codice qui sotto consente di chiamare una funzione definita dall'utente con qualsiasi numero di parametri e di 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.

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."); 
    } 
} 
+0

Corretto e geniale! Thnx. –