String value in byte[] c# - c#

I have to do a query to insert a value in a SQL table. The type of the value is varbinary and I have a string to insert with an hex value in it. So I tried to use the SQL Convert Function like this:
using (SqlCommand dbCommand = new SqlCommand("INSERT INTO [Link] ([Record]) values (CONVERT(varbinary,#myrecord);", dbConn))
dbCommand.Parameters.Add("myrecord", System.Data.SqlDbType.VarBinary).Value = recordString;
but I have this Error: Failed to convert parameter value from a String to a
Byte[].
So I tried to convert my string to byte[], but all the function I found also on this site convert my string to byte changing its value, so it's not good because my string has inside the value I need to insert in the table.
Recap: I have a string with this value: "0x54000000006C00000000099W043100300030003100" how can I add it in a SQL table with a varbinary field?

Ok, i think i understand now. If you are using sql server 2008+, you can do this:
using (SqlCommand dbCommand = new SqlCommand("INSERT INTO [Link] ([Record]) values (CONVERT(varbinary,#myrecord,1);", dbConn))
dbCommand.Parameters.Add("myrecord", System.Data.SqlDbType.VarChar).Value = recordString;
Notice the 1 in CONVERT(varbinary,#myrecord,1). Btw, the example number you gave us is not a valid Hex number...
More info: Msdn

you can and should be able to do this make sure you adjust the VarBinary Size to fit your case
using(SqlCommand dbCommand = new SqlCommand("INSERT INTO [Link] ([Record]) values(#myrecord);", dbCon))
{
// Replace 8000, below, with the correct size of the field
dbCommand.Parameters.Add("#myrecord", System.Data.SqlDbType.VarChar, recordString.Length).Value = recordString;
dbCommand.ExecuteNonQuery();//wrap around a try catch if you need to catch exceptions
}

Related

How to pass byte[] from C# as string to SQL Server stored procedure and convert into varbinary(MAX)

In this project, there is a class which wraps ADO.NET for common data access like ExecuteDataReader, ExecuteScalar, etc..
When using these methods to call a stored procedure, it allows you to pass a Dictionary<string, string> of parameters (string key, string value), which are then added to the SqlCommand object as SqlParameter.
There is a case where we have to save a document in the database. The document is a byte[] and the corresponding column in the database is varbinary(MAX).
We've looked around for a solution but all that is available are examples using SqlDbType.Varbinary, which is not an option in this situation.
Our latest attempt was to attempt to convert the byte[] to a binary string, pass it into the stored procedure as nvarchar(max), and then use CONVERT(varbinary(max), #theFileBinaryString) when saving it to the Document table, however, this saves a corrupt file.
C#
byte[] pDocumentBytes = ...;
string documentAsBinary = "0x" + BitConverter.ToString(pDocumentBytes).Replace("-", "");
SQL
#DocumentContentAsBinary nvarchar(max) -- This is "documentAsBinary" from C# above
DECLARE #DocumentContentVarbinary varbinary(max);
SET #DocumentContentVarbinary = CONVERT(varbinary(max), #DocumentContentAsBinary);
Assume you have this SP:
DECLARE
#Value1 ...
#Value2 ...
...
#File VARBINARY(MAX)
INSERT INTO [YourTable] (Column1, Column2, ..., File) VALUES (#Value1, #Value2, ..., #File)
Use this syntax to convert the file to byte array and directly insert byte array as varbinary data:
using System.Data.SqlClient;
using System.IO;
byte[] data;
using (FileStream fs = new FileStream(document, FileMode.Open)
{
BinaryReader fileReader = new BinaryReader(document);
data = fileReader.ReadBytes((int)document.Length);
document.Close(); // don't forget to close file stream
}
using (var connection = new SqlConnection("YourConnectionStringHere"))
{
connection.Open();
using (var command = new SqlCommand("YourSPHere", connection)
{
command.CommandType = CommandType.StoredProcedure;
// insert parameters here
// add file parameter at the end of collection parameters
// -1 means max
command.Parameters.AddWithValue("#File", SqlDbType.VarBinary, -1).Value = data;
command.ExecuteNonQuery();
}
connection.Close();
}
Reference: http://www.codeproject.com/Questions/309795/How-to-insert-byte-array-into-SQL-table
I hope this solution useful.
There isn't a SqlDbType that maps properly between VARBINARY(MAX) and byte[]. But actually that is OK, because the parameterisation infrastructure just handles this for you, the following code will just work:
var binary = new bytes[1];
var command = new SqlCommand("INSERT INTO [MyTable]([BinaryColumn]) VALUES (#binary)");
command.Parameters.AddWithValue("#binary", binary);
command.ExecuteNonQuery();
See here for more details:
What SqlDbType maps to varBinary(max)?
Update your query to use paramaters and pass the byte array as a paramater directly to the table
eg
SQL:
insert into table values (#data);
C#
SqlComman com = new SqlCommand("insert into table values (#data);",Database Connection);
com.Paramaters.Add(new SqlParameter("#Data" Byte array));
com.executeNonQuery();

Insert SQL with parameters causes "Incorect syntax near the keyword 'values'"

I want to populate a table in mssql with the values entered by the user (the error comes from the NumericUpDown) and I'm using this code:
string cs= "Data Source=CODRINMA\\CODRINMA;Initial Catalog=BusManager; Trusted_Connection=True;";
string insert = "INSERT INTO TipAutocar ([IDTipAutocar], [Marca], [Model], [Nrlocuri] values ([#TipAutocar], [#Marca], [#Model], [#Nrlocuri]))";
try
{
using (SqlConnection con = new SqlConnection(cs))
{
con.Open();
SqlCommand cmd = new SqlCommand(insert, con);
cmd.Parameters.AddWithValue("#IDTipAutocar", txtID.Text);
cmd.Parameters.AddWithValue("#Marca", txtMarca.Text);
cmd.Parameters.AddWithValue("#Model", txtModel.Text);
cmd.Parameters.AddWithValue("#Nrlocuri", nmrLocuri.Value);
int valoare = cmd.ExecuteNonQuery();
con.Close();
MessageBox.Show(valoare + "Tipul de autocar a fost adaugat cu succes!", "BusManager");
}
}
catch (Exception er) { MessageBox.Show(er.Message); }
But, when I press button to insert, I'm having the following error and I can't figure it out what's to do:
Incorect syntax near the keyword 'values'.
I'm missing a closing round parenthesis before values here:
string insert = "INSERT INTO TipAutocar ([IDTipAutocar], [Marca], [Model], [Nrlocuri] values ([#IDTipAutocar], [#Marca], [#Model], [#Nrlocuri]))";
You are not allowed to use [] around the parameters, otherwise it's not a parameter and you'll get an error f.e. "invalid columnname [#TipAutocar]".
You also name the parameter #TipAutocar but you add it as IDTipAutocar.
Also, always use the correct type, all the more if you use AddWithValue which infers the type from the value. So i guess that IDTipAutocar is an int, then parse it to one before:
cmd.Parameters.AddWithValue("#IDTipAutocar", int.Parse(txtID.Text));
As an aside, i'm always using a verbatim string literal. On that way i can format my sql query as i want, even with multiple lines. This should work as exptected:
string insert = #"INSERT INTO TipAutocar
( IDTipAutocar, Marca, Model, Nrlocuri )
VALUES
( #IDTipAutocar, #Marca, #Model, #Nrlocuri)";
Look at this bracket;
string insert = "INSERT INTO TipAutocar ([IDTipAutocar], [Marca], [Model], [Nrlocuri] values (#TipAutocar, [#Marca, #Model, #Nrlocuri))";
^^^
You close it at the end of your query, you should close it just before your VALUES part.
Change it to;
string insert = "INSERT INTO TipAutocar ([IDTipAutocar], [Marca], [Model], [Nrlocuri]) values (#TipAutocar, #Marca, #Model, #Nrlocuri)";
^^^ ^^^
You don't need are not allowed to use square brackets for your parameters by the way. Also use using statement to dispose your SqlCommand as well. And since you used this statement for your SqlConnection, you don't need to close it with con.Close() because this statement do that automaticaly.
Also you define your parameter name as #TipAutocar in your command but try to add parameter name as #IDTipAutocar which does not match. Change your parameter name like;
cmd.Parameters.AddWithValue("#TipAutocar", txtID.Text);
And don't use AddWithValue anymore. It may generate unexpected results. Use .Add() method overloads instead to specify your SqlDbType and parameter size.

How to pass Byte Array in a Query using C#?

I'm trying to insert bytes of byte array in the database. using following code.
String query = String.Format(#"INSERT INTO [Documents]
([InsertedBy], [DocumentName], [Document])
VALUES
('{0}','{1}',{2})",
insertedBy, docName, docBytes);
Cmd.CommandText = query;
Cmd.ExecuteNonQuery();
Following exception is occured:
An object or column name is missing or empty. For SELECT INTO
statements, verify each column has a name. For other statements, look
for empty alias names. Aliases defined as "" or [] are not allowed.
Change the alias to a valid name. Incorrect syntax near ''.
I'm not getting what the reason is.
Never use string concatenation or string functions to make parametrized queries.
Also, because (I suspect that) docBytes is a byte[], string concatenation will not have the results that you hope for.
Here is how I would do it:
private static void InsertDocument(SqlCommand cmd, int insertedBy, string docName, byte[] docBytes)
{
cmd.CommandText = #"INSERT INTO [Documents]
([InsertedBy], [DocumentName], [Document])
VALUES
(#insertedBy,#docName,#docBytes)";
cmd.Parameters.Add("insertedBy", SqlDbType.Int).Value = insertedBy;
// Note: consider using `nvarchar` instead of `varchar`;
cmd.Parameters.Add("docName", SqlDbType.VarChar, 100).Value = docName;
// Note: -1 maps to the nvarchar(max) length;
cmd.Parameters.Add("docBytes", SqlDbType.VarBinary, -1).Value = docBytes;
// The following call presupposes that the associated `SqlConnection` is open
cmd.ExecuteNonQuery();
}
If your insertedBy column is an int, you don't need to use single quotes with it. Because you are try to insert characters to your int typed column.
Just use it like;
string query = String.Format(#"INSERT INTO [Documents]
([InsertedBy], [DocumentName], [Document])
VALUES
({0},'{1}',{2})",
insertedBy, docName, docBytes);
But since we don't know your values, this is the only suggestion I have.

retrieving a value from a plsql select procedure

From a table containing rfid strings (random varchar strings) I have to select a free rfid string that is not yet in used in another table, for that i use the following sql statement:
select * from (
select rfid
from rfid_col
where rfid not in (select rfid from person)
)where rownum<=1;
the sql on itself works fine but then I needed to put it in a stored procedure
create or replace
procedure getFreeRfid(rfidout out varchar2) is
begin
select * into rfidout
from (select rfid from rfid_col where rfid not in (select rfid from person)
)where rownum<=1;
end getFreeRfid;
this code works fine in oracle sql developer
to retrieve this in C# using the oracle data I use the following code
OracleCommand rfidcommand = db.connection.CreateCommand();
rfidcommand.CommandType = System.Data.CommandType.StoredProcedure;
rfidcommand.CommandText = "getFreeRfid";
rfidcommand.Parameters.Add(new OracleParameter("rfidout", OracleDbType.Varchar2)).Direction = System.Data.ParameterDirection.Output;
rfidcommand.ExecuteNonQuery();
string rfid = rfidcommand.Parameters["rfidout"].Value.ToString();
however somehow this throws:
A first chance exception of type 'Oracle.DataAccess.Client.OracleException' occurred in Oracle.DataAccess.dll
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at "TIM.GETFREERFID", line 3
ORA-06512: at line 1
I have been struggling with this problem for quite some time now and this is my last solution
It is important to set size for strings when dealing with output parameters. The size sets automatically on Input parameters because it is known. I don't know if this will fix your issue but you will not get value if size not set on the output, not a full value anyway - you may get 1 character. And make sure that type in Db is indeed Varchar2
Please, try this code:
string connStr = ".........";
string result = null;
using (OracleConnection conn = new OracleConnection(connStr))
{
conn.Open();
using (OracleCommand comm = new OracleCommand("getFreeRfid", conn))
{
comm.CommandType = CommandType.StoredProcedure;
OracleParameter p = new OracleParameter("rfidout", OracleDbType.Varchar2, ParameterDirection.Output);
p.Size = 200;
comm.Parameters.Add(p);
comm.ExecuteNonQuery();
result = (string)comm.Parameters[0].Value;
}
}
Good luck!
PS: using will help you close and dispose of command and connection.

How to get UUID generated by MySQL into a C# variable

Here is the query:
string query = #"INSERT INTO session (PK_Id, user_id, login_time, machine_ip, machine_fingerprint)
VALUES (UUID(), #UId, #LogInTime, #MIp, #MFingerPrint);
";
Now I need this last inserted id back, which is a UUID generated by MySQL. As far as I read there is no select_last_insert_id() function for UUIDs!! And I read for php you could assign UUID() function first to a variable and then return that value. But how to go about that in C#?
Something like this, but not exactly:
string query = #"INSERT INTO session (PK_Id, user_id, login_time, machine_ip, machine_fingerprint)
VALUES (#UUID = SELECT UUID(), #UId, #LogInTime, #MIp, #MFingerPrint);
"; //how to do this here?
Here is more of my code:
string query = #"INSERT INTO session (PK_Id, user_id, login_time, machine_ip, machine_fingerprint)
VALUES (#UUID = SELECT UUID(), #UId, #LogInTime, #MIp, #MFingerPrint);
";
try
{
if (_conn.State != ConnectionState.Open)
_conn.Open();
MySqlCommand cmd = new MySqlCommand(query, _conn);
cmd.Parameters.AddWithValue("#UId", Utility.usr.Id);
cmd.Parameters.AddWithValue("#LogInTime", DateTime.Now);
cmd.Parameters.AddWithValue("#MIp", GetMachineIP());
cmd.Parameters.AddWithValue("#MFingerPrint", GetHardwareFingerPrint());
var s= Convert.ToString(cmd.ExecuteScalar()); //this returns an empty string :(
//I need to get it to any .NET data type, string, or Guid or byte[] or anything.
But I need this datatype of s to be used in another WHERE clause in a query like this:
string query = #"UPDATE session SET logout_time = #LogOutTime
WHERE user_id = #UId AND PK_Id = #SessionId";
try
{
if (_conn.State != ConnectionState.Open)
_conn.Open();
MySqlCommand cmd = new MySqlCommand(query, _conn);
cmd.Parameters.AddWithValue("#UId", Utility.usr.Id);
cmd.Parameters.AddWithValue("#SessionId", s);
cmd.Parameters.AddWithValue("#LogOutTime", DateTime.Now);
cmd.ExecuteScalar();
Here #"SessionId" is the UUID field in the same table. So basically, how can I get the MySQL varbinary field in C# so that I could use that type to update by specifying WHERE in another query?
In MySQL table the UUID field is varbinary (I hope to see some solution that is not another php link or that is not asking me to switch to char datatype in the database :) ).
Edit: The problem here is we have already added plenty of UUIDs generated by MySQL into the table, so I'm a bit apprehensive about changing MySQL UUID to .NET Guid. If that's the only workaround, I'll consider that. Just that this is the first time we needed the inserted UUID value back so that I can update in another query another point of time.
A sub question: Is .NET Guid exactly the same thing as MySQL UUID?
You can use the Guid type which is the MS implementation of UUID. You should be aware that when inserting data into the DB, you may need to convert the Guid to ByteArray if the MySQL driver isn't familiar with handling Guid's. See Store GUID in MySQL from C# for an example of this.
I think you can go ahead with your earlier implementation without having to rely on MS Guid, but I fear I am too late :)
string query = #"INSERT INTO session (PK_Id, user_id, login_time, machine_ip, machine_fingerprint)
VALUES (UUID(), #UId, #LogInTime, #MIp, #MFingerPrint);
SELECT PK_Id FROM session WHERE login_time=#LogInTime AND machine_fingerprint=#MFingerPrint; //or something similar which gives you the exact same id - UUID
";
try
{
if (_conn.State != ConnectionState.Open)
_conn.Open();
MySqlCommand cmd = new MySqlCommand(query, _conn);
cmd.Parameters.AddWithValue("#UId", Utility.usr.Id);
cmd.Parameters.AddWithValue("#LogInTime", DateTime.Now);
cmd.Parameters.AddWithValue("#MIp", GetMachineIP());
cmd.Parameters.AddWithValue("#MFingerPrint", GetHardwareFingerPrint());
MySqlDataReader r = cmd.ExecuteReader();
if (r.Read()) //ensure if it is read only once, else modify your `WHERE` clause accordingly
{
var s = (Guid)r[0];
}
//or even (Guid)cmd.ExecuteScalar() would work
Now you can query in update like this:
string query = #"UPDATE session SET logout_time = #LogOutTime
WHERE user_id = #UId AND PK_Id = #SessionId";
try
{
if (_conn.State != ConnectionState.Open)
_conn.Open();
MySqlCommand cmd = new MySqlCommand(query, _conn);
cmd.Parameters.AddWithValue("#UId", Utility.usr.Id);
cmd.Parameters.AddWithValue("#SessionId", s.ToByteArray());
cmd.Parameters.AddWithValue("#LogOutTime", DateTime.Now);
cmd.ExecuteNonQuery();
Note: Here I have converted the Guid variable s to byte array before querying. This is important, in WHERE clause, be it UPDATE or SELECT statements in query. I would ask you to move to binary field in MySQL table from varbinary.
Edit: If your table would grow dramatically large then inserting and selecting is a bad idea since SELECT query is an additional query being run. In that case #PinnyM's choice is better. I really do not think MySQL or any other database would have a default way to give back "custom" inserted ids which are not something database generated. So in short I advice you to not go for this..
Edit2: See this answer for getting binary value to .NET datatype. Sometimes casting do not work depending on MySQL .NET connector version..

Categories