This might seem an easy question for some, but I am struggling with it.
I am trying to use SQLDataReader.GetFieldType to check if a certain field is an Image field. Lets assume the first field of the result set is an Image field, if I do:
reader.GetFieldType(0).ToString;
I get System.Byte[] But is this the correct way to check for it? I really don't like:
if (reader.GetFieldType(0).ToString="System.Byte[]")
Is there a better way?
Thanks,
AJ
You could always shorten it a bit:
if(reader.GetFieldType(0) == typeof(byte[]));
Unfortunately there's no direct mapping from an image field in SQL Server to a .NET CLR type...which is why you get a byte array.
You might want to add further checking to make sure that the byte array being returned is actually an image (byte arrays are used for image, binary, varbinary, and rowversion columns as well).
You can check the type mappings at:
MSDN - Mapping CLR Parameter Data
It's preferable to use the Type.IsAssignableFrom method instead of looking at the type name itself.
Type fieldType = reader.GetFieldType(0);
bool isImageField = typeof(byte[]).IsAssignableFrom(fieldType);
This gives you some measure of compile-time safety.
Note: This doesn't actually guarantee that the field will contain images - any form of binary data can be stored in image/binary/varbinary fields, so the only way to see if it is truly an image is to read the value and try loading it as one. But you can use this to check if the field is a binary field.
An alternative way could be to use the SqlDataReader.GetSchemaTable method. This will return a datatable containing the schema of the resultset, and makes available the actual datatype from the db - e.g. the DataTypeName column of the schema table returned will be the actual SQL Server datatype like varchar, and the ProviderSpecificDataType column will be a System.Data.SqlType
e.g.
DataTable dataSchema = reader.GetSchemaTable();
// dataSchema.Rows[0]["DataTypeName"] would return the sql server
// data type name for the first column in the resultset.
You might have to check for the first bytes to see if they make an image header. Otherwise, you might deal with an audio file, for instance. So a byte array doesn't necessarily represent an image.
Related
We have a table which has a column IsChecked which has Binary(1) as the data type. Basically, it stores 0x00 or 0x01 to represent if that data row is checked.
I knew it would be better to use Bit as data type but there are lots of other modules associated with this table already so let's leave it the way it is for now.
I tried intuitive ways like
// _dr is the SqlDataReader
Convert.ToBoolean(_dr["IsChecked"]);
(bool)_dr["IsChecked"];
but it can't simply convert like that, then I tried some approaches I feel might work
bool.Parse(_dr["IsChecked"].ToString());
Convert.ToBoolean((byte)_dr["IsChecked"]);
Convert.ToBoolean((byte[])_dr["IsChecked"]);
Convert.ToBoolean((int)_dr["IsChecked"]);
But all above return me convert failed like
Specified cast is not valid.
I check out how my colleague read this field in their module and it seems to require an output parameter which has Bit as the data type to bring the value out.
But there should be some way easier to do the same, right?
I just need to know the correct way to convert _dr["IsChecked"].
As per the comment you are getting the value in _dr["IsChecked"] is a byte[] or collection and [0]=0 So you can use BitConverter.ToBoolean method,
which returns a Boolean value converted from the byte at a specified position in a byte array.
bool isChecked = BitConverter.ToBoolean(_dr["IsChecked"],0);
Try this working example as well. if the type of _dr["IsChecked"] is not byte[] then you can cast them using (byte[])_dr["IsChecked"] before applying BitConverter.ToBoolean
I'm building a C# project configuration system that will store configuration values in a SQL Server db.
I was originally going to set the table up as such:
KeyId int
FieldName varchar
DataType varchar
StringValue varchar
IntValue int
DecimalValue decimal
...
Values would be stored and retrieved with the value in the DataType column determining which Value column to use, but I really don't like that design. So I thought I'd go this route:
KeyId int
FieldName varchar
DataType varchar
Value varbinary
Here the value in DataType would still determine the type of Value brought back, but it would all be in one column and I wouldn't have to write a ton of overloads to accommodate the different types like I would have with the previous solution. I would just pull the Value in as a byte array and use DataType to perform whatever conversion(s) necessary to get my Value.
Is the varbinary approach going to cause any performance issues or is it just bad practice to drop all these different types of data into a varbinary? I've been searching around for about an hour and I can't get to a definitive answer.
Also, if there is a more preferred method anyone can think of to reach the same conclusion, I'm all ears (or eyes).
You could serialize your settings as JSON and just store that as a string. Then you have all the settings within one row and your clients can deserialize as needed. This is also a safe way to add additional settings at any time without any modifications to your database.
We are using the second solution and it works well. Remember, that the disk access is in orders of magnitude greater, than the ex. casting operation (it's milliseconds vs. nanoseconds, see ref), so do not look for bottleneck here.
The solution can be to implement polymorphic association (1, 2). But I dont think there is a need for that, or that you should do this. The second solution is close to non-Sql db - you can dump as a value anything, might be as well entire html markup for a page. It should be the caller responsability to know what to do wit the data.
Also, see threads on how to store settings in DB: 1, 2 and 3 for critique.
I have one web application, having one table in oracle10g having following structure:
Column Name DataType
UserImage long
My problem is that how should I display the IMAGE on my aspx page which is stored in long format?
If data type is BLOB or CLOB then it could be easier one, but it's stored in long.
I could not change the datatype since this is third party DB.
Please suggest me how could I achieve this. The solution could be either using Oracle or C#, I'm fine with both.
Thanks in advance.
You can't store an image in a 'long' datatype.
Instead - hold a static list of key-value pairs, each pair defines an index (say, from 1 to n) of an image
and the value holds the Image's file name.
For instance, the following pseudo code demonstrates a similar approach (should be implemented on the client/server side of your application, not in the DB
SWITCH (USERIMAGE)
CASE 1:
SETIMAGE("IMAGES/IMAGE_NUMBER_ONE.JPG");
BREAK:
CASE 2:
SETIMAGE("IMAGES/IMAGE_NUMBER_TWO.JPG");
BREAK:
and so on.
Another solution:
Assume your 1st table is called "Table1". create a new table in your database called my_images
Column name Column type Comments
UserImage LONG Foreign key to Table1.UserImage
ImageData BLOB
And,
SELECT t1.ImageData FROM Table1 t1, my_images mi
WHERE t1.UserImage == mi.UserImage;
The "chunk" characters you have posted seem to be a TIFF image. That gives an idea how the images are stored. In fact, the binary image data seems to be stored as character data. That's certainly completely unsupported and very fragile. I'd recommend converting it as soon as possible.
In the mean time, I can propose two ways of retrieving the data so I cannot guarantee that either one works.
But approaches are susceptible to characters sets: If two or more character sets are involved, your data will be converted and thereby destroyed. And both are susceptible to the maximum length of certain data types.
Approach 1:
Try to go via the RAW data type and retrieve it as a byte array. It's certainly limited to 32'000 characters, maybe even less.
SELECT UTL_RAW.CAST_TO_RAW(UserImage) FROM UNNAMED_TABLE WHERE ...
On the C# side, you should get an OracleBinary or byte[] instance.
Approach 2:
Try to retrieve it as a string. Then convert the string into a byte array using the original encoding (Encoding.GetBytes. With enough luck, the original data can be restored.
I have a table that contain column with VARBINARY(MAX) data type. That column represents different values for different types in my c# DB layer class. It can be: int, string and datetime. Now I need to convert that one column into three by it's type. So values with int type go to new column ObjectIntValue and so on for every new column.
But I have a problems with transmitting data to datetime column, because the old column contains datetime value as a long received from C# DateTime.ToBinary method while data saving.
I should make that in TSQL and can't using .NET for convert that value in new column. Have you any ideas?
Thanks for any advice!
Using CLR in T_SQl
Basically you use Create Assembly to register the dll with your function(s) in it,
Then create a user defined function to call it, then you can use it.
There's several rules depending on what you want to do, but as basically you only want DateTime.FromBinary(), shouldn't be too hard to figure out.
Never done it myself, but these guys seem to know what they are talking about
CLR in TSQL tutorial
This is a one off convert right? Your response to #schglurps is a bit of a concern.
If I get you there would have to be break in your update script, ie the one you have woukld work up to when you implement this chnage, then you's have a one off procedure for this manouevre, then you would be updating from a new version.
If you want to validate it, just check for the existnec or non-existance of the new columns.
Other option would be to write a wee application that filled in the new columns from the old one and invoke it. Ugh...
If this isn't one off and you want to keep and maintain the old column, then you have problems.
I have a table in which there is one column named:
'eZip' (varbinary(5), null).
Now I am adding value from a web form like this:
cmd.Parameters.Add("#eZip", SqlDbType.VarBinary).Value = BitConverter.GetBytes(int.Parse(txtZip.Text.ToString()));
Its working but instead of putting a valid zip code, it is inserting this into my column:
<Binary data>
What I am doing wrong here?
I don't think you are doing anything wrong per-se. if you define the field as varbinary you will always see "Binary Data" in SQL Server's management tools, regardless of the data.
Are you sure you don't want just CHAR(n) OR VARCHAR(n) for the zip code?
If you can't change the data type of that column, all you need to do is convert the value when you get the data back out. As recommended by others, you should at least change your code to assume that the five bytes are characters, not integers.
Insert the value:
cmd.Parameters.Add("#eZip", SqlDbType.VarBinary).Value = System.Text.Encoding.ASCII.GetBytes(txtZip.Text.ToString());
Retrieve the value in SSMS tools:
SELECT CONVERT(VARCHAR(5), [eZip]) AS [eZip] FROM #zip_table;
Retrieve the value from a DataRow dr in C#:
System.Text.Encoding.ASCII.GetString(dr["eZip"]);
If you can change the column to a CHAR(5) or VARCHAR(5), then no conversion will be necessary.