In database management and application development we must be mindful of space and memory requirements. I have always been taught to use the data type that uses the least amount of space for your needs.
In my scenario, I have a column in a table that stores values {0,1,2,3,4} (SQL Server 2012). For this I chose to use the tinyint datatype. These values are pulled from the database into a C# application. Currently, I cannot get this tinyint data type to convert to a byte. When I try, I get an error "Cannot implicitly convert int to byte". If I change the datatype in the application to an integer, I can pull it just fine. Same with a string.
For performance purposes, is it okay to use integers throughout my entire application where I would normally use byte? If not, how do you convert an integer to a byte?
This is the code that I use that gives an error:
string strSQL = "SELECT securityLevel FROM security WHERE employeeID=#empID;";
using (SqlConnection dbConn = new SqlConnection(connParam))
{
dbConn.Open();
byte level = 0;
using (SqlCommand dbCommand = new SqlCommand(strSQL, dbConn))
{
dbCommand.CommandType = System.Data.CommandType.Text;
dbCommand.Parameters.AddWithValue("#empID", "12345");
using (SqlDataReader dbReader = dbCommand.ExecuteReader())
{
while (dbReader.Read())
{
level = dbReader.GetByte(0);
}
}
}
Console.WriteLine(level);
Console.ReadLine();
}
I have also tried:
level = (byte)dbReader.GetValue(0);
Yes, you were correct to pick TINYINT as the datatype if you are storing only 0 - 4.
Yes, TINYINT equates to a byte in .Net. You can see a list of mappings here:
http://msdn.microsoft.com/en-us/library/cc716729(v=vs.110).aspx
No, you did not actually use TINYINT when creating the table, else you would not be getting this error. The error message is very specific about the source datatype being INT.
No, do not use INT to store these values. That is unnecessary and what you are attempting to do (i.e. TINYINT and byte) is perfectly valid and I have done it many times.
Assuming you do not have millions of rows of data in that table and constant hits against it, run the following:
ALTER TABLE [security] ALTER COLUMN [securityLevel] TINYINT NOT NULL;
(I am assuming that the column is currently NOT NULL and in that case, if you leave off the NOT NULL in the ALTER TABLE statement, it will change the field to TINYINT NULL. If the field isn't currently NOT NULL, then just leave that part off)
I wrote the following LinqPad (against SqlServer express) to verify that you can read in a tinyint as a byte using .NET and SqlServer:
var cb = new SqlConnectionStringBuilder { DataSource = #".\Sqlexpress", InitialCatalog = "Medallion_OData_Tests_CustomersContext251990930203", IntegratedSecurity = true };
using (var c = new SqlConnection(cb.ConnectionString))
{
c.Open();
var cmd = c.CreateCommand();
cmd.CommandText = "SELECT CAST(1 AS tinyint)";
var reader = cmd.ExecuteReader();
reader.Read();
reader.GetByte(0).Dump();
}
This suggests to me that the actual securityLevel column in your database is not of the type TINYINT. To verify, why not temporarily modify your select query to include a CAST to TINYINT as in my example? If this works, that will confirm that the table schema is the problem.
Other ways to check the actual table schema include querying sys.columns or highlighting the name of the table in SqlServer Management Studio and hitting ALT+F1.
I think safest way is to use Convert.ToByte Method:
level = Convert.ToByte(dbReader.GetValue(0));
It converts from many value types to byte.
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.
I set my table column as integer.
Now I am trying to read it in my c# code using getint32 and for some reason I get a cast error, and when I checked some more I saw that I am getting a decimal from my db. how can that be? Isn't the oracle integer equals to c# int?
using (OracleCommand cmd = new OracleCommand(#"select id,title from table"))
{
cmd.Connection = _conn;
OracleDataReader r = cmd.ExecuteReader();
while (r.Read())
{
Debug.WriteLine(reader.GetFieldType(0)); // <--decimal
//reader.GetDecimal(0);
reader.GetInt32(0); <---cast error
Debugger.Break();
}
r.Close();
}
the id column is set as integer, also tryed number. comfused :S
Have a read at this:
Which .NET data type is best for mapping the NUMBER Oracle data type in NHibernate?
Oracle number maps to .net decimal. Microsoft is aware of this issue.
You shouldn't do that.
An int (System.Int32) is not big enough to hold every possible decimal value. If your column type is decimal, use GetDecimal() method, if your column type is int, use GetInt32() method.
There is no implicitly conversation decimal to int at all.
How can I INSERT values into SQL Server that are stored in a string[] such that some of the values should be disregarded in favor of the values stored in SQL Server as default constraints on the table? What do I need to pass(e.g. NULL or something else) to use those defaults?
Currently, I add all the defaults in my code, and it is getting bulky.
Below is my code:
if (value == "") value = "0";
string insert = "INSERT INTO " + table + " (" + columns + ") VALUES (" + atColumns + ")";
using (SqlConnection connect = new SqlConnection(connection))
{
using (SqlCommand command = new SqlCommand(insert, connect))
{
//adds values to corresponding parameters
for (int i = 0; i < table_cols.Length; i++)
{
command.Parameters.AddWithValue("#" + table_cols[i], table_vals[i]);
}
foreach (SqlParameter Parameter in command.Parameters)
{
if (Convert.ToString(Parameter.Value) == "")
{
Parameter.Value = DBNull.Value;
}
}
connect.Open();
command.ExecuteNonQuery();
response = "Success";
return response;
If a specific Parameter.Value is not-null and has a default set by SQL Server, this code will not work with null.
In SQL Server, this gets handled by omitting the value in your insert statement (this omission triggers inserting the default value for the table, whereas providing null produces errors).
If you want SQL Server to use the default value constraint for the column then don't include the column as part of the insert parameters.
Example:
--From SQL Server
CREATE TABLE Orders
(
Id INT IDENTITY PRIMARY KEY
,Amount INT NOT NULL
,Cost MONEY NOT NULL
,SaleDate DATE NOT NULL DEFAULT GETUTCDATE()
);
//From C#
public int Insert(decimal cost, int amount)
{
using (var connection = new SqlConnection(connectionString))
{
var command = connection.CreateCommand();
//Don't specify the SaleDate and it will insert the current time
command.CommandText = "INSERT INTO Orders(Amount, Cost) VALUES(#Amount, #Cost); SELECT SCOPE_IDENTITY();";
command.Parameters.AddWithValue("#Amount", amount);
command.Parameters.AddWithValue("#Cost", cost);
using(var reader = command.ExecuteReader())
{
if(reader.Read())
return Convert.ToInt32(reader[0]);
}
}
return 0;
}
If you want to use a parameters list in your C# code then just keep the parameter names grouped with their values and if the value is null and it has a default value then just skip it.
Passing in a NULL tells SQL that you want a NULL in that column overriding the default. If you want to pass something in pass in the keyword DEFAULT. I wrote an article, "keyword DEFAULT", about the usage:
The DEFAULT keyword causes the default value (from the constraint) to be inserted into the column.
Just remember that when you pass in DEFAULT don't put quotes around it. That makes it the string DEFAULT rather than the keyword DEFAULT.
The only other way of doing it I can think of would be triggers based your approach (and you're better off coding it at that point).
However, if you alter your approach to use stored procedures, you can do your value handling natively in SQL, otherwise you're stuck coding it into your app... might i recommend Ternary statements for your example: http://msdn.microsoft.com/en-us/library/ty67wk28%28v=vs.80%29.aspx .
If you include a column in the column list, it will try and insert the value you give, it. It will not assume that NULL means "just insert the default value".
If you don't want to insert a value into that column, don't include it in your column list (or value list, obviously).
While it may seem more efficient to loop through the table columns and be agnostic of the column name, type, etc. In the long run you may be better off handling each column explicitly so you can choose whether or not to use a default, verify the value, etc.
I actually used the INFORMATION_SCHEMA.COLUMNS table to pull back from SQL Server all of the Column Defaults. Then I just organized the defaults into a string[] and looped through it to insert defaults rather than nulls (some defaults are null).
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.
I have a .NET Wndows application in C#. It's a simple Windows application that is using the MySql 5.1 database community edition. I've downloaded the MySql ODBC driver and have created a dsn to my database on my local machine. On my application, I can perform get type queries without problems, but when I execute a given insert statement (not that I've tried doing any others), I get the following error:
{"ERROR [HY001] [MySQL][ODBC 5.1 Driver][mysqld-5.0.27-community-nt]Memory allocation error"}
I'm running on a Windows XP machine. My machine has 1 GB of memory.
Anyone have any ideas? See code below
OdbcConnection MyConn = DBConnection.getDBConnection();
int result = -1;
try
{
MyConn.Open();
OdbcCommand myCmd = new OdbcCommand();
myCmd.Connection = MyConn;
myCmd.CommandType = CommandType.Text;
OdbcParameter userName = new OdbcParameter("#UserName", u.UserName);
OdbcParameter password = new OdbcParameter("#Password", u.Password);
OdbcParameter firstName = new OdbcParameter("#FirstName", u.FirstName);
OdbcParameter LastName = new OdbcParameter("#LastName", u.LastName);
OdbcParameter sex = new OdbcParameter("#sex", u.Sex);
myCmd.Parameters.Add(userName);
myCmd.Parameters.Add(password);
myCmd.Parameters.Add(firstName);
myCmd.Parameters.Add(LastName);
myCmd.Parameters.Add(sex);
myCmd.CommandText = mySqlQueries.insertChatUser;
result = myCmd.ExecuteNonQuery();
}
catch (Exception e)
{
//{"ERROR [HY001] [MySQL][ODBC 5.1 Driver][mysqld-5.0.27-community-nt]Memory
// allocation error"} EXCEPTION ALWAYS THROWN HERE
}
finally
{
try
{
if (MyConn != null) MyConn.Close();
}
finally { }
}
It was because some fields accept null, I had passed them as null where they should be passed as DBNull.Value. For all the fields which allow null should be checked for null and if found null, DBNull.Value should be passed.
Just for the sake of completeness, Chinjoo's SQL statement would likely be something like this:
mySqlQueries.insertChatUser = "insert into ChatUsers (UserName, Password, FirstName, LastName, sex) values (?,?,?,?,?);";
This is known as a parameterized insert where each question mark represents one of his parameters. In this simple example the order of the parameters in the parameter collection in code must match the order of the column names in the SQL statement.
While less elegant than using a function, the fix for his null problem would look something like this for one of his parameters:
OdbcParameter LastName = new OdbcParameter("#LastName", u.LastName);
is replaced with
// if the value is "null" return DBNull, else just the value
OdbcParameter LastName = new OdbcParameter("#LastName",
(u.LastName == null) ? System.DBNull.Value : (object)u.LastName);
At least in my code (which is slightly different) the inner cast to type object is required since otherwise the compiler isn't sure what type the ?: operator should return.
Hope this helps anyone who is relatively new to parameterization, etc.
No criticism of Chinjoo implied at all--his posting helped me out! Just thought I'd share for the less-experienced. I'm by no means expert so take everything I say with a grain of salt.
This exception also can be raised if you try to insert invalid chars in a VARCHAR field. In example, if the string is generated by a UNIX machine and has end of line characters '\n'. You can just replace that problematic characters to Windows style, or viceversa, or just delete it if you don't want to store end of lines.
You can check the strings, and if any of them has end of line characters, try to repeat the insert deleting them. If it works, the problem are these characters.