Retrieve VarBinary Data from SQL and Save the image/file - c#

When I use the SQL statement
SELECT File_Data
FROM Attachments
WHERE UserID = '12345' AND FileNames = 'testing1.jpg'
the image downloads and looks great. But if I put in a stored procedure it creates the file of testing1.jpg in my folder called C:\Testing\ but it is not writing the data in the image and it will not display correctly. Below is what I have to call the stored procedure and to write it up. Any ideas on what I am doing wrong here?
For testing purpose:
strfilename = testing1.jpg
userid = 12345
Code:
protected void LoadFiles(string strfilename, int userid)
{
string fullname = strfilename;
using (SqlConnection cn = new SqlConnection(conn_string))
{
cn.Open();
using (SqlCommand cmd = new SqlCommand("GET_ATTACHMENT", cn))
{
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter p1 = new SqlParameter("#FileName", SqlDbType.NVarChar, 255);
p1.Direction = ParameterDirection.Input;
p1.Value = strfilename;
cmd.Parameters.Add(p1);
SqlParameter p2 = new SqlParameter("#User_ID", SqlDbType.Int);
p2.Direction = ParameterDirection.Input;
p2.Value = userid;
cmd.Parameters.Add(p2);
// Tried using this statement but it did not work. //
SqlParameter pSub = new SqlParameter("#File_Data", SqlDbType.VarBinary);
pSub.Direction = ParameterDirection.ReturnValue;
cmd.Parameters.Add(pSub);
Response.Write(pSub);
// *** *** ///
using (SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
if (dr.Read())
{
// For some reason the data being returned is blank
// When I run it in SQL I get data being returned.
byte[] fileData = (byte[])dr.GetValue(0);
using (System.IO.FileStream fs = new System.IO.FileStream("C:\\Testing\\" + (fullname), System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite))
{
using (System.IO.BinaryWriter bw = new System.IO.BinaryWriter(fs))
{
bw.Write(fileData);
bw.Close();
}
}
}
dr.Close();
}
}
}
}
SQL Server stored procedure:
ALTER PROCEDURE [dbo].[GET_ATTACHMENT]
#User_ID int,
#FileName nvarchar(250)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #FileData varbinary(max)
Set #FileData = (SELECT File_Data FROM Attachments
WHERE UserID = #User_ID and
FileNames = #FileName);
SELECT #FileData
END

A few suggestions:
Set a break point at byte[] fileData = (byte[])dr.GetValue(0); to see if any data is returned before writing it to the file.
Use CommandBehavior.Default
When using CommandBehavior.SequentialAccess try using GetBytes method of SqlDataReader.
As the last resort, change your SP to return User_ID, just to check if anything is returned.

Related

How to write and consume oracle procedure in .Net Core 3.1

As I am new in Oracle and don't have much experience how to create & consume oracle procedure. Can someone please help me to fix my code below.
Procedure
CREATE OR REPLACE PROCEDURE sprocGetTableColumns (
p_table_name in user_tab_columns.table_name%type,
po_userdisp_cur OUT SYS_REFCURSOR
)
IS
BEGIN
OPEN po_userdisp_cur
FOR SELECT u.Column_Name,
u.Data_Type,
u.Nullable
FROM USER_TAB_COLUMNS u
WHERE u.table_name = p_table_name order by column_id
END sprocGetTableColumns;
C# Code
using (OracleConnection conn = new OracleConnection(templateSettingModel.ConnectionString))
{
OracleCommand objCmd = new OracleCommand();
objCmd.Connection = conn;
objCmd.CommandText = "sprocGetTableColumns";
objCmd.CommandType = CommandType.StoredProcedure;
objCmd.Parameters.Add("#tableName", OracleDbType.Varchar2).Value = 20;
objCmd.Parameters.Add("P_COLUMN_NAMES", OracleDbType.Varchar2).Direction = ParameterDirection.Output;
await conn.OpenAsync();
var dataReader = await objCmd.ExecuteReaderAsync(CommandBehavior.CloseConnection);
while (dataReader.Read())
{
var item = new TemplateFieldMappingModel
{
ColumnName = CommonHelper.To<string>(dataReader["COLUMN_NAME"]),
DataType = CommonHelper.To<string>(dataReader["DATA_TYPE"]),
IsNullable = CommonHelper.To<bool>(dataReader["IS_NULLABLE"])
};
// set the field name to be the same as the column name
item.FieldName = item.ColumnName;
if (!item.IsNullable)
item.IsRequired = true;
models.Add(item);
}
await dataReader.CloseAsync();

Fetching Single Row in PL/SQL

I am trying to create a new procedure in Oracle SQL Developer client. This procedure will fetch a single row on the basis of one condition.
My procedure code is as follow:-
create or replace PROCEDURE GETUSERKEYS
(
USERNAME IN NVARCHAR2
, STATUS OUT NUMBER
, TEMPTB OUT ClientKey%rowtype
) AS
BEGIN
SELECT * INTO TEMPTB FROM ClientKey WHERE ClientKey.USERNAME=USERNAME;
STATUS:=1;
END GETUSERKEYS;
Here is my C# code:
using (OracleConnection connection = new OracleConnection(ConnectionString))
{
using (OracleCommand cmd = new OracleCommand("GetUserKeys", connection))
{
cmd.CommandType = CommandType.StoredProcedure;
OracleParameter username = new OracleParameter();
username.OracleDbType = OracleDbType.NVarchar2;
username.ParameterName = "Username";
username.Direction = ParameterDirection.Input;
username.Value = Username;
cmd.Parameters.Add(username);
OracleParameter status = new OracleParameter();
status.OracleDbType = OracleDbType.Int32;
status.ParameterName = "Status";
status.Direction = ParameterDirection.Output;
cmd.Parameters.Add(status);
if (connection.State == ConnectionState.Open)
connection.Close();
connection.Open();
cmd.ExecuteNonQuery();
DataSet dataset = new DataSet();
OracleDataAdapter da = new OracleDataAdapter(cmd);
da.Fill(dataset);
_id = (int)cmd.Parameters["Status"].Value;
if (_id > 0)
{
if (dataset.Tables[0] != null && dataset.Tables[0].Rows.Count != 0)
{
_key = new ClientKey();
_key.ClientId = dataset.Tables[0].Rows[0]["ClientId"].ToString();
_key.ClientSecret = dataset.Tables[0].Rows[0]["ClientSecret"].ToString();
_key.ClientKeyId = int.Parse(dataset.Tables[0].Rows[0]["ClientKeyID"].ToString());
_key.Username = dataset.Tables[0].Rows[0]["Username"].ToString();
_key.CreateOn = Convert.ToDateTime(dataset.Tables[0].Rows[0]["CreateOn"].ToString());
}
}
}
}
I am not able to figure out a way to return a row from a table based on condition.
I am new to Oracle.
The problem is Oracle's C# client does not support %ROWTYPE , so you need to use a workarounds.
The simplest solution for you would be to use SYS_REFCURSOR , which maps to an ODBC ResultSet. One record is still a set. You probably don't want to go down the road of building Oracle user-defined types.
This Oracle tutorial provides a starting point for using SYS_REFCURSOR with ODP.Net.

Stored procedure output parameter returns #Value

I'm struggling with this thing for the past hour and I'm sure I'm missing something small, I have a stored procedure in SQL Server 2008 and C# code that I want to return the output parameters of my stored procedure.
SQL :
Alter Procedure dbo.GetAssessment
#UserID int,
#AssessmentName varchar(255),
#Score varchar(100) output,
#Completed varchar(10) output,
#DisplayName nvarchar(128) output,
#Result varchar(2500) output
as
begin
select #Score = A.Score, #Completed = A.Completed, #DisplayName = U.Displayname, #Result = A.Result
from Assessment A
inner join Users U
on U.UserId = A.UserID
where U.UserID = #UserId
and AssessmentName = #AssessmentName
end
GO
C#
String SScore, SName, SResult, SComp;
lblAsse.Text = Request.QueryString["AID"];
InsertAssessment(lblAsse.Text, "No", 2, "N/A", "N/A");
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["SiteSqlServer"].ConnectionString))
{
SqlParameter outScore = new SqlParameter("#Score", SqlDbType.VarChar,100){ Direction = ParameterDirection.Output };
SqlParameter outComp = new SqlParameter("#Completed", SqlDbType.VarChar,10){ Direction = ParameterDirection.Output };
SqlParameter outName = new SqlParameter("#DisplayName", SqlDbType.NVarChar, 128) { Direction = ParameterDirection.Output };
SqlParameter outResult = new SqlParameter("#Result", SqlDbType.VarChar,2500){ Direction = ParameterDirection.Output };
conn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = conn;
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandText = "GetAssessment";
cmd.Parameters.AddWithValue("#AssessmentName", lblAsse.Text);
cmd.Parameters.AddWithValue("#UserId", 2);
cmd.Parameters.Add(outScore);
cmd.Parameters.Add(outComp);
cmd.Parameters.Add(outName);
cmd.Parameters.Add(outResult);
cmd.ExecuteScalar();
SScore = outScore.ToString();
SName = outName.ToString();
SResult = outResult.ToString();
SComp = outComp.ToString();
conn.Close();
lblAsse.Text = SScore;`
Output :
#Score
What can possibly be wrong with me or my code. Please help!
You just need to read out the actual values from your output parameters:
SScore = outScore.Value;
The .ToString() doesn't return the value - it returns the name of the parameter instead...
See the MSDN documentation on SqlParameter for more details.
just need to do this.
Before getting the output parameters you must close the Data reader as
reader.Close();
and then you get output parameters as
SScore = outScore.Value.Tostring();
for more help consult this http://msdn.microsoft.com/en-us/library/ms971497
>Try this its working fine for the multiple output parameter:
using (SqlConnection sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["conStringEndicia"].ConnectionString)){
using (var sqlCmd = new SqlCommand("endicia.credentialLookup", sqlConnection))
{
sqlCmd.CommandType = System.Data.CommandType.StoredProcedure;
sqlCmd.Parameters.AddWithValue("#accountNumber", accountNumber);
SqlParameter outLogin = new SqlParameter("#login", SqlDbType.NVarChar, 100) { Direction = ParameterDirection.Output };
sqlCmd.Parameters.Add(outLogin);
SqlParameter outPassword = new SqlParameter("#password", SqlDbType.NVarChar, 100) { Direction = ParameterDirection.Output };
sqlCmd.Parameters.Add(outPassword);
sqlConnection.Open();
sqlCmd.ExecuteNonQuery();
string login, password;
login = outLogin.Value.ToString();
password = outPassword.Value.ToString();
}
}

Calling stored procedure with return value

I am trying to call a stored procedure from my C# windows application. The stored procedure is running on a local instance of SQL Server 2008. I am able to call the stored procedure but I am not able to retrieve the value back from the stored procedure. This stored procedure is supposed to return the next number in the sequence. I have done research online and all the sites I've seen have pointed to this solution working.
Stored procedure code:
ALTER procedure [dbo].[usp_GetNewSeqVal]
#SeqName nvarchar(255)
as
begin
declare #NewSeqVal int
set NOCOUNT ON
update AllSequences
set #NewSeqVal = CurrVal = CurrVal+Incr
where SeqName = #SeqName
if ##rowcount = 0 begin
print 'Sequence does not exist'
return
end
return #NewSeqVal
end
Code calling the stored procedure:
SqlConnection conn = new SqlConnection(getConnectionString());
conn.Open();
SqlCommand cmd = new SqlCommand(parameterStatement.getQuery(), conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter param = new SqlParameter();
param = cmd.Parameters.Add("#SeqName", SqlDbType.NVarChar);
param.Direction = ParameterDirection.Input;
param.Value = "SeqName";
SqlDataReader reader = cmd.ExecuteReader();
I have also tried using a DataSet to retrieve the return value with the same result. What am I missing to get
the return value from my stored procedure? If more information is needed, please let me know.
You need to add a ReturnValue-direction parameter to the command:
using (SqlConnection conn = new SqlConnection(getConnectionString()))
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = parameterStatement.getQuery();
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("SeqName", "SeqNameValue");
// #ReturnVal could be any name
var returnParameter = cmd.Parameters.Add("#ReturnVal", SqlDbType.Int);
returnParameter.Direction = ParameterDirection.ReturnValue;
conn.Open();
cmd.ExecuteNonQuery();
var result = returnParameter.Value;
}
Setting the parameter's direction to ParameterDirection.ReturnValue instructs the SqlCommand to declare it as a variable and assign the stored procedure's return value to it (exec #ReturnValue = spMyProcedure...), exactly like you would write it in SQL.
I know this is old, but i stumbled on it with Google.
If you have a return value in your stored procedure say "Return 1" - not using output parameters.
You can do the following - "#RETURN_VALUE" is silently added to every command object. NO NEED TO EXPLICITLY ADD
cmd.ExecuteNonQuery();
rtn = (int)cmd.Parameters["#RETURN_VALUE"].Value;
The version of EnterpriseLibrary on my machine had other parameters.
This was working:
SqlParameter retval = new SqlParameter("#ReturnValue", System.Data.SqlDbType.Int);
retval.Direction = System.Data.ParameterDirection.ReturnValue;
cmd.Parameters.Add(retval);
db.ExecuteNonQuery(cmd);
object o = cmd.Parameters["#ReturnValue"].Value;
I had a similar problem with the SP call returning an error that an expected parameter was not included. My code was as follows.
Stored Procedure:
#Result int OUTPUT
And C#:
SqlParameter result = cmd.Parameters.Add(new SqlParameter("#Result", DbType.Int32));
result.Direction = ParameterDirection.ReturnValue;
In troubleshooting, I realized that the stored procedure was ACTUALLY looking for a direction of "InputOutput" so the following change fixed the problem.
r
Result.Direction = ParameterDirection.InputOutput;
This is a very short sample of returning a single value from a procedure:
SQL:
CREATE PROCEDURE [dbo].[MakeDouble] #InpVal int AS BEGIN
SELECT #InpVal * 2; RETURN 0;
END
C#-code:
int inpVal = 11;
string retVal = "?";
using (var sqlCon = new SqlConnection(
"Data Source = . ; Initial Catalog = SampleDb; Integrated Security = True;"))
{
sqlCon.Open();
retVal = new SqlCommand("Exec dbo.MakeDouble " + inpVal + ";",
sqlCon).ExecuteScalar().ToString();
sqlCon.Close();
}
Debug.Print(inpVal + " * 2 = " + retVal);
//> 11 * 2 = 22
ExecuteScalar(); will work, but an output parameter would be a superior solution.
You can try using an output parameter. http://msdn.microsoft.com/en-us/library/ms378108.aspx
Or if you're using EnterpriseLibrary rather than standard ADO.NET...
Database db = DatabaseFactory.CreateDatabase();
using (DbCommand cmd = db.GetStoredProcCommand("usp_GetNewSeqVal"))
{
db.AddInParameter(cmd, "SeqName", DbType.String, "SeqNameValue");
db.AddParameter(cmd, "RetVal", DbType.Int32, ParameterDirection.ReturnValue, null, DataRowVersion.Default, null);
db.ExecuteNonQuery(cmd);
var result = (int)cmd.Parameters["RetVal"].Value;
}
I see the other one is closed. So basically here's the rough of my code. I think you are missing the string cmd comment. For example if my store procedure is call:DBO.Test. I would need to write cmd="DBO.test". Then do command type equal to store procedure, and blah blah blah
Connection.open();
String cmd="DBO.test"; //the command
Sqlcommand mycommand;

datatable not accepting the value of varbinary

the value buf has a datatype varbinary(max) and the value is 0x0000002D
string buF =
"0x" + BitConverter.ToString((byte[])dt.Rows[i]["BuF"]).Replace("-", "");
Label3.Text = buF;
i use the value to find the fileid
DataTable dt = new DataTable();
SqlConnection connection = new SqlConnection();
connection.ConnectionString = ConfigurationManager.ConnectionStrings["XYZ"].ConnectionString;
connection.Open();
SqlCommand sqlCmd = new SqlCommand("SELECT FileID FROM Backed where MachineID = #machineID AND BuF =#buF", connection);
SqlDataAdapter sqlDa = new SqlDataAdapter(sqlCmd);
sqlCmd.Parameters.AddWithValue("machineID", strID);
sqlCmd.Parameters.AddWithValue("buF", buF);
sqlDa.Fill(dt);
connection.Close();
i does not use the value of buf and i dont get the correct filid....
but if i use this with the value0x0000002D instead of buf i get the file id... why is this happening... i tried everything but nothing seems to work
i need help
The equivalent type for varbinary in C# is byte[], not string. Also, as Hogan said, AddWithValue tries to assume a data type. Instead, you can make it explicit:
sqlCmd.Parameters.Add("buF", SqlDbType.VarBinary, -1).Value = yourByteArray;
The -1 for length corresponds to varbinary(max).
It would be better to work with the binary data as byte[] and not use strings and string conversions if you don't have to. Here is a complete example that should work to demonstrate how to read and query varbinary(max) types.
static void Test(SqlConnection openConnection)
{
using(SqlCommand cmd = openConnection.CreateCommand())
{
cmd.CommandText =
#"create table #Test
(bin varbinary(max), num int);
insert into #Test (bin, num)
values (0x0000002D, 1);";
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT TOP 1 bin FROM #Test;";
byte[] binValue = (byte[])cmd.ExecuteScalar();
cmd.CommandText = "SELECT * FROM #Test WHERE bin = #bin;";
var parameter = new SqlParameter("#bin", SqlDbType.VarBinary, -1);
cmd.Parameters.Add(parameter);
parameter.Value = binValue;
DataTable table = new DataTable();
using (var reader = cmd.ExecuteReader())
{
table.Load(reader);
}
Debug.Assert(table.Rows.Count == 1);
}
}
AddWithValue makes a parameter of the type it sees. When you pass a long it uses a number, when a string it uses the ascii. Try this:
sqlCmd.Parameters.AddWithValue("buF",long.Parse(buF));

Categories