the problem domain is that I have an db file with like ~90000 rows and 6 columns. I got an Select query where I get all the rows and columns that are necessary for me and that works fine. Now is the thing that I fill a DataTable with those records. I do this with SQliteDataAdapter Fill Method and this takes about ~1,3 seconds and after this I fill my ObservableCollection (<--Bound to DataGrid) with this data and this takes also about ~1,3 seconds. So here is my code
private void GetSelectedMaterial()
{
DataTable dtMaterial = new DataTable();
materialColl.Clear(); // Clearing ObservableCollection
Trace.WriteLine("GetSelectedMaterial TS " + DateTime.Now + DateTime.Now.Millisecond);
using (SQLiteConnection connection = new SQLiteConnection(dbConnection))
using (SQLiteCommand cmd = connection.CreateCommand())
{
connection.Open();
query = "SELECT * FROM Tbl_Materialliste LEFT JOIN(SELECT * FROM Tbl_Besitzt k WHERE k.TechnikID = '" + teTechnikID + "') as k ON k.MaterialID = Tbl_Materialliste.MaterialID";
dataAdapter = new SQLiteDataAdapter(query, connection);
Trace.WriteLine("query: " + DateTime.Now + DateTime.Now.Millisecond);
dtMaterial.Columns.Add("Checked", typeof(bool));
Trace.WriteLine("here comes the fill: " + DateTime.Now + DateTime.Now.Millisecond);
dataAdapter.Fill(dtMaterial);
Trace.WriteLine("Checkbox: " + DateTime.Now + DateTime.Now.Millisecond);
DetermineCheckBox(dtMaterial, teTechnikID, 8);
Trace.WriteLine("SQL TS: " + DateTime.Now + DateTime.Now.Millisecond);
}
FillMaterialColl(dtMaterial);
}
private void FillMaterialColl(DataTable dtMaterial)
{
foreach (DataRow dr in dtMaterial.Rows)
{
Material mat = new Material();
mat.isChecked = (bool)dr.ItemArray[0];
mat.materialID = (string)dr.ItemArray[1];
mat.materialkurztext = (string)dr.ItemArray[2];
mat.herstellername = (string)dr.ItemArray[3];
mat.herArtikenummer = (string)dr.ItemArray[4];
mat.dokument = (string)dr.ItemArray[5];
mat.substMaterial = (string)dr.ItemArray[6];
materialColl.Add(mat);
}
}
I know ObservableCollections are draining performance but is there some way to do this in another way? Some say to use DataReader instead of DataAdapter but DataAdapter shall use DataReader so I think there is no improvement in performance. So the main problem is that that process takes to long and user experience is not so good if showing new material takes about 3-4 seconds..
EDIT
So here comes my DB design:
It is a many-to-many relationship between Tbl_Material and Tbl_Technik
And my Select query gives me ALL entrys from Tbl_Material (~90k) and in addition those columns from Tbl_Besitzt where I can find the technikID
So that I can filter (for an checkbox) which entrys belong to my MaterialID
In my DB file MaterialId from Tbl_Materialliste is a PK and also TechnikID from Tbl_Technik - not that you are wondering in the design image, I didnt get they into the model..
Thanks a lot!
It's hard to investigate the performance issues of a database without knowing its schema and design. In your SQL query, there is a join expression. You need to ensure that the corresponding data fields are indexed in order to make the join operation fast. This depends also on the data size of both tables.
To speed up the displaying of the search results, you should avoid adding them item-by-item in your ObservableCollection<T>. This is because each time you add a new item, the Binding Engine transfers this item to the DataGrid causing the grid to perform all the actions it needs to display a record.
If you don't really need the collection to be observable (e.g. you won't add or remove any items in the view), then just make it to an IEnumerable<T>:
public IEnumerable<Material> Materials
{
get { return this.materials; }
private set
{
// Using the PRISM-like implementation of INotifyPropertyChanged here
// Change this to yours
this.SetProperty(ref this.materials, value);
}
}
In you method, create a local List<Material>, fill it, and then expose to the view:
List<Material> materials = new List<Material>();
// fill the list here
// ...
// finally, assign the result to your property causing the binding to do the job once
this.Materials = materials;
If you need the ObservableCollection<T> though, you can do the same trick - create a local copy, fill it, and finally expose.
If this doesn't help, you should try using the UI virtualization. This is a rather big topic, but there is a lot of information on the net.
Related
I have a problem with format in C#.
I have a DataGridView and a TextBox. In this datagridview, there is a column: the single price (format int).
I want sum every elements of single price's column and insert the result into this textbox, but Visual Studio gives me a problem with format of string input ("Format of input's string is not correct").
this is the code than i used:
int TOT = 0;
for (int i = 0; i < dataGridView3.Rows.Count; i++)
{
TOT = TOT + Convert.ToInt32(dataGridView3.Rows[i].Cells[6].ToString());
}
textBoxTot.Text = Convert.ToString(TOT);
Can you help me with this bad error?
UPDATE:
I think that the problem now is another. I can't find the methods of MySql.Data.MySqlClient library that it can give me the result of query.
MySqlCommand command = new MySqlCommand();
String sumQuery = "SELECT SUM(`prezzo`) FROM `fatturetemp`";
command.CommandText = sumQuery;
command.Connection = conn.getConnection();
command.Parameters.Add("#prezzo", MySqlDbType.Int32).Value = costo;
conn.openConnection();
conn.closeConnection();
How is the command that give me the result of sumQuery. If i find this command, i can take the result of query and paste in textbox
If your datagridview is showing a datatable (I.e. your data is stored in a datatable) you can add a DataColumn to the datatable whose .Expression property is set to the string "SUM([Price])", where Price is the name of your numeric datatyped column holding the price info.
Now every row in the table will have the sum of the prices (the same value over and over again), so if you want to databind your textBox to this new column then it will always show the sum no matter which row is the current row (because all rows have the same value). It will also auto update without you having to do anything!
And if you're not using databinding to a datatable, I recommend that you do do it, because it represents good MVC practice of keeping your data in one thing (DataTable) and showing it in another (DataGridView) and keeping these concerns separate
It would look something like this, as a quick example:
DataTable dt = new DataTable();
dt.Columns.Add("Name");
dt.Columns.Add("Price", typeof(int));
dt.Columns.Add("CalculatedTotal", typeof(int)).Expression = "SUM([Price])";
dt.Rows.Add("Apples", 100);
dt.Rows.Add("Oranges", 200);
BindingSource bs = new BindingSource();
bs.DataSource = dt;
WhateverDataGridView.DataSource = bs;
totalTextBox.DataBindings.Add(new Binding("Text", bs, "CalculatedTotal", true));
Here we have a data model (the datatable) where we keep our data. It has a couple of things we can set directly, and an third column that calculates based on the existing prices in all the table. If you look at this in the datagridview (assuming you have autogeneratecolumns turned on) you'll see that both rows have 300 for the CalculatedTotal, but they have individual amounts for price. There is a device called a BindingSource that sits between the datatable and the UI controls; you don't have to have one but it makes certain things easier regards updating controls when the data changes, and it maintains a concept of "current" - essentially whatever the current row is you're looking at in the datagridview; it all helps to avoid having to ask the DGV for anything - we just let the user type into the DGV, and it shows the data out of the datatable. All our dealings can be with the datatable directly - if you wrote a button to loop through the table and double all the prices, the controls in the UI would just reflect the change automatically. The textbox is connected to the CalculatedValue column via databinding; whatever the current row is, the textbox will show the CalculatedValue. Because the CalculatedValue column has the same value on every row, and they always all update if any price changes, the total textbox will always show the total. Add another textbox bound to Name to see what I mean; as you click around the grid and select different rows to be the "Current" row, the Name will change but the total does not. In truth it is actually changing in the same way that Name is, it's just that because the actual numeric value is the same on every row the contents of the textbox look like they don't change
UPDATE: I think that the problem now is another. I can't find the methods of MySql.Data.MySqlClient library that it can give me the result of query.
public string sommaFattura(String costo)
{
MySqlCommand command = new MySqlCommand();
String sumQuery = "SELECT SUM(`prezzo`) FROM `fatturetemp`";
command.CommandText = sumQuery;
command.Connection = conn.getConnection();
command.Parameters.Add("#prezzo", MySqlDbType.Int32).Value = costo;
conn.openConnection();
conn.closeConnection();
}
How is the command that give me the result of sumQuery. If i find this command, i can take the result of query and paste in textbox
It is weird that you are first converting to a string and then to an int.
int TOT = 0;
for (int i = 0; i < dataGridView3.Rows.Count; i++)
{
if (!dataGridView3.Rows[i].IsNewRow &&
int.TryParse(dataGridView3.Rows[i].Cells[6].Value.ToString(), out int v))
TOT += v;
}
textBoxTot.Text = TOT.ToString();
EDIT: Edited for your updated question. You shouldn't ask question inside a question buy anyway:
string sumQuery = "SELECT SUM(`prezzo`) FROM `fatturetemp`";
decimal total = 0M;
using (MySqlConnection cn = new MySqlConnection(" your connection string here "))
using (MySqlCommand cmd = new MySqlCommand(sumQuery, cn))
{
cn.Open();
total = Convert.ToDecimal(cmd.ExecuteScalar());
cn.Close();
}
Console.WriteLine(total);
I basically have a listbox that has postcode areas i.e : AE,CW,GU etc etc.
The user selects this and then a postback occurs - an sql statement is builts and a database query operation is performed and the results are returned to a datatable called tempdata.
So far so good. I then need to loop through this datatable and copy the records to my main viewstate datatable which is the datasource for google maps api.
DataTable tempstore = GetData(querystring, "");
//check tempstore has rows otherwise add defaultcust as default otherwise map will be blank
if (tempstore.Rows.Count == 0)
{
tempstore = GetData("WHERE CUSTCODE=='CD344'", "");
infoalert.Visible = true;
infoalert.InnerHtml = "No Results Returned For Selection";
}
foreach (DataRow row in tempstore.Rows)
{
dtpc.ImportRow(row);
dtpc.AcceptChanges();
}
//database command
using (OleDbConnection con = new OleDbConnection(conString))
{
using (OleDbCommand cmd = new OleDbCommand(query))
{
using (OleDbDataAdapter sda = new OleDbDataAdapter())
{
cmd.Connection = con;
sda.SelectCommand = cmd;
sda.Fill(dt5);
}
}
}
So my main datatable can grow and grow as users add more postcodes. However when it gets to around 500 rows or so I get a huge memory spike only on postback and then it settles back down.My ram usage goes from 2gb to 3gb and if even more postcodes is selected it maxes the memory and crashes my pc.
If I remove the:
dtpc.Importrow(row);
the memory spike goes completely, obviously because the main datatable has no rows. I thought you only run into memory issues when you have thousands of rows?
Any help would be much appreciated.
thank you
Do you really need all the rows at once
A DataReader will access a single row at a time and keep you memory to a minimum
DataReader class
If you need all you data at once create a class of strut for the data and hold it in a collection like a List. DataTable is a heavy object.
And if you are measuring memory via Task Manager be aware it is not very accurate.
First off, make sure you're wrapping any SQL execution in the appropriate "using" clauses. This is most likely the cause of your problem.
using (var command = new SqlCommand())
{
// Some code here
}
Like Blam said, DataTable is too heavy for your purposes.
You can convert your data rows into class objects quite easily:
var datasourceList = new List<YourCustomObject>();
foreach (DataRow row in tempstore.Rows)
{
var newMapsObject = new YourCustomObject
{
Value1 = row.Field<String>("Value1ColumnName"),
Value2 = row.Field<String>("Value2ColumnName")
};
datasourceList.Add(newMapsObject);
}
viewStateList.AddRange(datasourceList);
To bind a custom collection to a data display (such as a repeater) you assign the list to the .DataSource property of said display, then call .DataBind(). This will work for most all ASP.NET data display objects.
repeater1.DataSource = viewStateList;
repeater1.DataBind();
I'm trying to create an object variable that will hold a collection from an Execute SQL Task. This collection will be used in multiple Script Task throughout the ETL package.
The problem is, after the first Fill of the first Script Task, the object variable becomes empty. Here's a code on how I used the variable to a DataTable:
try
{
DataTable dt = new DataTable();
OleDbDataAdapter da = new OleDbDataAdapter();
da.Fill(dt, Dts.Variables["reportMetrics"].Value);
Dts.TaskResult = (int)ScriptResults.Success;
}
catch (Exception Ex)
{
MessageBox.Show(Ex.Message);
Dts.TaskResult = (int)ScriptResults.Failure;
}
Throughout the ETL package, Script Task components will have this piece of code. Since the variable becomes empty after the first Fill, I can't reuse the object variable.
I'm guessing that the Fill method has something to do with this.
Thanks!
It looks like your Dts.Variables["reportMetrics"].Value object holds DataReader object. This object allows forward-only read-only access to the data. You cannot fill DataTable twice using DataReader. To accomplish your task you need to create another script task that performs exactly what you described here: it reads the Reader to DataTable object and stores this DataTable object in another Dts.Variable with type Object.
Dts.Variables["reportMetricsTable"].Value = dt
After that all your subsequequent script tasks shall either create a copy of this table if they modify the data, or use it directly if they do not modify it.
DataTable dtCopy = (Dts.Variables["reportMetricsTable"].Value as DataTable).Copy()
I had a similar situation. While I think you can do a SQL Task with a SELECT COUNT(*) query and assign the result to an SSIS variable, what I did was create an int SSIS variable called totalCount with an original value of 0. I expect the total count to be > 0 (otherwise, I won't have anything to iterate on) so I created an if statement within my Script Task. If the value is zero, I assume totalCount has not been initialized, so I use the same code you are using (with the Fill method). Otherwise (i.e, in further iterations), I skip that part and continue to use totalCount variable. Here's the block of code. Hope it helps:
if ((int)Dts.Variables["User::totalCount"].Value == 0) // if the total count variable has not been initialized...
{
System.Data.OleDb.OleDbDataAdapter da = new System.Data.OleDb.OleDbDataAdapter();
DataTable stagingTablesQryResult = new DataTable();
da.Fill(stagingTablesQryResult, Dts.Variables["User::stagingTablesQryResultSet"].Value); // to be used for logging how many files are we iterating. It may be more efficient to do a count(*) outside this script and save the total number of rows for the query but I made this as proof of concept for future developments.
Dts.Variables["User::totalCount"].Value = stagingTablesQryResult.Rows.Count;
}
Console.WriteLine("{0}. Looking for data file {0} of {1} using search string '{2}'.", counter, Dts.Variables["User::totalCount"].Value, fileNameSearchString);
Excellent
This has helped me around an issue in building myt ETL platform.
Essentially I execute a SQL task to build a dataset of tasks, there is some in line transformations and rules which pull the relevant tasks to the fore, which for obvious reasons I only want to execute the once per execution.
I then need to get the unique ProcessIDs from the data set (to use in a For Each Loop)
Within the FEL, I want to then fetch the relevant records from the original dataset to then push through a further FEL process.
I was facing the same "empty data set" for the 2nd execution against the dataset.
I thought I'd try to share my solution to assist others
You'll need to add the Namespaces
using System.Data.OleDb;
into the Scripts
Screen shot of solution
Get dataset
Execute SQL - Get your data and pass into a Variable Object
Pull Ds
Declare the Variable Objects
public void Main()
{
DataTable dt = new DataTable();
OleDbDataAdapter da = new OleDbDataAdapter();
//Read the original table
da.Fill(dt, Dts.Variables["Tbl"].Value);
//Push to a replica
Dts.Variables["TblClone"].Value = dt;
Dts.TaskResult = (int)ScriptResults.Success;
}
Build Proc List
This gets a list of ProcessIDs (and Names) by filtering on a Rank field in the dataset
Declare the Variable Objects
public void Main()
{ //Take a copy of the Cloned Dataset
DataTable dtRead = (Dts.Variables["TblClone"].Value as DataTable).Copy();
//Lock the output object variable
Dts.VariableDispenser.LockForWrite("User::ProcTbl");
//Create a data table to place the results into which we can write to the output object once finished
DataTable dtWrite = new DataTable();
//Create elements to the Datatable programtically
//dtWrite.Clear();
dtWrite.Columns.Add("ID", typeof(Int64));
dtWrite.Columns.Add("Nm");
//Start reading input rows
foreach (DataRow dr in dtRead.Rows)
{
//If 1st col from Read object = ID var
if (Int64.Parse(dr[9].ToString()) == 1) //P_Rnk = 1
{
DataRow newDR = dtWrite.NewRow();
newDR[0] = Int64.Parse(dr[0].ToString());
newDR[1] = dr[4].ToString();
//Write the row
dtWrite.Rows.Add(newDR);
}
}
//Write the dataset back to the object variable
Dts.Variables["User::ProcTbl"].Value = dtWrite;
Dts.Variables.Unlock();
Dts.TaskResult = (int)ScriptResults.Success;
}
Build TaskList from ProcList
Cycle round ProcessID in a For Each Loop
Build TL Collection
..and map Vars
Build TL Var Mappings
Build TL Script
This will dynamically build the output for you (NB this works for me although havent extensively tested it, so if it doesnt work....have a fiddle with it).
You'll see I've commented out some Debug stuff
public void Main()
{
//Clone the copied table
DataTable dtRead = (Dts.Variables["TblClone"].Value as DataTable).Copy();
//Read the var to filter the records by
var ID = Int64.Parse(Dts.Variables["User::ProcID"].Value.ToString());
//Lock the output object variable
Dts.VariableDispenser.LockForWrite("User::SubTbl");
//Debug Test the ProcID being passed
//MessageBox.Show(#"Start ProcID = " + ID.ToString());
//MessageBox.Show(#"TblCols = " + dtRead.Columns.Count);
//Create a data table to place the results into which we can write to the output object once finished
DataTable dtWrite = new DataTable();
//Create elements to the Datatable programtically
//dtWrite.Clear();
foreach (DataColumn dc in dtRead.Columns)
{
dtWrite.Columns.Add(dc.ColumnName, dc.DataType);
}
MessageBox.Show(#"TblRows = " + dtRead.Rows.Count);
//Start reading input rows
foreach (DataRow dr in dtRead.Rows)
{
//If 1st col from Read object = ID var
if (ID == Int64.Parse(dr[0].ToString()))
{
DataRow newDR = dtWrite.NewRow();
//Dynamically create data for each column
foreach (DataColumn dc in dtRead.Columns)
{
newDR[dc.ColumnName] = dr[dc.ColumnName];
}
//Write the row
dtWrite.Rows.Add(newDR);
//Debug
//MessageBox.Show(#"ProcID = " + newDR[0].ToString() + #"TaskID = " + newDR[1].ToString() + #"Name = " + newDR[4].ToString());
}
}
//Write the dataset back to the object variable
Dts.Variables["User::SubTbl"].Value = dtWrite;
Dts.Variables.Unlock();
Dts.TaskResult = (int)ScriptResults.Success;
}
For Each Loop Container
FEL Cont Collection
N.B. Dont forget to map the items in the Variable Mappings
Now you can consume the records and do stuff with that data
I included the Msg Loop script as an easy data check...in reality this will go off and trigger other processes but just to aid you in data checks I though Id include it
Msg Loop
Msg Loop Script
public void Main()
{
// TODO: Add your code here
MessageBox.Show("ID = " + Dts.Variables["User::ProcID"].Value + ", and val = " + Dts.Variables["User::TaskID"].Value, "Name = Result");
Dts.TaskResult = (int)ScriptResults.Success;
}
Hope that helps somebody solve their issue (Ive been tring to resolve this for a working day or so :/
I have a MySQL database with comments, and I've already filled in my dataGridView_flaggedComments with flagged comments using this function:
private void button_Search1_Click(object sender, EventArgs e)
{
commentCount = 0;
//comboBox_stockIndex.SelectedIndex = 0;
richTextBox_flaggedComments.Clear();
dataGridView_flaggedComments.Refresh();
DataTable flaggedcomments = new DataTable("flaggedcomments");
using (MySqlConnection sqlConn = new MySqlConnection(strProvider))
{
using (MySqlDataAdapter da = new MySqlDataAdapter("SELECT Comment_ID, Comments_Date, Author, Title, Comments_Comment, Tickers_Ticker_ID FROM comments ORDER BY Comments_Date ASC", sqlConn))
{
da.Fill(flaggedcomments);
}
}
StringBuilder sb = new StringBuilder();
string[] words = File.ReadAllLines(sourceDirTemp + comboBox_crimeKeywords.SelectedItem.ToString() + ".txt");
var query = flaggedcomments.AsEnumerable().Where(r =>
words.Any(wordOrPhrase => Regex.IsMatch(r.Field<string>("Comments_Comment"), #"\b" + Regex.Escape(wordOrPhrase) + #"\b",
RegexOptions.IgnoreCase)));
dataGridView_flaggedComments.DataSource = query.AsDataView();
}
The flagged comments appear in dataGridView_flaggedComments are belong to different stock prices (each stock has its unique symbol and its Ticker_ID). I am trying to filter the current dataGridView_flaggedComments so that it only shows what I selected from comboBox_stockIndex.
However, my code will somehow retrieve all comments for this particular symbol from database rather than filtering what's in the dataGridView_flaggedComments. Can anyone point out what went wrong?
I've went through quite a number of questions at SO, but couldn't really relate it. Here's my code and it would be much appreciated if I could get some help! Thank you!
private void comboBox_stockIndex_SelectedIndexChanged(object sender, EventArgs e)
{
DataTable link_stockIndex = new DataTable("link_stockIndex");
using (MySqlConnection sqlConn = new MySqlConnection(strProvider))
{
using (MySqlDataAdapter da = new MySqlDataAdapter("SELECT Ticker_ID, Symbol FROM tickers", sqlConn))
{
da.Fill(link_stockIndex);
}
}
foreach (DataRow da in link_stockIndex.Rows)
{
for (int i = 0; i < dataGridView_flaggedComments.Rows.Count - 1; i++)
{
if (dataGridView_flaggedComments.Rows[i].Cells["Tickers_Ticker_ID"].Value.ToString() != "" && comboBox_stockIndex.SelectedItem.ToString() == da["Symbol"].ToString())
{
(dataGridView_flaggedComments.DataSource as DataView).RowFilter = string.Format("Tickers_Ticker_ID = '{0}'", da["Ticker_ID"]);
}
}
}
}
You have a very strange code in your comboBox_stockIndex_SelectedIndexChanged handler.
Just have a look: on every index change of combobox you're quering database with always the same query and later in the code you actually doesn't use results of this query. What for is it?
Let's go further. You are iterating over your dataGridView_flaggedComments rows and setting your RowFilter multiple times. Looks pretty unnecessary, as only the last filter will take place.
It looks like your code should be something like this:
Query database for SELECT Ticker_ID, Symbol FROM tickers as you have made, but outside SelectedIndexChanged handler, and store it into datatable.
In SelectedIndexChanged handler iterate over that datatable, and find a row having "Symbol" equal to your comboBox_stockIndex.SelectedItem.
Set RowFilter like "Tickers_Ticker_ID = Ticker_ID from row you've found in previous point. And return, don't set multiple filters.
Remark: I don't know how frequently your tickers database table being changed, so maybe suggestion about query it outside of SelectedIndexChanged is wrong if it changes very frequently.
For the video player I'm building I have a database of .mp4 video files created in Visual Studio's server explorer. The database has a single "Videos" table consisting of the following columns:
ArtistName,
SongTitle,
hddPath,
songDuration.
I have filled all except the songDuration column manually. I'm using a component for my video player which has a method that returns a song's duration after it has been loaded in a player I have set. Don't bother with the player, just bear in mind that the call component.getduration(hddPath), where hddPath is a string, returns a string in the following format: hh:mm:ss.
I can loop through the table rows and get the duration of each song in a for each statement:
DataTable dt = myDataSet.Tables["Videos"];
foreach(DataRow row in dt.Rows)
{
component.loadsound(0, row["hddPath"].ToString()); // 0 represents the index
// of the player
string duration = component.getduration(0); // gets the duration of the song
// loaded in player 0
}
But how do I update each row's "hddPath" column with the duration string and save it in my database?
I think that your question should actually read: "how do I update each row's songDuration column".
If that is the case, then have you tried:
row["songDuration"] = component.getduration(0);
and then outside of the loop:
yourDataAdapter.Update(dt);
There is more information on how to update records in the database here.
If you
have a DataAdapter associated with the DataSet
and have update commands associated with it (e.g., via a CommandBuilder instance)
and have a column in the DataTable for the duration (and assign the new value to it)
then you can send the updates to the database via the DataAdapter:
myDataAdapter.Update(myDataSet);
If you didn't use a DataAdapter to fill up the data set (which is what it sounds like from the OP), then it would also be possible to execute commands directly via an SqlCommand object. It might look something like the following statements. Note that you would want to simply update the parameter value in the loop and run the ExecuteNonQuery method each iteration (as opposed to creating a new command object each time). I'm unsure what the primary key (pk in the example) would be for your specific case. If the only fields are the ones shown in the OP, then I suspect it would the hddpath, since that sounds as if it would be unique.
SqlConnection myConn = new SqlConnection();
SqlCommand myCmd = myConn.CreateCommand();
myCmd.CommandText = "update thetable set duration = #duration where pk=#pk";
myCmd.CreateParameter();
SqlParameter duration = new SqlParameter("#duration", 1234);
myCmd.Parameters.Add(duration);
SqlParameter pk = new SqlParameter("#pk", 1);
myCmd.Parameters.Add(pk);
myCmd.ExecuteNonQuery();
There are a number of overloads for the SqlParameter objects. Pick the appropriate one.
Try something like this:
Create your update method something like this:
private void UpdateDurationofMyHddPath(string hdpath,string duration) //Add other parameters that you need
{
// Your ado.net update sql stuff
//Update yourColum Set duration=#duration where hddpath=#hdpath
}
Add Method on your loop:
DataTable dt = myDataSet.Tables["Videos"];
foreach(DataRow row in dt.Rows)
{
component.loadsound(0, row["hddPath"].ToString()); // 0 represents the index
// of the player
string duration = component.getduration(0); // gets the duration of the song
// loaded in player 0
string hdpath = row["hddPath"].ToString();
//Update hdpath duration
UpdateDurationofMyHddPath(hdpath,duration);
}
Regards