I have an app for pictures that can be added to sql database with some information.. I keep pictures as varbinary in sql table. I want to check whether the picture was added before. my code as follows:
byte[] img = File.ReadAllBytes(item);
//that converts the file to bytearray
string str = ByteString(img);
//ByteString is a method that converts bytearray to string (It works)
DataRow[] satirlar = das.Tables[0].Select("PicBinary=" + str);
//sql table keeps picture as varbinary in PicBinary Column
if (satirlar[0]!=null)
{
//codes
continue;
}
but I get an exception like ("column (//something unreadable) not found") over my das.Tables[0].Select command.. Any advice?
My first thought is that "something unreadable" is the string representation of the contents of the image file and Select is treating the right hand side of the expression "PicBinary=" + str as a column name since it's not quoted.
That said, I'm not certain that DataTable's Select method will allow you to do the comparison this way. You might want to look in to LINQ to DataSet (as recommended by this answer) to do a byte-by-byte comparison of the data from your file and the contents of each cell in that column.
You need to add correct Escape Sequences when passing the string variable in select.
Update:
I might have been wrong.
Try passing parameter as following?
SqlParameter parameter = new SqlParameter("#PicBinary", SqlDbType.VarBinary, buffer.Length);
parameter.Value = buffer;
sqlCommand.Parameters.Add(parameter);
where buffer is your input data for the query.
Related
I am constructing a sql_insert_string to be used in Microsoft.ApplicationBlocks.Data.SqlHelper to be used as follows:
SqlHelper.ExecuteNonQuery(Transaction, CommandType.Text, sql_insert_string)
When I hover over the SQL statement it looks like below:
string sql_insert_string = "Insert into images_table(image_id, image_byte_array) values ('123', System.Byte[])
One of the insert value is a byte array as shown above. The variable has value in the byte array, say like byte[6738] . But after the sql_insert_string is constructed, it comes as System.Byte[]. The image_byte_array column type is varbinary(max). The database is SQL Server 2008. Because of this the database throws the following error:
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.
you can insert the byte array like so:
private void FireSql(byte[] input)
{
const string sql_insert_string =
"Insert into images_table(image_id, image_byte_array) values (#image_id, #image_byte_array)";
SqlTransaction transaction = null; //wherever you get the transaction obj from.
var imageIdParam = new SqlParameter("#image_id", SqlDbType.Int, 4)
{
Direction = ParameterDirection.Input,
Value = 123
}; //change the data type to whatever data type you are expecting
var byteParam = new SqlParameter("#image_byte_array", SqlDbType.VarBinary)
{
Direction = ParameterDirection.Input,
Size = input.Length,
Value = input
}; //change the data type to whatever data type you are expecting
SqlHelper.ExecuteNonQuery(transaction, CommandType.Text, sql_insert_string, imageIdParam, byteParam);
}
I would suggest looking at an ORM (https://en.wikipedia.org/wiki/Object-relational_mapping) like Entity Framework(http://www.asp.net/entity-framework) to do all of this for you while increasing security and future changes much easier.
You should be using the Parameters while constructing the SQL Query which obviously will avoid SQL Injection attacks. How your queries are getting constructed is still unclear here.
Something like this should do it for you.
SqlParameter sParam = new SqlParameter("#image_byte_array", SqlDbType.VarBinary)
{
Value = image
};
SqlHelper.ExecuteNonQuery(Transaction, CommandType.Text, sql_insert_string, sParam)
You may use
string sql_insert_string =
String.Format("INSERT INTO images_table(image_id, image_byte_array) VALUES ('123', CAST('{0}' AS VARBINARY(MAX)))", System.Byte[].ToString());
And yes, as #marc_s commented, you shouldn't be constructing SQL statements as a security concern.
A small question
I am trying to run a db query through c#.
I am trying to print something on DB which I want to return as a string from C#
string altertable1 = "print 'scfs'";
SqlCommand altertable = new SqlCommand(createtablecommand, connection);
string x = altertable.(function which return the printed query result);
SO what i want is that x value will be scfs;
I don't think there is an easy way to capture the output of PRINT command, since it doesn't return any row readable through a SqlDataReader object.
I would consider a solution that stores the output messages of a query into a temporary table (for example #outputMessages) with just one varchar column. When the execution of your query is completed, I would capture its output messages stored into #outputMessages table with just a SELECT * FROM #outputMessages.
When the output messages capturing process is completed, just drop the temporary table.
Please also read the question linked by #Corak.
So I did it in a different manner ,
I declared a variable , and get my print statement data in that variable and rather than printing the variable , i select that variable in the last part.
Now for C# , i use altertable.ExecuteScalar which return the first row as string, so for me it was what I needed.
string altertable1 = "print 'scfs'";
SqlCommand altertable = new SqlCommand(createtablecommand, connection);
string x = altertable.(function which return the printed query result);
basically i have a service which looks at two tables - one resides on a remote server, the other locally. I am trying to write a program which will select any required files from the remote server and copy them locally. i can get this working for standard records but how do i handle the blob in c# - i am just starting out with the language so be gentle
a snippet of what i have is below
public static void BroadcastCheck(String ip_addr)
{
OdbcConnection local = new OdbcConnection("DSN=local");
OdbcConnection cloud = new OdbcConnection("DSN=cloud");
local.Open();
cloud.Open();
OdbcCommand update1 = new OdbcCommand("UPDATE exchange set status = '1' where `status`='0' and inp_date=chg_date and LEFT(filename,12)='" + ip_addr + "' and type='UPDATE'", cloud);
update1.ExecuteNonQuery();
OdbcCommand broadcastSelect = new OdbcCommand("select * from exchange where inp_date=chg_date and LEFT(filename,12)='" + ip_addr + "' and status='1' and type='UPDATE'", cloud);
OdbcDataReader DbReader = broadcastSelect.ExecuteReader();
int fCount = DbReader.FieldCount;
byte[] outByte = new byte[500];
while (DbReader.Read())
{
String type = DbReader.GetString(0);
String filename = DbReader.GetString(1);
String data = DbReader.GetBytes(1);
OdbcCommand broadcastCopy = new OdbcCommand("INSERT INTO exchange(type,filename) VALUES('"+type+"','"+filename+"'"+data+")", local);
broadcastCopy.ExecuteNonQuery();
}
itouchcloud.Close();
itouchlocal.Close();
Console.Write("Broadcast Check Completed \n");
}
Basically the cloud db is queried and may return multiple results, i want to process each record returned and copy it to the local DB.
i have looked around and cant seem to really get a decent solution, i can do this simply in Visual FoxPro 9 so im guessing there is a similar solution.
any help appreciated :)
The first part of the answer is, avoid dynamic SQL if you can. You're using "... VALUES ('"+type+"','"+filename+"'"+data+")" when you should be using "... VALUES (?, ?, ?)".
Then, add the parameters using, for instance,
// sample: the name of the parameter (here #Type) can be anything, and the type and length should match your schema.
broadcastCommand.Parameters.Add("#Type", OleDbType.VarChar, 10).Value = type;
The question marks will be replaced by the parameters in the order you specify them, so you should add type, then filename, then data, in that order.
Now, the value you specify should ALSO correspond to the type of field you are inserting into. So instead of String, String, String, you might want your variables to be of type String, String, byte[].
There are about a million reasons not to construct your queries dynamically, so I would recommend studying up on how to use the Parameters collection on your OdbcCommand. Start here.
UPDATE
In general you can get DataReader values simply by using the indexer [], without needing to go through the GetXXX() methods. For byte arrays, that's usually simpler, because you don't need to know or try to guess the length beforehand.
You can convert your code to use indexers this way:
String type = (string)DbReader[0];
String filename = (string)DbReader[1];
byte[] data = (byte[])DbReader[2];
Note that your GetBytes() call originally had a 1 in there, but I assume you aren't trying to get the bytes of the filename field. So, if your byte[] data is in another field, use that instead. Be aware, however, that you could also use the string field names just as easily (and it might be clearer the next time you need to read the code):
String type = (string)DbReader["type"]; // replace with whatever your fields are actually called
String filename = (string)DbReader["filename"];
byte[] data = (byte[])DbReader["data"];
On the off-chance you had filename and data both using the same field because data isn't actually in the database and instead you want to take the filename and read that filesystem object in as your data for the insert query, you'll need to use a different method.
byte[] data = System.IO.File.ReadAllBytes(filename); // requires .NET 2.0+
Either way you fill your variables, insert them with a parameterized query as explained above.
i am trying to save a xml file as a string in clob type column in oracle db from c# am not sure how to insert clob type data from c#.
code here:
public bool Insert_XMLDocument(string ReportType,object XMLDocument)
{
try
{
Database db = DatabaseFactory.CreateDatabase("XMLDOC_ConnectionString");
DbCommand dbc = db.GetStoredProcCommand("insert_XMLDOC");
dbc.CommandType = CommandType.StoredProcedure;
db.AddInParameter(dbc, "pid", DbType.Int32, 1);
db.AddInParameter(dbc, "repo_document", DbType.Object,XMLDocument);
int i = db.ExecuteNonQuery(dbc);
if (i > 0)
return true;
else
return false;
}
catch (Exception ex) {
//HandleException(ex);
return false; }
}
Error due to compilation of this : Cannot bind type System.String as Blob.
Can you show us your stored procedure and/or your db.AddInParameter() method? Without seeing more code this is more or less just a guess:
It seems like passing DbType.Object to your data layer would indicate that the data type of the parameter is supposed to be a BLOB (binary) yet you have indicated you want it to be a CLOB (character).
Let's assume your stored procedure is defined like this:
CREATE PROCEDURE insert_XMLDOC (pid IN NUMBER, repo_document IN CLOB)
If the input object XMLDocument parameter is a string, or if your db.AddInParameter() method is converting this object to a string or any sort of textual representation then your data layer could be trying to assign a string as a BLOB parameter.
instead of using database factory i used the .net oracle provider method in which we can get "OracleType.Clob" which solves the problem i just passed the xml document as string and the job was done
Although the question seems to be outdated, I want to share an example that worked for me.
My intention was to save a JSON string (with more than 32k characters) into a clob field.
This is what I did:
string JSON_string = JsonConvert.SerializeObject(SomeObject);
System.Data.OleDb.OleDbCommand myCommand = new System.Data.OleDb.OleDbCommand();
myCommand.Parameters.AddWithValue("", SomeAttribute);
myCommand.Parameters.AddWithValue("", SomeAttribute2);
myCommand.Parameters.AddWithValue("", SomeAttribute3);
myCommand.Parameters.AddWithValue("", JSON_string);
And then execute the command. I'm using our companies library to do that, so I don't have to worry about the database connection:
DataSet myDS = myUser.myLoginUser._MySpAppS.RunSQL("INSERT INTO MARS$T_BCSAVINGS (MASSNAHMEN_ID, USER_ID, AKTIV, HEBELDATEI) VALUES (?, ?, ?, ?);", myCommand.Parameters);
I'm saving the result in a DataSet only to check if the query was successful.
So basically what I did, is to handover the string to the OleDbCommand parameters list and executed the query with those parameters.
In my project i have to give a string input through a text field, and i have to fill a database table with these values. I should first check the values of a specific table column, and add the input string only if it is not there in the table already.
I tried to convert the table values to a string array, but it wasn,t possible.
If anyone have an idea about this, your reply will be really valuable.
Thankx in advance.
Since you say your strings in the database table must be unique, just put a unique index on that field and let the database handle the problem.
CREATE UNIQUE INDEX UIX_YourTableName_YourFieldName
ON dbo.YourTableName(YourFieldName)
Whenever you will try to insert another row with the same string, SQL Server (or any other decent RDBMS) will throw an exception and not insert the value. Problem solved.
If you need to handle the error on the front-end GUI already, you'll need to load the existing entries from your database, using whatever technology you're familiar with, e.g. in ADO.NET (C#, SQL Server) you could do something like:
public List<string> FindExistingValues()
{
List<string> results = new List<string>();
string getStringsCmd = "SELECT (YourFieldName) FROM dbo.YourTableName";
using(SqlConnection _con = new SqlConnection("your connection string here"))
using(SqlCommand _cmd = new SqlCommand(getStringsCmd, _con)
{
_con.Open();
using(SqlDataReader rdr = _con.ExecuteReader())
{
while(rdr.Read())
{
results.Add(rdr.GetString(0));
}
rdr.Close();
}
_con.Close();
}
return results;
}
You would get back a List<string> from that method and then you could check in your UI whether a given string already exists in the list:
List<string> existing = FindExistingValues();
if(!existing.Contains(yournewstring))
{
// store the new value to the database
}
Or third option: you could write a stored procedure that will handle the storing of your new string. Inside it, first check to see whether the string already exists in the database
IF NOT EXISTS(SELECT * FROM dbo.YourTableName WHERE YourFieldName = '(your new string)')
INSERT INTO dbo.YourTableName(YourFieldName) VALUES(your-new-string-here)
and if not, insert it - you'll just need to find a strategy how to deal with the cases where the new string being passed in did indeed already exist (ignore it, or report back an error of some sorts).
Lots of options - up to you which one works best in your scenario!