bulk image storage in sql server 2008 - c#

I am creating a asp.net app in C# .net 4.0 using VS 2008 & MS SQL Server 2008 R2. I want to upload image(.bmp) for each order and store it in DB corresponding to its order. It must be retrieved when View functionally is requested.
My requirement is to store images and retrieve it. Number of orders might be around 50 orders each day. It might be over be overhead as number increases. Please suggest me efficient method to overcome memory issue.

Well, you can either store them in the database as varbinary(max) or store a URL to a file. If you have 50 images a day, it might be better to go for the file and URL method.
There's advantages and disadvantages to both. But as you said you want to store them in the DB:
I think one big one on the database storage is that no one can just come along and rename / delete the folder, or mess with the files in it.
Another good point for the database is that you can restore a database and not have to try to keep the keep the folder in sync.
You can use an ImageConverter to convert between an array of bytes to an image and back
var stream = new MemoryStream();
var imageData = DataAccess.GetImageData(); //Returns a System.Linq.Binary for me
var imgageBinaryData = imageData.ImageData.ToArray(); //This returns a byte array
var img = Image.FromStream(stream); //Here is your image ready for displaying
Then to go back something like
var stream = new MemoryStream();
img.Save(stream,System.Drawing.Imaging.ImageFormat.Jpeg);
var myBytes = ms.ToArray();
Edit: Oh and storing them as Jpeg rather than Bmp will save a lotta space

Related

Efficiently iterating and updating large amounts of data from a database

I have a table in SQL Server that is storing files in binary format. Each row is on average ~3MB and there are tens of thousands of rows. What I'd like to do (since I must keep these tables around), is query each row, then run some compression on the binary data, and then re-insert the data (by updating each row).
My current naive implementation simply does something similar to this (using Dapper):
var files = con.QueryAsync<MyClass>("SELECT ID, Content from Files");
foreach (var file in files)
{
... compress file.Content here
con.ExecuteAsync("UPDATE Files SET Content = #NewContent WHERE ID = #ID", { ... });
}
Obviously this is very inefficient because it first loads all files into memory, etc... I was hoping can somehow do a query/update in "batches", and IDEALLY I'd like to be able to run each batch asynchronously (if that's even possible).
Any suggestions would be appreciated (using SQL Server BTW).
Entire operation could be done on db instance, without moving data over network to application and back, using built-in function COMPRESS:
This function compresses the input expression, using the GZIP algorithm. The function returns a byte array of type varbinary(max).
UPDATE Files
SET Content = COMPRESS(Content)
WHERE ID IN (range); -- for example 1k rows per batch
If you are using SQL Server version lower than 2016 or you need "custom" compression algorithm you could use user-defined CLR function.

Error when converting byte array to System.Drawing.Image

I'm using C# 4.5 Framework and MySql
MySqlDataReader reader = Command.ExecuteReader();
if (reader.Read())
{
byte[] ReturnImage = reader["Photo"] as byte[];
MemoryStream ms = new MemoryStream(ReturnImage);
Image Photo = Image.FromStream(ms); //Error is in this statement!!
}
When this stmt is executed the following error displays "Parameter is not valid"
I couldn't find the answer from the web.. Somebody Pls help..
The most likely cause here is that the contents of the longblob are not the raw image bytes. Rather than go around in circles, the first thing to do is to: compare them. For example, you say (comments) that the data came from a jpg file, via OpenFileDialog. In that case, compare them. Check that you have successfully stored and retrieved the image.
Let's suppose that the file in question is c:\Some\Photo.jpg - stored etc per whatever process. In that case, you should be able to check the contents are the same. Until the following reports success, all bets are off:
byte[] original = File.ReadAllBytes(#"c:\Some\Photo.jpg");
byte[] ReturnImage = reader["Photo"] as byte[];
if(Convert.ToBase64String(original) == Convert.ToBase64String(ReturnImage)) {
Console.WriteLine("Success; the contents match");
} else {
Console.WriteLine("Failure; the contents are different");
}
If this reports "Failure; the contents are different", then the error is most likely in one of:
the code where you prepare the image to be stored (populating parameters etc)
the stored procedure that does the storage
the code that fetches the image back from the database
If this reports "Success; the contents match": then and only then is it meaningful to look at the code that attempts to load the Image. In this scenario, and assuming that c:\Some\Photo.jpg loads in most other image loading tools ("paint", etc) - then it is possible that Image doesn't recognise the subformat. But my guess is that it is going to say "Failure; the contents are different".
Note that Convert.ToBase64String here is used solely as a lazy way to check binary equivalence. You wouldn't use it like this in production code, but it is fine for this purpose.

In Asp.net (c#) ,how to store an image in database(linq to sql)?

i need to get an image from client and displayed(preview) before saving it into database..and then should be saved in database after getting preview..?
Is is possible in Asp.net using c#... ?
Yes, it's possible.
If you are using MS SQL Server, declare a field in your table as type "image" or "varbinary". Varbinary limits the number of bytes stored depending on your version of SQL Server, so "image" is the way to go. After all, you are storing an image ;)
Then store your image as a byte array in that field.
Without seeing some code, it's hard to give code samples. Are you using SqlCommand directly, Linq2Sql, Entity framework or NHibernate to communicate with your database?
[Edit: Linq2Sql sample]
On your linq object you will have a propery called Image, if that's what you named your image/varbinary column. To assign it do this:
// assign data
byte[] imageByteArray = ...some byte data...;
myObject.Image = new Binary(imageByteArray);
// save to db
dataContext.YourTable.InsertOnSubmit(myObject); //YourTable is the name of your actual table class
dataContext.SubmitChanges();
where imageByteArray is a byte[] holding your image.
The Binary object is a wrapper around a byte[].

Store an image in a SQL Server CE database

Does any one know of an example on how to store an image in a SQL Server CE database?
What data type should the column be? (I am guessing binary.)
I use Linq-To-Datasets. Is it possible using that to put the image into the database and pull it out again later?
Thanks for any advice.
Here is how I did it:
MemoryStream stream = new MemoryStream();
myBitmapImage.Save(stream, ImageFormat.Png);
myInsertLinqToDataSetRow.IMAGE_COLUMN = stream.ToArray();
To load it back out again I did this:
MemoryStream stream = new MemoryStream(myLinqToDataSetRow.IMAGE_COLUMN);
myBitmapImage.SignatureImage = new Bitmap(stream);
I found a page on MSDN that said that the Image column type is going away and that you should use varbinary(MAX). Max is not supported on SQL Server CE so I did varbinary(8000).
LATER NOTE: while varbinary(max) is not supported on SQL Server CE. Varbinary(8000) is not big enough for many images. I did end up using the Image type even though it is planned to be deprecated. Once ms offers a resonable alternitive on the mobile platform I will consider switching.
Here is an MSDN article explaining how:
http://support.microsoft.com/kb/318639
Unfortunately, the example is in VB, but I am sure that you can get the idea of how to do it.
I would say the binary datatype would be fine for storing the images.
Why aren't you using the Image type? Here is a description of types, supported by the sql server ce.
Image - Variable-length binary data with a maximum length of 2^30 – 1 (1,073,741,823) bytes.
This is not a direct answer to your question, but I've had good success storing the image's filepath (example: C:\images\image1.png) as a string value in the database instead of the raw image.
One advantage to this is that it keeps the database size smaller.
Another is that multiple tables can point to the images without storing multiple copies of the image.

Retrieving an image from database with Linq to SQL

In my database I have stored images in the "image" data type, showing up as a binary code.
I now want to retrieve all images from one column and diplay them on a asp.net page with C#.
databaseDataContext db = new databaseDataContext();
var images = from Picture p in db.Pictures
select p.pictureThumb;
then I use this:
foreach (Picture p in images)
{
galleryImages.Controls.Add(p);
}
But that doesn't work because Binary can't be converted to Picture. I have Googled this and found that I have to cast to Byte and then to image? I can't find examples on how to do that though.
This should do it:
databaseDataContext db = new databaseDataContext();
var images = from p in db.Pictures
select Image.FromStream(new MemoryStream(p.pictureThumb.ToArray());
foreach (Image image in images)
{
galleryImages.Controls.Add(image);
}
Note that Image.FromStream takes ownership of the stream - it's only a MemoryStream anyway, but do make sure that you dispose of the image, for various reasons.
EDIT: Ah... I hadn't realised that this was for ASP.NET. That makes things harder - because the HTML is going to contain URLs, and then you'll need to be able to fetch the data later.
Does a picture have an ID of some kind? If so, fetch that instead of the actual data, and then set up a URL which is able to serve any thumbnail based on the ID (by fetching it from the database and just serving it with an appropriate content type).

Categories