I need to insert values in a table that have different columns from time to time. The columns and row data are updated from MySql. Each row values are in single MySql cells with the following format:
ColumnName{Delimiter}Value{BigDelimiter}Column2Name{Delimiter}Value2...
So I split the cell strings to get the column header and value, as the user can rearrange columns, modify, delete or insert new ones. I searched for a solution, though I get nothing but empty rows:
private void GetDataTableValues()
{
if (dtData.Value != null)
{
try
{
LoadFields();
dgwDataMain.Items.Clear();
dgwDataMain.Columns.Clear();
foreach (Fields field in fields)
{
DataGridTextColumn column = new DataGridTextColumn();
column.Header = field.name;
column.Binding = new Binding(field.name);
dgwDataMain.Columns.Add(column);
}
if (connection.State == System.Data.ConnectionState.Broken || connection.State == System.Data.ConnectionState.Closed)
connection.Open();
command.Parameters.Clear();
DateTime dt = dtData.Value ?? DateTime.Now;
command.Parameters.Add("#date", MySqlDbType.Date, 50).Value = dt.ToString("yyyy-MM-dd");
command.CommandText = "SELECT value,team FROM sessions WHERE date=#date";
List<string> teams = new List<string>();
foreach (Control ctrl in panDataFilter.Children)
if ((ctrl as CheckBox).IsChecked == true)
teams.Add(Convert.ToString((ctrl as CheckBox).Content));
using (MySqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
bool v = false;
if (teams.Contains(reader[1].ToString()) || teams.Count == 0)
v = true;
if (v)
{
DatabaseObject obj = new DatabaseObject();
List<string> str2 = new List<string>(reader[0].ToString().Split(new string[] { "</s&p>" }, StringSplitOptions.None).ToList());
obj.Items = new List<string>(str2.Count);
foreach (string str in str2)
{
List<string> item = new List<string>(str.Split(new string[] { "<&p>" }, StringSplitOptions.None).ToList());
int index = dgwDataMain.Columns.Single(c => c.Header.ToString() == item[0].ToString()).DisplayIndex;
obj.Items.Insert(index, item[1].ToString());
}
dgwDataMain.Items.Add(obj);
}
}
}
}
catch (MySqlException ex)
{
MessageBox.Show(ex.ErrorCode.ToString() + ": " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Exclamation);
}
}
}
public class DatabaseObject
{
public List<string> Items = new List<string>();
}
to delete extra row from datagrid is, just make property...
Canuseraddrows="false";
Please use Observablecollection to bind the data grid. By using observablecollection easily you can add or delete item and not required to reset the data source of data grid.
Sample Code:
observableCollection myClass = new
observableCollection();
myClass.add(Class)
Related
hello i am currently having search button on my form and i want to search is between 2 date and i want to have a alert message if i have 2 same record on other column this is my code for now
SqlConnection sqlCon = new SqlConnection(ConnectionString);
if (sqlCon.State == ConnectionState.Closed)
sqlCon.Open();
SqlDataAdapter sqlData = new SqlDataAdapter("DateFilter", sqlCon);
sqlData.SelectCommand.CommandType = CommandType.StoredProcedure;
sqlData.SelectCommand.Parameters.AddWithValue("#Date", TxtFromDate.Text);
sqlData.SelectCommand.Parameters.AddWithValue("#Date2", TxtToDate.Text);
DataTable dtbl = new DataTable();
sqlData.Fill(dtbl);
sqlCon.Close();
Gridview1.DataSource = dtbl;
Gridview1.DataBind();
Gridview1.UseAccessibleHeader = true;
Gridview1.HeaderRow.TableSection = TableRowSection.TableHeader;
It is really hard decrypting your question. It seems you have an existing SQL result in your DataGridView and then want to check via a button if there are multiple entries with the same "CreatedDate" value.
(1) You should use defined objects in order to be able to work with object items instead of DataTable row/column indexes which is a hassle.
Therefore you need to define your object, map your DataTable rows as objects items in a collection (here: a simple List<>) and then set this collection to your DataGridView.DataSource, e.g.:
// define single object
public class FinishedGood {
public int ID { get; set; }
public DateTime CreatedDate { get; set; }
...
}
// define object collection
public class FinishedGoods : List<FinishedGood> { }
// execute your existing SQL query and fill the DataTable
...
// convert DataTable to FinishedGoods
FinishedGoods finishedGoods = new FinishedGoods();
foreach (DataRow row in dtbl.Rows) {
finishedGoods.Add(new FinishedGood() {
ID = Convert.ToInt32(row["ID"]),
CreatedDate = DateTime.Parse(row["CreatedDate"].ToString());,
...
});
}
// set the collection as datasource
gv.DataSource = finishedGoods;
(2) Now, you can check the DataSource for duplicates via Linq:
using System.Linq;
private HashSet<FinishedGood> CheckForDuplicateCreatedDates() {
HashSet<FinishedGood> result = new HashSet<FinishedGood>();
// collect all createdDates
HashSet<DateTime> createdDates = new HashSet<DateTime>();
foreach (FinishedGood finishedGood in gv.DataSource){
if (!createdDates.Contains(finishedGood.createdDate)) {
createdDates.Add(finishedGood.createdDate);
}
}
// loop through all createdDates
foreach (DateTime createdDate in createdDates) {
// check if there are more than 2 entries with the createdDate in your DataSource
if (gv.DataSource.Count(x => x.CreatedDate == createdDate) > 2) {
// add those entries to your duplicate result list
foreach (FinishedGood finishedGood in gv.DataSource.Where(x => x.CreatedDate == createdDate)) {
result.Add(finishedGood);
}
}
}
return result;
}
(3) To show the alert popup, you can use MessageBox.Show().
(4) To highlight the corresponding rows in the DataGridview, you can use the result of (2) to find the corresponding row indexes and then adjust their DefaultCellStyle.
The button click would look something like this:
private void buttonCheck_Click(object sender, EventArgs e) {
// get duplicates
HashSet<FinishedGood> duplicates = CheckForDuplicateCreatedDates();
if (duplicates.Count() > 0) {
// show alert popup
MessageBox.Show("Duplicates found");
// highlight the corresponding rows
foreach (DataGridViewRow row in gv.Rows) {
if (duplicates.Contains((row.DataBoundItem as FinishedGood))) {
row.DefaultCellStyle.BackColor = Color.DarkRed;
row.DefaultCellStyle.ForeColor = Color.White;
}
}
}
}
I'm trying to insert some values into the database using reflection. Here is my code, query works well, but how to pass values? I don't know what went wrong:
public class MyORM<T> where T : IData
{
public void Insert(T item)
{
var sql = new StringBuilder("Insert into ");
var type = item.GetType();
var properties = type.GetProperties();
sql.Append(type.Name);
sql.Append(" (");
foreach (var property in properties)
{
sql.Append(property.Name);
sql.Append(", ");
}
sql.Remove(sql.Length - 1, 1);
sql.Append(") values (");
foreach (var property in properties)
{
sql.Append('#').Append(property.Name).Append(',');
}
sql.Remove(sql.Length - 1, 1);
sql.Append(");");
var query = sql.ToString();
var command = new SqlCommand(query, _sqlConnection);
foreach (var property in properties)
{
command.Parameters.Add(property.Name);
}
}
}
command.Parameters.AddWithValue(property.Name, property.GetValue(item));
This line will solve your problem and will be able to pass the value.
public void DBInsertNewRecordIntoTable(DatabaseTableObject databaseTableObject, string tableName)
{
string connectMe = "Server=localhost;User ID=root;Database=test";
string sqlCommand = string.Concat("SELECT * FROM ", tableName, " LIMIT 0;");
//1. Get an instance of MySqlAdapter
MySqlDataAdapter mySqlDataAdapter = new MySqlDataAdapter(sqlCommand, connectMe);
//2. Retrieve schema from tableName and store it in DataSet
DataSet dataSet = new DataSet(string.Concat(tableName, "DataSet"));
mySqlDataAdapter.FillSchema(dataSet, SchemaType.Source, tableName);
//5. Get dataTable from dataSet
DataTable dataTable = dataSet.Tables[tableName];
//6. Add new row data
DataRow dataRow = dataTable.NewRow();
//6.1 Get a list of the properties in the databaseTableObject and store it into an array
PropertyInfo[] properties = databaseTableObject.GetType().GetProperties();
//6.2 Loop through all properties in databaseTableObject and assign their values to dataRow accordingly
foreach (var property in properties)
{ //6.3 Getting property value
var propertyValue = databaseTableObject.GetType().GetProperty(property.Name).GetValue(databaseTableObject, null);
//6.4 Only assign value to dataRow if databaseTableObject's property's value is not null
if (propertyValue != null)
dataRow[property.Name] = propertyValue;
}
//7. Add dataRow data to local table
dataTable.Rows.Add(dataRow);
//8. Apply the change to remote table
_ = new MySqlCommandBuilder(mySqlDataAdapter);
mySqlDataAdapter.Update(dataSet, tableName);
Console.WriteLine("Successfully updated the remote table");
}
interface DatabaseTableObject { }
public class DatabaseTableObjectEmployee: DatabaseTableObject
{
private string name;
private int? age = null;
private int? salary = null;
public int? Age { get => age; set => age = value; }
public int? Salary { get => salary; set => salary = value; }
public string Name { get => name; set => name = value; }
}
You can add property.GetValue(entity) in your iteration to get value and store it in a dictionary to pass it and use it as a parameter.Here my code.I have implemented it.Hope this will help.
public void Insert(TEntity entity)
{
if (entity == null) return;
Type type = entity.GetType();
PropertyInfo[] propertyInfos = type.GetProperties(); `
string s1 = "", s2 = "";
bool flag = false;
`Dictionary<string, object> dic = new Dictionary<string, object>();`
foreach (var property in propertyInfos)
{
Type type1 = property .GetType();
if (!flag)
flag = true;
else {
s1 += ",";
s2 += ",";
}
s1 += property .Name;
s2 += "#" + property .Name;
dic.Add(property .Name, property.GetValue(entity));//Here getting value
} `
`string sql = "Insert into " + type.Name + " (" + s1 + ") Values (" + s2 + ");";`
` ExecuteCommand(sql, dic);`
}```
//`Database Execution portion`
`public void ExecuteCommand(string command, Dictionary<string, object> parameters)`
{
using(SqlConnection connection = new SqlConnection(_conncectionstring))
{
using(SqlCommand sqlcommand = new SqlCommand(command, connection))
{
try
{
if (connection.State != ConnectionState.Open)
{
connection.Open();
}
if (parameters != null)
{
foreach (var item in parameters)
{
sqlcommand.Parameters.Add(new SqlParameter(item.Key, item.Value));
}
}
sqlcommand.ExecuteNonQuery();
}
catch (Exception ex) {
}
}
}
}`
I get an error 'this row already belongs to this table' from the following code:
public static DataTable AddNewAllocations(string pCaseNo, ref DataTable pTable)
{
try
{
string sqlText = "SELECT UserID FROM tblUsers;";
aSqlQuery aQ = new aSqlQuery(sqlText, "table");
DataTable userTable = aQ.TableResult;
foreach (DataRow userRow in userTable.Rows)
{
int allocAlready = 0;
foreach (DataRow allocRow in pTable.Rows)
{
if (allocRow["FeeEarner"].ToString() == userRow["UserID"].ToString())
{
allocAlready = 1;
}
}
if (allocAlready == 0)
{
string strUser = userRow["UserID"].ToString();
decimal fees = cTimesheet.UserFees(strUser, pCaseNo);
int intCaseNo = Int32.Parse(pCaseNo);
if (fees > 0)
{
Object[] array = new object[8];
array[0] = 0;
array[1] = intCaseNo;
array[2] = DateTime.Today;
array[3] = strUser;
array[4] = fees;
array[5] = 0;
array[6] = fees;
array[7] = true;
pTable.Rows.Add(array);
}
}
}
return pTable;
}
catch (Exception eX)
{
throw new Exception("cAllocation: Error in NewAllocations()" + Environment.NewLine + eX.Message);
}
When I step through the code I can see that the error is thrown on the second occasion the following line is accessed:
pTable.Rows.Add(array);
Given that I create a new object array each time the code enters the loop, I fail to see why I am receiving this error message, which suggests to me the same row is being added multiple times. Why does the code see each loop as adding the same datarow when the row is generated by a new object array each time?
Another approach is to create a NewRow() at the beginning of the loop, assign its data, then Rows.Add() at the bottom of the loop.
{
// initialization code
// ...
foreach (DataRow row in dt.Rows)
{
row.Delete();
}
Oda.Update(ds, "USERTABLE");
DataRow dr;
foreach (var userRecord in urList)
{
dr = dt.NewRow();
dr["username"] = userRecord.userName;
dr["firstname"] = userRecord.firstName;
dr["lastname"] = userRecord.lastName;
dr["createdon"] = userRecord.createdOn;
dt.Rows.Add(dr);
}
Oda.Update(ds, "USERTABLE");
}
The code that finally worked was this:
public static DataTable AddNewAllocations(string pCaseNo, DataTable pTable)
{
try
{
DataTable newTable = NewAllocationTable();
string sqlText = "SELECT UserID FROM tblUsers;";
aSqlQuery aQ = new aSqlQuery(sqlText, "table");
DataTable userTable = aQ.TableResult;
foreach (DataRow userRow in userTable.Rows)
{
int allocAlready = 0;
foreach (DataRow allocRow in pTable.Rows)
{
if (allocRow["FeeEarner"].ToString() == userRow["UserID"].ToString())
{
allocAlready = 1;
}
}
if (allocAlready == 0)
{
string strUser = userRow["UserID"].ToString();
decimal fees = cTimesheet.UserFees(strUser, pCaseNo);
int intCaseNo = Int32.Parse(pCaseNo);
if (fees > 0)
{
Object[] array = new object[8];
array[0] = 0;
array[1] = intCaseNo;
array[2] = DateTime.Today;
array[3] = strUser;
array[4] = fees;
array[5] = 0;
array[6] = fees;
array[7] = true;
newTable.Rows.Add(array);
}
}
}
foreach (DataRow row in pTable.Rows)
{
newTable.ImportRow(row);
}
newTable.DefaultView.Sort = "AllocID";
return newTable;
}
catch (Exception eX)
{
throw new Exception("cAllocation: Error in NewAllocations()" + Environment.NewLine + eX.Message);
}
}
I think the key was using ImportRow rather than Rows.Add. I still use Rows.Add in my method but only when adding rows to a newly created table. I then loop through the existing table which was passed in as a paramater, and use ImportRow to add each row of the paramater table, to the newly created one. I then pass the new combined table out in my return statement, rather than a modified parameter table.
I want to set value to a literal control using LINQ. I got the result from database in var by the following code:
var result=md.StoredProc_Name(id);
Now I want to assign particular columns value to a literal. As we can do simply in asp.net as bellow with the help of datatable,
dt=obj.Test(id);
ltrlName.Text=dt.Rows[0]["Name"].ToString();
ltrlAddress.Text=dt.Rows[0]["Address"].ToString();
How can we do the same thing in LINQ?
var first = result.FirstOrDefault();
if (first != null)
{
ltrlName.Text = first.Name;
ltrlAddress.Text = first.Address;
}
Addendum - How to do this without linq to objects:
With the code below in a class called DB
var result = DB.SelectIntoItem("StoredProc_Name",
connectionString,
System.Data.CommandType.StoredProcedure,
new { param1 = "val1" });
if (!reader.Empty)
{
ltrlName.Text=result.Name;
ltrlAddress.Text=result.Address;
}
etc.
Code
public static dynamic SelectIntoItem(string SQLselect, string connectionString, CommandType cType = CommandType.Text, object parms = null)
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
using (SqlCommand cmd = conn.CreateCommand())
{
dynamic result = new System.Dynamic.ExpandoObject();
cmd.CommandType = cType;
cmd.CommandText = SQLselect;
if (parms != null)
Addparms(cmd, parms);
conn.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.Read()) // read the first one to get the columns collection
{
var cols = reader.GetSchemaTable()
.Rows
.OfType<DataRow>()
.Select(r => r["ColumnName"]);
foreach (string col in cols)
{
((IDictionary<System.String, System.Object>)result)[col] = reader[col];
}
result.Empty = false;
if (reader.Read())
{
// error, what to do?
result.Error = true;
result.ErrorMessage = "More than one row in result set.";
}
else
{
result.Error = false;
}
}
else
{
result.Empty = true;
result.Error = false;
}
}
conn.Close();
return result;
}
}
}
private static void Addparms(SqlCommand cmd, object parms)
{
// parameter objects take the form new { propname : "value", ... }
foreach (PropertyInfo prop in parms.GetType().GetProperties())
{
cmd.Parameters.AddWithValue("#" + prop.Name, prop.GetValue(parms, null));
}
}
If you are insterested follow my GitHub, I'll be making the rest of it public soon (GitHub)
I want to check the given value present in a dataset column.
I was insert the value using separator and stored in a column name fld empname.
Example the dataset field fldempname have the value Hari,vinoth,Arun. suppose i ll insert again the value hari and arun means it display error message Like this Employee name already present otherwise the value inserted.
please help me..
My partial code is here..
for (int i = 0; i < lstbox.Items.Count; i++)
{
if (lstbox.Items[i].Selected)
{
string id = lstbox.Items[i].Text;
DataSet4TableAdapters.sp_getallattendancesetupTableAdapter TA1 = new DataSet4TableAdapters.sp_getallattendancesetupTableAdapter();
DataSet4.sp_getallattendancesetupDataTable DS1 = TA1.GetData();
if (DS1.Rows.Count == 0)
{
employee = employee + lstbox.Items[i].Text + ",";
}
else if (DS1.Rows.Count > 0)
{
foreach (DataRow dr in DS1.Rows)
{
foreach (string category in dr["fldemployee"].ToString().Split(','))
{
if (category != "")
{
if (category == id)
{
Value = Value + lstbox.Items[i].Text + "\\n";
break;
}
}
continue;
}
}
}
}
You can use the DataSet's Select() method:
DataRow[] foundRows;
foundRows = dataSet1.Tables["MyTable"].Select("fldempname = 'Hari'");
I haven't worked with datasets in a while.. so there prob is cleaner/better way to do this..
DataSet st = new DataSet();
foreach (DataRow row in st.Tables["table_name"].Rows)
{
if (row["column_name"] == "value")
{
//found
}
}
side note: i'd try Mitch Wheat's answer