This works:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.OleDb;
public class MyClass
{
public static void Main()
{
OleDbConnection mySqlConnection =new OleDbConnection(#"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\data\nwind.Mdb");
OleDbCommand mySqlCommand = mySqlConnection.CreateCommand();
mySqlCommand.CommandText = "SELECT EmployeeID AS MappedID, FirstName, LastName " +
"FROM Employees AS Emp " +
"WHERE EmployeeID = 9";
OleDbDataAdapter mySqlDataAdapter = new OleDbDataAdapter();
mySqlDataAdapter.SelectCommand = mySqlCommand;
DataSet myDataSet = new DataSet();
mySqlConnection.Open();
mySqlDataAdapter.Fill(myDataSet, "Employees");
mySqlConnection.Close();
DataTableMapping myDataTableMapping = mySqlDataAdapter.TableMappings.Add("Employees", "dtEmployee");
myDataSet.Tables["Employees"].TableName = "dtEmployee";
Console.WriteLine("myDataTableMapping.DataSetTable = " + myDataTableMapping.DataSetTable);
Console.WriteLine("myDataTableMapping.SourceTable = " + myDataTableMapping.SourceTable);
myDataTableMapping.ColumnMappings.Add("EmployeeID", "MappedId");
DataTable myDataTable = myDataSet.Tables["dtEmployee"];
foreach (DataRow myDataRow in myDataTable.Rows)
{
Console.WriteLine("ID = " + myDataRow["MappedId"]);
Console.WriteLine("FirstName = " + myDataRow["FirstName"]);
Console.WriteLine("LastName = " + myDataRow["LastName"]);
}
Console.ReadLine();
}
}
Just change "MappedId" to something else like "NewMappedId":
myDataTableMapping.ColumnMappings.Add("EmployeeID", "NewMappedId");
Console.WriteLine("ID = " + myDataRow["NewMappedId"]);
to something else like "NewMappedId" and the program will crash at runtime saying NewMappedId doesn't belong to table dtEmployee. Is this a bug ?!
No bug here.
If you change the contents of a bound dataset, this error is normal since you no longer match the underlying schema you are bound to.
Related
I've declared 2 string variables:
string fname;
string lname;
When i wrote MySQL query in phpMyAdmin database:
SELECT workers.FNAME, workers.LNAME FROM project1.workers INNER JOIN
project1.order_status ON workers.ID_WORKER = order_status.ID_WORKER
INNER JOIN project1.orders ON orders.ID_ORDER = order_status.ID_ORDER
WHERE orders.ORDER_NUMBER = 'TEST' GROUP BY workers.FNAME, workers.LNAME
I've got 2 wokers:
-"Adam Gax" and
"Andrew Worm"
Then i'd like to store object from this query and to load that data to datagridview:
string query1 = string.Format("SELECT workers.FNAME, workers.LNAME FROM project1.workers INNER JOIN project1.order_status " +
"ON workers.ID_WORKER = order_status.ID_WORKER INNER JOIN project1.orders ON orders.ID_ORDER = order_status.ID_ORDER " +
"WHERE orders.ORDER_NUMBER = '"+ NrOrder +"' GROUP BY workers.FNAME, workers.LNAME");
SQLdata.connection.Open();
using (var command = new MySqlCommand(query1, SQLdata.connection))
{
using (var reader1 = command.ExecuteReader())
{
while (reader1.Read())
{
fname = Convert.ToString(reader1[0]);
lname = Convert.ToString(reader1[1]);
}
}
}
I've taken the breakpoints in lines of code in while loop and reads all FNAME's and LNAME's. Then it loads all data correctly. Next I want to load them to datagridview.
SQLdata.connection.Close();
sick_leaves x = new sick_leaves();
x.FNAME = fname;
x.LNAME = lname;
return x;
and bind them like this:
sick_leaves a = calculate_sickness_leaves(txt_NrOrder.Text);
cu = calculate_sickness_leaves(txt_NrOrder.Text);
var source = new BindingSource();
source.DataSource = cu;
dataGridView2.DataSource = source;
then using data from Orders.cs file:
public class sick_leaves
{
public string FNAME { get; set; }
public string LNAME { get; set; }
}
After compiling it in datagridview i have loaded only 1 Worker: "Andrew Worm". That should be that 2 workers, so it didn't load all data from sql query.
Now: How can I load all data from sql query to datagridview? Any ideas? Warning! I need help in Desktop Application
EDIT
I'd like to load that data with saving the code structure because i wanna to build that datagridview with calculating sickness, leaves times. (with TimeSpan object). Is that possible to write like that?
My codes:
GenerateOrder.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using MySql.Data.MySqlClient;
using System.Windows.Forms.DataVisualization.Charting;
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.IO;
using System.Diagnostics;
namespace ControlDataBase
{
public partial class GenerateChartsOfOrders : Form
{
string fname;
string lname;
sick_leaves cu = new sick_leaves();
public GenerateChartsOfOrders()
{
InitializeComponent();
}
public void loaddata2()
{
string connect = "datasource=localhost;port=3306;username=root;password=";
MySqlConnection connection = new MySqlConnection(connect);
connection.Open();
sick_leaves a = calculate_sickness_leaves(txt_NrOrder.Text);
cu = calculate_sickness_leaves(txt_NrOrder.Text);
var source = new BindingSource();
source.DataSource = cu;
dataGridView2.DataSource = source;
connection.Close();
}
private sick_leaves calculate_sickness_leaves(string NrOrder)
{
string query1 = string.Format("SELECT workers.FNAME, workers.LNAME FROM project1.workers INNER JOIN project1.order_status " +
"ON workers.ID_WORKER = order_status.ID_WORKER INNER JOIN project1.orders ON orders.ID_ORDER = order_status.ID_ORDER " +
"WHERE orders.ORDER_NUMBER = '"+ NrOrder +"' GROUP BY workers.FNAME, workers.LNAME");
SQLdata.connection.Open();
using (var command = new MySqlCommand(query1, SQLdata.connection))
{
using (var reader1 = command.ExecuteReader())
{
while (reader1.Read())
{
fname = Convert.ToString(reader1[0]);
lname = Convert.ToString(reader1[1]);
}
}
}
SQLdata.connection.Close();
sick_leaves x = new sick_leaves();
x.FNAME = fname;
x.LNAME = lname;
return x;
}
}
}
Orders.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ControlDataBase
{
public class sick_leaves
{
public string FNAME { get; set; }
public string LNAME { get; set; }
}
}
SQLData.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MySql;
using MySql.Data.MySqlClient;
namespace ControlDataBase
{
class SQLdata
{
public static MySqlConnection connection = new MySqlConnection
("datasource=localhost;port=3306;username=root;password=");
}
}
There are a few problems in the code:
You have defined fname and lname as fields of form.
In calculate_sickness_leaves You set value of those fields in while(reader1.Read())
At the end return a single sick_leaves object from calculate_sickness_leaves.
So basically, fname and lname will always contain first name and last name of the last row of your table, because of 1 and 2.
Your DataGridView will always show a single record, because of 3.
To solve the problem:
Remove fname and lname as you don't need them.
Change output type of calculate_sickness_leaves to IEnumerable<sick_leaves>.
In the while loop, when reading field values from data reader, create a new instance of sick_leaves yield return it.
Side-note
Always use parametrized queries to prevent a SQL Injection.
Always use using statement when working with disposable objects like connection.
If you are interested to work with typed entity objects, then you may want to take a look at MySQL Connector for Entity Framework.
Example
You can find a lot of examples about loading data into DataTable or using DataReader. Anyway I'll share two more examples here, showing you how you can get data from MySql and convert to a a list of a specific type.
In the following examples, I assume you have an Employee class like this:
public class Employee
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
Example 1 - Using DataAdapter, DataTable and Select extension method
public IEnumerable<Employee> GetEmployees()
{
string connectionString = "CONNECTION STRING";
string commandText = "COMMAND TEXT";
DataTable table = new DataTable();
using (var adapter = new MySqlDataAdapter(commandText , connectionString))
adapter.Fill(table);
return table.AsEnumerable().Select(x => new Employee()
{
FirstName = x.Field<string>("FirstName"),
LastName = x.Field<string>("LastName")
});
}
Example 2 - Using DataReader and yield return new Employee
public IEnumerable<Employee> GetEmployees()
{
string connectionString = "CONNECTION STRING";
string commandText = "COMMAND TEXT";
using (var connection = new MySqlConnection(connectionString))
{
connection.Open();
using (var command = new MySqlCommand(commandText, connection))
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
yield return new Employee()
{
FirstName = reader.GetFieldValue<string>(0),
LastName = reader.GetFieldValue<string>(1)
};
}
}
}
}
}
You can use either of above method like this:
bindingSource.DataSource = GetEmployees();
dataGridView.DataSource = bindingSource;
This might help
private void GetData(string selectCommand)
{
try
{
// Specify a connection string.
// Replace <SQL Server> with the SQL Server for your Northwind sample database.
// Replace "Integrated Security=True" with user login information if necessary.
String connectionString =
"Data Source=<SQL Server>;Initial Catalog=Northwind;" +
"Integrated Security=True";
// Create a new data adapter based on the specified query.
dataAdapter = new SqlDataAdapter(selectCommand, connectionString);
// Create a command builder to generate SQL update, insert, and
// delete commands based on selectCommand.
SqlCommandBuilder commandBuilder = new SqlCommandBuilder(dataAdapter);
// Populate a new data table and bind it to the BindingSource.
DataTable table = new DataTable
{
Locale = CultureInfo.InvariantCulture
};
dataAdapter.Fill(table);
bindingSource1.DataSource = table;
// Resize the DataGridView columns to fit the newly loaded content.
dataGridView1.AutoResizeColumns(
DataGridViewAutoSizeColumnsMode.AllCellsExceptHeader);
}
catch (SqlException)
{
MessageBox.Show("To run this example, replace the value of the " +
"connectionString variable with a connection string that is " +
"valid for your system.");
}
}
C# data access layer (simplified example with only 1 sub in DAl.cs in this example):
Using System.Data.SqlClient;
Public Class DAL
{
Public Static void GetQueryResults(String cmdText)
{
SqlConnection oConn = New SqlConnection();
oConn.ConnectionString = MainW.MyConnection; // get connection string
SqlCommand cmd = New SqlCommand(cmdText, oConn);
DataSet ds = New DataSet();
SqlDataAdapter da = New SqlDataAdapter(cmd);
Try
{
oConn.Open();
da.Fill(ds); // retrive data
oConn.Close();
}
Catch (Exception ex)
{
SysErrScreen errform = New SysErrScreen();
errform.ChybaText.Text = ex.Message + Constants.vbCrLf + Constants.vbCrLf + cmdText;
errform.ShowDialog();
oConn.Close();
}
Return ds;
}
}
Same in VB.NET:
Imports System.Data.SqlClient
Public Class DAL
Public Shared Function GetQueryResults(cmdText As String)
Dim oConn As New SqlConnection
oConn.ConnectionString = MainW.MyConnection ' get connection string
Dim cmd As New SqlCommand(cmdText, oConn)
Dim ds As New DataSet()
Dim da As New SqlDataAdapter(cmd)
Try
oConn.Open()
da.Fill(ds) ' retrive data
oConn.Close()
Catch ex As Exception
Dim errform As New SysErrScreen
errform.ChybaText.Text = ex.Message & vbCrLf & vbCrLf & cmdText
errform.ShowDialog()
oConn.Close()
End Try
Return ds
End Function
End Class
Note, that I defined a ConnectionString elsewhere (MainW.MyConnection), where you can set it for all application. You'd usually retrieve it during start-up from some settings (file, application variable).
Then I'ts easy to use it over and over (C#):
Private void FillDGV()
{
String cmdText = "SELECT workers.FNAME, workers.LNAME FROM project1.workers INNER JOIN project1.order_status " +
"ON workers.ID_WORKER = order_status.ID_WORKER INNER JOIN project1.orders ON orders.ID_ORDER = order_status.ID_ORDER " +
"WHERE orders.ORDER_NUMBER = '" + NrOrder + "' GROUP BY workers.FNAME, workers.LNAME\"; ";
DataSet ds;
ds = DAL.GetQueryResults(cmdText);
DataTable dt;
if (ds.Tables.Count > 0)
{
dt = ds.Tables(0);
this.DataGridView1.DataSource = dt; // fill DataGridView
}
}
VB.NET:
Private Sub FillDGV()
Dim cmdText As String = "SELECT workers.FNAME, workers.LNAME FROM project1.workers INNER JOIN project1.order_status " +
"ON workers.ID_WORKER = order_status.ID_WORKER INNER JOIN project1.orders ON orders.ID_ORDER = order_status.ID_ORDER " +
"WHERE orders.ORDER_NUMBER = '" & NrOrder & "' GROUP BY workers.FNAME, workers.LNAME""; "
Dim ds As DataSet
ds = DAL.GetQueryResults(cmdText)
Dim dt As DataTable
If ds.Tables.Count > 0 Then
dt = ds.Tables(0)
Me.DataGridView1.DataSource = dt ' fill DataGridView
End If
End Sub
Note, that I used DataTable as a data object, between DataSet and DataGridView. It's good to get in habit to use it (unless other more advanced ways are used) due to number of reasons. One major is, that it won't earase your DataGridView GUI-defined columns, if the DataSet table happens to be empty. You can also perform client-side data operations way more productively and reliably on DataTable, then on DataGridView.
One can also consider, if he should use BindingSource, rather then a DataTable. It's implementation works very similarly to DataTable, so if you get this example working, you can then switch to BindingSource, if you need it.
Another consideration is to use parametric queries. If you (your users) operate your desktop application in closed environment, then it's OK. However with exposed applications you can be sure you'll get some SQL injection attacks.
This code works for me when downloading data from SQL database and presening it in a DataGridView:
string connectionString;
String sql = "";
SqlConnection cnn;
sql = "SELECT workers.FNAME, workers.LNAME FROM project1.workers INNER JOIN project1.order_status " +
"ON workers.ID_WORKER = order_status.ID_WORKER INNER JOIN project1.orders ON orders.ID_ORDER = order_status.ID_ORDER " +
"WHERE orders.ORDER_NUMBER = '"+ NrOrder +"' GROUP BY workers.FNAME, workers.LNAME"";
connectionString = #"datasource=localhost;port=3306;username=root;password=";
cnn = new SqlConnection(connectionString);
cnn.Open();
SqlDataAdapter dataadapter = new SqlDataAdapter(sql, cnn);
DataSet ds = new DataSet();
dataadapter.Fill(ds, "workers");
dataGridView1.DataSource = ds;
dataGridView1.DataMember = "workers";
cnn.Close();
I need to load data from multiple excel files to single table in sql server. But, I may get different headers in different files. Also, no of columns in excel will be less when compared to table. So, I'm trying to take columns from excel files and comparing against system table in database to get the corresponding column name. I'm using this inside a script task in SSIS package. Please see the code and sample data given below. Getting an error while doing column mapping.
Name EmpId Salary
Anna PD200 200
Julie PD300 300
Name EmpId Sal
Maria PD400 400
Treeza PD500 500
CREATE TABLE [dbo].[testLoad]
(
[Name] [nvarchar](255) NULL,
[EmpId] [nvarchar](255) NULL,
[Salary] [nvarchar](50) NULL
)
public void Main()
{
// TODO: Add your code here
string filepath = Dts.Variables["User::var_File_Path"].Value.ToString();
string tablename = Dts.Variables["User::var_Tbl_Name"].Value.ToString();
string filename = Dts.Variables["User::var_File_Name"].Value.ToString();
string tbl = tablename.Replace("[", "");
tbl = tbl.Replace("]", "");
tbl = tbl.Replace("dbo.", "");
SqlConnection sqlconnection = new SqlConnection();
sqlconnection = (SqlConnection)(Dts.Connections["ADOAUDIT"].AcquireConnection(Dts.Transaction));
string ConStr;
string HDR;
HDR = "YES";
ConStr = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=" + filepath + "; Extended Properties=\"EXCEL 12.0 XML; HDR="+HDR+"\";";
OleDbConnection cnn = new OleDbConnection(ConStr);
cnn.Open();
DataTable dtSheet = cnn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
string sheetname = "";
string ExcelColumn = "";
string SqlColumn = "";
string SqlColumns = "";
string ExcelCol = "";
string query = "";
string querycol = "";
foreach (DataRow drSheet in dtSheet.Rows)
{
sheetname = drSheet["TABLE_NAME"].ToString();
OleDbCommand oconn = new OleDbCommand(" top 1 * from [" + sheetname + "]", cnn);
OleDbDataAdapter adp = new OleDbDataAdapter(oconn);
DataTable dt = new DataTable();
adp.Fill(dt);
cnn.Close();
for (int i = 0; i < dt.Columns.Count; i++)
{
ExcelCol = dt.Columns[i].ColumnName;
ExcelCol = ExcelCol.Substring(0, 5);
querycol = "select COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS " +
"where TABLE_NAME = '" + tbl + "' " +
"and COLUMN_NAME like '" + ExcelCol + "%'";
SqlCommand sqlCommand = new SqlCommand(querycol, sqlconnection);
SqlColumn = (string)sqlCommand.ExecuteScalar();
if (!String.IsNullOrEmpty(SqlColumn))
{
SqlColumns = SqlColumns + "'" + SqlColumn + "',";
ExcelColumn = ExcelColumn + "'" + dt.Columns[i].ColumnName + "',";
}
}
SqlColumns = SqlColumns.TrimEnd(',');
ExcelColumn = ExcelColumn.TrimEnd(',');
query = "select " + ExcelColumn + " from [" + sheetname + "]";
OleDbConnection conn1 = new OleDbConnection(ConStr);
conn1.Open();
OleDbCommand oconn1 = new OleDbCommand(query, conn1);
OleDbDataAdapter adp1 = new OleDbDataAdapter(oconn1);
DataTable dt1 = new DataTable();
adp1.Fill(dt1);
conn1.Close();
//Load Data from DataTable to SQL Server Table.
using (SqlBulkCopy BC = new SqlBulkCopy(sqlconnection))
{
BC.DestinationTableName = tablename;
foreach (var column in dt1.Columns)
{
BC.ColumnMappings.Add(column.ToString(), SqlColumns.ToString());
}
BC.WriteToServer(dt);
}
sqlconnection.Close();
}
Dts.TaskResult = (int)ScriptResults.Success;
}
#region ScriptResults declaration
/// <summary>
/// This enum provides a convenient shorthand within the scope of this class for setting the
/// result of the script.
///
/// This code was generated automatically.
/// </summary>
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
#endregion
}
Thank You
Julie
Wow, this is going to be a pain to setup and maintain. Here is a way to merge 2 Excel files into 1.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Excel = Microsoft.Office.Interop.Excel;
using System.Reflection;
namespace WindowsFormsApplication5
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Excel.Application app = new Excel.Application();
app.Visible = true;
app.Workbooks.Add("");
app.Workbooks.Add(#"C:\Users\Excel\Desktop\excel_files\Book1.xlsx");
app.Workbooks.Add(#"C:\Users\Excel\Desktop\excel_files\Book2.xlsx");
for (int i = 2; i <= app.Workbooks.Count; i++)
{
int count = app.Workbooks[i].Worksheets.Count;
app.Workbooks[i].Activate();
for (int j = 1; j <= count; j++)
{
Excel._Worksheet ws = (Excel._Worksheet)app.Workbooks[i].Worksheets[j];
ws.Select(Type.Missing);
ws.Cells.Select();
Excel.Range sel = (Excel.Range)app.Selection;
sel.Copy(Type.Missing);
Excel._Worksheet sheet = (Excel._Worksheet)app.Workbooks[1].Worksheets.Add(
Type.Missing, Type.Missing, Type.Missing, Type.Missing
);
sheet.Paste(Type.Missing, Type.Missing);
}
}
}
}
}
If I were you, I would not use C# for this kind of thing. I think you are better off using VBA, to push the date from each Excel file into SQL Server. Here are some options for you to consider.
https://www.excel-sql-server.com/excel-sql-server-import-export-using-vba.htm#Introduction
Or, used SQL to go grab the data out of the excel files and load everything into SQL Server.
SELECT *
FROM OPENROWSET(
'Microsoft.ACE.OLEDB.12.0',
'Excel 8.0;HDR=NO;Database=T:\temp\Test.xlsx',
'select * from [sheet1$]')
Or, even consider using a 3rd party resource to merge all excel files into 1, and then load that into SQL Server. Here is an example of what I'm talking about.
https://www.rondebruin.nl/win/addins/rdbmerge.htm
I have two methods that will run after a button click, bgEqptRec() and receiveHeader(). The bgEqptRec() contains the recieveHeader() who set the column header title. But it cannot set due to index was out of range. I'm pretty sure that I'm using the right number of the index from SQL Server. Here's the code:
private void btnSearch_Click(object sender, EventArgs e)
{
bgEqptRec();
}
private void bgEqptRec()
{
receiveHeader();
gvSearch.DataSource = null;
using (var connect = connection.getConnection())
{
using (SqlCommand cmd = new SqlCommand("SELECT * FROM receive WHERE rec_stat='IN' AND rec_date BETWEEN '" + dtpFrom.Text + "' AND '" + dtpTo.Text + "'"))
{
cmd.Connection = connect;
cmd.CommandType = CommandType.Text;
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
using (DataTable dt = new DataTable())
{
da.Fill(dt);
gvSearch.DataSource = dt;
}
}
}
}
}
private void receiveHeader()
{
gvSearch.Columns[0].HeaderText = "Supplier";
gvSearch.Columns[1].HeaderText = "Invoice";
gvSearch.Columns[2].HeaderText = "Brand";
gvSearch.Columns[3].HeaderText = "Model";
gvSearch.Columns[4].HeaderText = "Equipment";
gvSearch.Columns[5].HeaderText = "Serial No.";
gvSearch.Columns[6].HeaderText = "Price";
gvSearch.Columns[7].HeaderText = "PO No.";
gvSearch.Columns[8].HeaderText = "Release Date";
gvSearch.Columns[9].HeaderText = "Release By";
gvSearch.Columns[10].HeaderText = "Status";
}
The error given by VS was "Index was out of range. Must be non-negative and less than the size of the collection."
Hope that the issue is that: at the Time of calling the receiveHeader(); method the dataSource of the grid is either null or few columns less that 11, as you are taking Columns[10]. So I suggest you to call the method after assigning the DataSource for the Grid. Make sure that the query returns at least 11 columns. Which means the code will be like this:
using (var connect = connection.getConnection())
{
using (SqlCommand cmd = new SqlCommand("SELECT * FROM receive WHERE rec_stat='IN' AND rec_date BETWEEN '" + dtpFrom.Text + "' AND '" + dtpTo.Text + "'"))
{
// rest of code
gvSearch.DataSource = dt;
}
}
// call the method here since the grid is populated
receiveHeader();
I am trying to pass a protected DataRow[] msgArray; from code-behind to the .net page.
msgArray contains rows from a DB table that I selected, when I do Response.Write(msgArray[0]["comment"]) it outputs correctly what I have stored in the comment column in my DB.
The problem is that I cannot do the same in my .net page when I load the page where I do this:
<asp:Panel ID="commentSection" runat="server">
<%= msgArray[0]["comment"] %>
</asp:Panel>
I get a Object reference not set to an instance of an object.
What am I doing wrong ?
This is my code-behind(.cs) :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using MySql.Data.MySqlClient;
namespace Groups
{
public partial class Group : System.Web.UI.Page
{
MySql.Data.MySqlClient.MySqlConnection conn;
MySql.Data.MySqlClient.MySqlCommand cmd;
MySql.Data.MySqlClient.MySqlDataReader reader;
String queryStr;
String gname;
String gtype;
String uname;
DataTable group = new DataTable();
DataTable msg = new DataTable();
protected DataRow[] msgArray;
protected void Page_Load(object sender, EventArgs e)
{
String id = Request.QueryString["id"];
if (id != null)
{
String connString = System.Configuration.ConfigurationManager.ConnectionStrings["GroupsConnString"].ToString();
conn = new MySql.Data.MySqlClient.MySqlConnection(connString);
conn.Open();
queryStr = "SELECT g.*, (SELECT COUNT(id) FROM app_groups.users_groups_leg ugl WHERE ugl.id_group = g.id) as member_count FROM app_groups.groups g WHERE g.id = " + id;
cmd = new MySql.Data.MySqlClient.MySqlCommand(queryStr, conn);
group.Load(reader = cmd.ExecuteReader());
var groupArray = group.AsEnumerable().ToArray();
reader.Close();
int member_count = 0;
int.TryParse(groupArray[0]["member_count"].ToString(), out member_count);
Panel grInfo = new Panel();
grInfo.Controls.Add(new LiteralControl("<br/><div class='panel panel-primary'><div class='panel-heading'><h2>" + groupArray[0]["group_name"] + "</h2></div><div class='panel-body'><span>Categorie: <span class='title'>" + groupArray[0]["group_type"] + "</span></span><br/><span class='membrii'>" + (member_count == 1 ? member_count + " membru" : member_count + " membri") + "</span><br/><span>Fondat pe: " + ConvertUnixTimeStamp(groupArray[0]["founded"].ToString()) + "</span><br/></div></div>"));
groupInfo.Controls.Add(grInfo);
conn.Close();
showComments();
}
}
public static DateTime? ConvertUnixTimeStamp(string unixTimeStamp)
{
return new DateTime(1970, 1, 1).AddSeconds(Convert.ToDouble(unixTimeStamp) + 3600*2);
}
public DataRow[] showComments()
{
String id = Request.QueryString["id"];
if (id != null)
{
String connString = System.Configuration.ConfigurationManager.ConnectionStrings["GroupsConnString"].ToString();
conn = new MySql.Data.MySqlClient.MySqlConnection(connString);
conn.Open();
queryStr = "SELECT gc.* FROM app_groups.group_comments gc WHERE gc.id_group = " + id;
cmd = new MySql.Data.MySqlClient.MySqlCommand(queryStr, conn);
msg.Load(reader = cmd.ExecuteReader());
msgArray = msg.AsEnumerable().ToArray();
reader.Close();
Response.Write(msgArray[0]["comment"]);
/*Panel grComments = new Panel();
grComments.Controls.Add(new LiteralControl(""));
groupInfo.Controls.Add(grComments);*/
}
return msgArray;
}
}
}
Create a new class dataAccess.cs
using System;
using System.Data;
namespace Groups
{
public class dataAccess
{
public List<string> GetComments()
{
String connString = System.Configuration.ConfigurationManager.ConnectionStrings["GroupsConnString"].ToString();
conn = new MySql.Data.MySqlClient.MySqlConnection(connString);
try
{
MySql.Data.MySqlClient.MySqlDataReader reader;
DataTable msg = new DataTable();
conn.Open();
List<string> comments = new List<string>();
queryStr = "SELECT gc.* FROM app_groups.group_comments gc WHERE gc.id_group = " + id;
cmd = new MySql.Data.MySqlClient.MySqlCommand(queryStr, conn);
msg.Load(reader = cmd.ExecuteReader());
foreach(DataRow dr in msg.Rows)
{
comments.Add(dr["comment"]);
}
reader.Close();
return comments;
}
catch (Exception ex)
{
//throw ex;
}
}
}
}
In the ASPX page
<asp:Panel ID="commentSection" runat="server">
<%
var data = Groups.dataAccess.GetComments();
foreach(string c in data)
{
Response.Write("<p>" + c + "</p>");
}
%>
</asp:Panel>
According to ASP.NET Page Life cycle, your method showComments() will be called after the <%= msgArray[0]["comment"] %> part. Hence it won't be available there.
Best way is to have a control like Label in your .aspx page and update the text property from showComments() method.
I'm populating the following WPF datagrid:
Using the following method:
private void ButtonFilterWorkflowWhenClick(object sender, RoutedEventArgs e)
{
var db = new DatabaseHandle();
dataGridWorkflow.ItemsSource = db.DisplayHealthIndicator(DateTime.Now, DateTime.Now);
labelWorkflowLastLoaded.Content = "Last Loaded at " + DateTime.Now.ToString(CultureInfo.InvariantCulture) + " with " +
dataGridWorkflow.Items.Count.ToString(CultureInfo.InvariantCulture) + " total events.";
}
Which references the following class object:
public DataView DisplayHealthIndicator(DateTime startDate, DateTime endDate)
{
string queryString = "[marlin].[support_retrieve_workflow_history]";
using (SqlConnection connection = new SqlConnection(GetConnectionString()))
{
using (var cmd = new SqlCommand(queryString, connection))
{
connection.Open();
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("date_from", startDate.Date);
cmd.Parameters.AddWithValue("date_to", endDate.Date);
var reader = cmd.ExecuteReader();
var dt = new DataTable();
dt.Load(reader);
connection.Close();
return dt.DefaultView;
}
}
}
I'm trying to find a way that I can find the sum of the total column so I can add it to my label but having no success. I can do this with a second query but I'd like to avoid that wherever possible. How should I approach this problem?
You may have to enumerate the rows in your DataView, something like:
dataGridWorkflow.ItemsSource = db.DisplayHealthIndicator(DateTime.Now, DateTime.Now);
DataView dv = (DataView)dataGridWorkflow.ItemsSource;
DataRowCollection drc = dv.Table.Rows;
IEnumerator rowEnum = drc.GetEnumerator();
int sum = 0;
while (rowEnum.MoveNext())
{
sum += (int)((DataRow)rowEnum.Current)[3];//assuming the 'Total' column has index 3.
}
labelWorkflowLastLoaded.Content = "Last Loaded at " + DateTime.Now.ToString(CultureInfo.InvariantCulture) + " with " + sum.ToString(CultureInfo.InvariantCulture) + " total events.";
Edit: I changed it so that you should be able to just copy and paste into your code.