Как использовать пользовательские функции SQL в .NET?
-
20-08-2019 - |
Вопрос
Я создал скалярную функцию в базе данных
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, я попытался сопоставить его с помощью function mapping, но у меня ничего не получилось.я не хочу делать это с помощью простой 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 будут приветствоваться.
Решение
Это звучит как правильно способ в этом случае - использовать функциональность entity framework для определения функции .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
}
}
Другие советы
Это очень похоже на приведенный выше ответ, но приведенный ниже код позволяет вам вызывать UDF с любым количеством параметров и любым типом возвращаемого значения.Это может быть полезно в качестве более общего решения.Это также не было тщательно протестировано...Я думаю, что у него будут некоторые проблемы с 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.");
}
}
}