datatable on single cell multiples values - c#

I have DataTable which I add Columns and Rows from database. Problem is I have one cell which has multiples record like province can be multiples in database. So I need to create multiple records in one cell of province. My code is
foreach (var item in attributes)
{
table.Columns.Add(item.name);
//column add
}
foreach (var item in forms)
{
string FormId = Convert.ToString(item);
var row = table.NewRow();
row["Form Id"] = FormId;
foreach (var itemdata in attributes)
{
var value = attributesData.FirstOrDefault(t => t.attributeName == itemdata.name && t.strFormId == FormId);
if (value != null && String.IsNullOrWhiteSpace(value.strFormId) == false )
{
row[itemdata.name] = value.strValue;
//row add
}
}
table.Rows.Add(row);
}
gvView.DataSource = table;
I bind this with my GridView. How to break one cell with mutliples records please help.

Related

Linq group by multiple columns, one of which is selectable

I have a table consisting of
MyDate(DATETIME),
Type nvarchar(255),
PropertyAId(int),
PropertyBId(int),
Data1 (float),
Data2 (float),
...
Data50 (float)
I want to return a table grouped by
MyDate,Type, and one of PropertyAId,PropertyBId (depending on user selection)
and sum all of the Data columns.I would prefer summing and selecting Data columns based on prefix or data type, and not having to repeat the same line 50 times
What I have so far is a bit ugly
DataTable dt2 = dt.Clone();
var grouped = dt.AsEnumerable().
GroupBy(r => new
{
MyDate = r.Field<DateTime>("MyDate"),
PropertyAId = selectedGroupingColumn == "PropertyAId" ? r.Field<int?>("PropertyAId") : null,
PropertyBId = selectedGroupingColumn == "PropertyBId" ? r.Field<int?>("PropertyBId") : null,
Type = r.Field<string>("Type")
});
foreach (var group in grouped)
{
DataRow row = dt2.NewRow();
foreach (var col in dt.Columns.Cast<DataColumn>())
{
if (col.ColumnName.StartsWith("Data"))
{
double sum = 0;
if (col.DataType == typeof(double))
sum = group.Sum(r => r.Field<double>(col));
row.SetField(col.ColumnName, sum);
}
else
row[col.ColumnName] = group.First()[col];
}
dt2.Rows.Add(row);
}
//dt2.Columns.Remove unselected property and return table
Your logic seems (mostly) sound, but I would suggest just using selectedGroupingColumn directly to get the value to group by, and only set the sum for "Data" columns of type double:
DataTable dt2 = dt.Clone();
var grouped = dt.AsEnumerable().
GroupBy(r => new {
MyDate = r.Field<DateTime>("MyDate"),
GroupingColumnValue = r.Field<int?>(selectedGroupingColumn),
Type = r.Field<string>("Type")
});
foreach (var group in grouped) {
DataRow row = dt2.NewRow();
foreach (var col in dt.Columns.Cast<DataColumn>())
if (col.ColumnName.StartsWith("Data") && col.DataType == typeof(double))
row.SetField(col.ColumnName, group.Sum(r => r.Field<double>(col)));
else
row[col.ColumnName] = group.First()[col];
dt2.Rows.Add(row);
}

How can I convert a List<T> to DataTable with only selected parameters

I have a List<Indicators> where Indicators has several properties.
I have a ListView which holds selected properties of that class as a list of strings.
I want to create a DataTable from the List using only the selected properties in the listview.
So far I can create the columns for the DataTable with the selected parameters in listview. I'm stuck on how to fill each row with data from selected columns only.
the for block is where I'm stuck, I know what I have there isn't right. Any help is appreciated, thanks.
internal DataTable ConvertToDataTableAll(List<Indicators> data)
{
DataTable table = new DataTable();
foreach (ListViewItem item in listviewFeatures.Items)
{
table.Columns.Add(item.Text);
//this for block should fill the current column with data.
for (int i = 0; i < data.Count; i++)
{
var row = table.NewRow();
table.Rows.InsertAt(row, i);
table.Rows[i][item.Text] = data.Select(x => item.Text);
}
}
}
Solution with some changes to CodingYoshis suggestion.
This is after adding all columns from code above and removing the for block.
foreach(Indicators ind in data)
{
var row = table.NewRow();
foreach(PropertyInfo prop in ind.GetType().GetProperties())
{
if (table.Columns.Contains(prop.Name))
{
row[prop.Name] = prop.GetValue(ind);
}
}
table.Rows.Add(row);
}
You need to add the columns once for the entire table, not for every row as you are doing. So it should be done like this:
var firstItem = listviewFeatures.Items.FirstOrDefault();
if (firstItem == null)
{
// Nothing to convert to datatable so return
return;
}
// We have items so lets initialize the table
DataTable table = new DataTable();
foreach (ColumnHeader header in listviewFeatures.Columns)
{
table.Columns.Add(header);
}
// Now lets add the rows
foreach (ListViewItem item in listviewFeatures.Items)
{
// Create one row per row in listview
var row = table.NewRow();
// Traverse the listview by each column and fill the row
foreach (ColumnHeader header in listviewFeatures.Columns)
{
row[header] = item.Text;
}
// Add row to table. It will add it to the end.
table.Rows.Add(row);
}

How to read values from a DataGridView.Rows collection and assign them to a list of custom objects?

My custom object has two properties: userid and username.
Here I found how to traverse through each DataGridViewRow using a foreach loop, but I don't get how to assign current cell value to my custom object value.
foreach (DataGridViewRow dr in dataGridView1.Rows)
{
ClsOBJ userobj1 = new ClsOBJ();
foreach (DataGridViewCell dc in dr.Cells)
{
// userobj1.userid =
// cell index 0 should be read to userid
// and cell index 1 should be read to username
// userobj1.username =
}
list1.Add(userobj1);
}
No need to iterate through the collection of cells. Just access each one and convert it as needed:
foreach (DataGridViewRow dr in dataGridView1.Rows)
{
ClsOBJ userobj1 = new ClsOBJ();
userobj1.userid = Convert.ToInt32(dr.Cells[0].Value);
userobj1.username = Convert.ToString(dr.Cells[1]);
list1.Add(userobj1);
}
You could populate the list using LINQ, but if you're unfamiliar with it, the foreach loop is perfectly fine.
list1.AddRange(
dataGridView1.Rows
.Cast<DataGridViewRow>()
.Select(x => new ClsOBJ
{
userid = Convert.ToInt32(x.Cells[0].Value),
username = Convert.ToString(x.Cells[1].Value)
}));

Check duplicate GridEX rows with Linq does'nt work

I have two Janus GridEXs. When an specific button is clicked, I want to add rows of first grid to another grid; but I want to check that already these rows do'nt exist in the second grid, so I used this code block with linq:
DataTable dtSelectedRows = new DataTable();
dtSelectedRows = firstGrid.GetDataSource().Clone();
foreach (GridEXRow row in rows)
{
DataRow dr = ((DataRowView)row.DataRow).Row;
if (dtSelectedRows.AsEnumerable().Count() > 0)
{
if (dtSelectedRows.AsEnumerable().Where(t => t.Field<Int32>("myColumn") == Convert.ToInt32(dr["myColumn"])).Count() == 0)
{
dtSelectedRows.ImportRow(dr);
}
}
else
dtSelectedRows.ImportRow(dr);
}
}
secondGrid.SetDataSource(dtSelectedRows);
but unfortunately it did'nt work and dtSelectedRows is always empty. So I forced to rewrite the block as:
GridEXRow[] rows = firstGrid.GetCheckedRows();
DataTable dtSelectedRows = new DataTable();
dtSelectedRows = firstGrid.GetDataSource().Clone();
foreach (GridEXRow row in rows)
{
if (row.RowType == Janus.Windows.GridEX.RowType.Record)
{
DataRow dr = ((DataRowView)row.DataRow).Row;
bool rowExists = false;
foreach (DataRow r in dtSelectedRows.Rows)
{
if (Convert.ToInt32(r["myColumn"]) == Convert.ToInt32(dr["myColumn"]))
{
rowExists = true;
break;
}
}
if (!rowExists)
dtSelectedRows.ImportRow(dr);}
}
secondGrid.SetDataSource(dtSelectedRows);
and fortunately it just worked. So how can I correct the first code block?
try this :
dtSelectedRows = firstGrid.GetDataSource().AsEnumerable().ToList();
instead of :
dtSelectedRows = firstGrid.GetDataSource().Clone();

Display row number from system.data.datarow

So i'm importing an excel doc into my project
DataSet result = excelReader.AsDataSet();
if (result != null)
{
foreach (System.Data.DataTable t in result.Tables)
{
if (t != null && t is System.Data.DataTable)
{
System.Data.DataTable table = t as System.Data.DataTable;
Items Lastitem = new Items();
foreach (System.Data.DataRow r in t.Rows)
{
if (r != null && r is System.Data.DataRow)
{
//new ItemType
if (r.ItemArray[0] != null)
{
Then I run checks to check which column is empty when I get the empty column i then want to get the empty row.
I have tried:
if (checkIfColumnisEmpty(r.ItemArray[0]) && !checkIfColumnisEmpty(r.ItemArray[1]))
{
throw new ImportBOQException("Error importing document: First column is empty at row " + r);
r being the datarow, the telesense allows me rowError, rowState etc... but not row Number....any ideas please? }
You could use a For Loop instead of Foreach when iterating through your rows as follows :
for (int i = 0; i < t.Rows.Count; i++)
{
// Do Your Null Checking and throw the exception with iteration number + 1
if (checkIfColumnisEmpty(t.Rows[i].ItemArray[0]) && !checkIfColumnisEmpty(t.Rows[i].ItemArray[1]))
{
throw new ImportBOQException("Error importing document: First column is empty at row " + (i + 1));
}
}

Categories