Best way to handle column conversion for DataTable.Load

Please support our C# advertiser: Programming Forums - DaniWeb Sister Site
Thread Solved

Join Date: Jul 2009
Posts: 972
Reputation: DdoubleD is a jewel in the rough DdoubleD is a jewel in the rough DdoubleD is a jewel in the rough DdoubleD is a jewel in the rough 
Solved Threads: 213
DdoubleD DdoubleD is offline Offline
Posting Shark

Best way to handle column conversion for DataTable.Load

 
0
  #1
Nov 7th, 2009
Hello friends! I have some database tables that store Image/Bitmap as part of each record as a Byte[]. I also have method that loads all the tables records into a DataTable and I would like some suggestions on how I can get this Byte[] column in my DataTable to be of type
System.Drawing.Image after or during the load from the DbDataReader .

Thanks in advance!

  1. public DataTable SelectAll(string tableName, DbConnection conn)
  2. {
  3. DataTable dt = new DataTable();
  4.  
  5. try
  6. {
  7. string query = "SELECT * FROM " + tableName;
  8.  
  9. conn.Open();
  10.  
  11. using (DbCommand cmd = GetDbCommand(query, conn))
  12. {
  13. using (DbDataReader dr = cmd.ExecuteReader())
  14. {
  15. dt.Load(dr);
  16. }
  17. }
  18. }
  19. catch (DbException ex)
  20. {
  21. Console.WriteLine("Exception: {0}\r\n Stack Trace: {1}", ex.Message, ex.StackTrace);
  22. System.Diagnostics.Debugger.Break();
  23. }
  24. finally
  25. {
  26. conn.Close();
  27. }
  28.  
  29. return dt;
  30. }
Reply With Quote Quick reply to this message  
Join Date: Feb 2009
Posts: 3,460
Reputation: sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of 
Solved Threads: 629
Sponsor
sknake's Avatar
sknake sknake is offline Offline
.NET Enthusiast
 
0
  #2
Nov 7th, 2009
Just create a new column and move the data over to the desired data type.


I don't know of a one-liner to do this:
  1. private void button1_Click(object sender, EventArgs e)
  2. {
  3. DataTable dt = new DataTable();
  4. dt.Columns.Add(new DataColumn("RecordId", typeof(int)));
  5. dt.Columns.Add(new DataColumn("Picture", typeof(byte[])));
  6. {
  7. DataRow row = dt.NewRow();
  8. row["RecordId"] = 1;
  9. row["Picture"] = System.IO.File.ReadAllBytes(@"C:\picture.bmp");
  10. dt.Rows.Add(row);
  11. row = dt.NewRow();
  12. row["RecordId"] = 2;
  13. row["Picture"] = System.IO.File.ReadAllBytes(@"C:\picture2.bmp");
  14. dt.Rows.Add(row);
  15. }
  16.  
  17. string colName = Guid.NewGuid().ToString();
  18. dt.Columns.Add(new DataColumn(colName, typeof(Image)));
  19. foreach (DataRow row in dt.Rows)
  20. {
  21. using (System.IO.MemoryStream ms = new System.IO.MemoryStream((byte[])row["Picture"]))
  22. {
  23. Image bmp = Bitmap.FromStream(ms);
  24. row.BeginEdit();
  25. row[colName] = bmp;
  26. row.EndEdit();
  27. }
  28. }
  29. dt.AcceptChanges();
  30. dt.Columns.Remove("Picture");
  31. dt.Columns[colName].ColumnName = "Picture";
  32. dt.AcceptChanges();
  33. System.Diagnostics.Debugger.Break();
  34. }
Last edited by sknake; Nov 7th, 2009 at 4:45 pm.
Scott Knake
Custom Software Development
Apex Software, Inc.
Reply With Quote Quick reply to this message  
Join Date: Jul 2009
Posts: 972
Reputation: DdoubleD is a jewel in the rough DdoubleD is a jewel in the rough DdoubleD is a jewel in the rough DdoubleD is a jewel in the rough 
Solved Threads: 213
DdoubleD DdoubleD is offline Offline
Posting Shark
 
0
  #3
Nov 8th, 2009
Thanks Scott, that works fine for what I'm doing.

Out of curiosity, do you know of a way or example of overriding the default behavior of the datatable's load from the db reader? I was thinking if I had a large table schema with several column types that cannot be directly translated to system types that I would want to consider a more efficient way of performing a load and conversion all-in-one.
Reply With Quote Quick reply to this message  
Join Date: Feb 2009
Posts: 3,460
Reputation: sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of 
Solved Threads: 629
Sponsor
sknake's Avatar
sknake sknake is offline Offline
.NET Enthusiast
 
0
  #4
Nov 8th, 2009
You can use the .NET reflector to dig in to the sql classes to see how it works. I'm sure it parses the rows one by one so you could manually read the rows and convert the columns as you import the data instead of using datable.load(); . I personally try to do everything at the data access layer after the .NET framework loads it in to a datatable (like the earlier example). In the old days of ado data access did not work so hot -- and i'm reluctant to try expanding their current data access and cause problems for myself.

As far as efficiency goes it would probably be the same. If you're pulling a PDF or an image down from the SQL Server it is stored as a byte[] array on the server. On the client end you have to instantiate the container class and load the buffer. No matter where you perform that task you're going to take a performance hit.

What you could do that my code didn't do is set the picture byte[] column to null after the image is loaded. The way I wrote the code means you will use double the memory until the all of the conversion is done, then it will drop the byte buffers.
  1. foreach (DataRow row in dt.Rows)
  2. {
  3. using (System.IO.MemoryStream ms = new System.IO.MemoryStream((byte[])row["Picture"]))
  4. {
  5. Image bmp = Bitmap.FromStream(ms);
  6. row.BeginEdit();
  7. row[colName] = bmp;
  8. row["Picture"] = DBNull.Value; //new line, reclaim memory
  9. row.EndEdit();
  10. }
  11. }
Scott Knake
Custom Software Development
Apex Software, Inc.
Reply With Quote Quick reply to this message  
Join Date: Oct 2008
Posts: 2,721
Reputation: adatapost has much to be proud of adatapost has much to be proud of adatapost has much to be proud of adatapost has much to be proud of adatapost has much to be proud of adatapost has much to be proud of adatapost has much to be proud of adatapost has much to be proud of adatapost has much to be proud of adatapost has much to be proud of 
Solved Threads: 501
Moderator
adatapost's Avatar
adatapost adatapost is offline Offline
Posting Maven
 
0
  #5
Nov 8th, 2009
You cannot change DataType of column if it has data already. Why not just add a column and remove a column than in this case?
Reply With Quote Quick reply to this message  
Join Date: Jul 2009
Posts: 972
Reputation: DdoubleD is a jewel in the rough DdoubleD is a jewel in the rough DdoubleD is a jewel in the rough DdoubleD is a jewel in the rough 
Solved Threads: 213
DdoubleD DdoubleD is offline Offline
Posting Shark
 
0
  #6
Nov 9th, 2009
Originally Posted by sknake View Post
... I'm sure it parses the rows one by one so you could manually read the rows and convert the columns as you import the data instead of using datable.load(); .

...On the client end you have to instantiate the container class and load the buffer.
Thanks for the follow-up sknake. I'm going to mark this as solved, but was wondering if you could refer any examples related to the excerpted quotes above?
Reply With Quote Quick reply to this message  
Join Date: Feb 2009
Posts: 3,460
Reputation: sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of sknake has much to be proud of 
Solved Threads: 629
Sponsor
sknake's Avatar
sknake sknake is offline Offline
.NET Enthusiast
 
0
  #7
Nov 10th, 2009
DdoubleD,

Watching the behavior of DTS in MSSQL I noticed that it submitted two queries -- the first fetches the schema only, the second starts fetching the data. It appears what they did is this:
  1. public DataTable QueryDataTableSchemaOnly(string query, List<DataParameter> lst)
  2. {
  3. DataTable result = null;
  4. using (DbConnection conn = GetDbConnection())
  5. {
  6. conn.Open();
  7. using (DbCommand cmd = GetDbCommand(query, lst, conn))
  8. {
  9. LogQuery(query, lst);
  10. using (DbDataReader dr = cmd.ExecuteReader(CommandBehavior.SchemaOnly))
  11. {
  12. result = new DataTable();
  13. result.Load(dr);
  14. }
  15. }
  16. conn.Close();
  17. }
  18. return result;
  19. }

Now that you have the schema information you could re-run your query with executing a reader but instead of loading the reader directly in to a datatable you could read row-by-row and convert all of the values to the desired data type as you imported the rows. I have long suspected this is how the .NET framework works under the hood but I have never dug in to it.
Scott Knake
Custom Software Development
Apex Software, Inc.
Reply With Quote Quick reply to this message  
Join Date: Jul 2009
Posts: 972
Reputation: DdoubleD is a jewel in the rough DdoubleD is a jewel in the rough DdoubleD is a jewel in the rough DdoubleD is a jewel in the rough 
Solved Threads: 213
DdoubleD DdoubleD is offline Offline
Posting Shark
 
0
  #8
Nov 10th, 2009
Thanks--I'll look into this.
Reply With Quote Quick reply to this message  
Reply

This thread has been marked solved.
Perhaps start a new thread instead?
Message:




Views: 529 | Replies: 7
Thread Tools Search this Thread



Tag cloud for C#
About Us | Contact Us | Advertise | DaniWeb | Acceptable Use Policy | RSS Feed

©2003 - 2009 DaniWeb® LLC