C# Group DataRows in DataTable - c#

I have a DataTable with two columns: File & Email
C://file1.jpg aaa#gmail.com
C://file2.jpg aaa#gmail.com
C://file3.jpg bbb#gmail.com
C://file4.jpg ccc#gmail.com
C://file5.jpg bbb#gmail.com
In my code i loop through the DataRows and send an email to Email with File attached.
Problem:
I need to somehow check if there are any other DataRows with the same Email and if so, send just one email with multiple attachments.
So the above DataTable would result in 3 emails:
file1,file2 sent to aaa#gmail.com
file3,file5 sent to bbb#gmail.com
file4 sent to ccc#gmail.com
My code sample:
foreach (DataRow row in dt.Rows) {
string file = row[0].ToString();
string email = row[1].ToString();
SendEmailWithAttachments(email,file);
}
I could pass a StringCollection or an array to my SendEmailWithAttachments() function then loop throught it and attach all the files, but how do I group these DataRows in first place

Using the GroupBy Linq extension you could handle your DataRows grouping them for the Email field, then foreach create a list of strings with the file names.
Of course, you need also to change the SendMailWithAttachments to receive as second parameter a List<string> instead of a single string
var g = dt.AsEnumerable().GroupBy(d => d.Field<string>("Email"));
foreach (var x in g)
{
List<string> files = new List<string>();
foreach (var z in x)
files.Add(z.Field<string>("File"));
SendEmailWithAttachments(email,files);
}

You could use GroupBy to group by email:
DataTable dt = new DataTable();
dt.Columns.Add("Path");
dt.Columns.Add("Email");
DataRow dr = dt.NewRow();
dr.ItemArray=new object[2]{"C://file1.jpg", "aaa#gmail.com"};
dt.Rows.Add(dr);
dr = dt.NewRow();
dr.ItemArray=new object[2]{"C://file2.jpg", "aaa#gmail.com"};
dt.Rows.Add(dr);
dr = dt.NewRow();
dr.ItemArray=new object[2]{"C://file3.jpg", "bbb#gmail.com"};
dt.Rows.Add(dr);
dr = dt.NewRow();
dr.ItemArray=new object[2]{"C://file4.jpg", "ccc#gmail.com"};
dt.Rows.Add(dr);
dr = dt.NewRow();
dr.ItemArray=new object[2]{"C://file5.jpg", "bbb#gmail.com"};
dt.Rows.Add(dr);
var grouped=dt.AsEnumerable().GroupBy(x=>x.Field<string>("Email"));
foreach (var mail in grouped)
{
List<string> filesForEmail = new List<string>();
foreach (var file in mail)
{
filesForEmail.Add(file.Field<string>("Path"));
}
SendEmailWithAttachments(mail.Key, filesForEmail);
}

Related

Adding DataRow into a New Datatable error saying the row is already associated to a table

I am using the below code in Visual Studios to go through each DataRow in a table and include an If statement to say where if a certain criteria is met, it creates a DataRow. I then want that DataRow to then be added into dt_tempHold for use later on in my program. Is "dt_tempHold.Rows.Add(dr_EPA);" not the thing to use here because I get an error saying that the row already belongs to another table? I just want a copy of the DataRow, into the DataTable as it goes through the ForEach and the If statements.
DataTable dt_tempHold = new DataTable();
foreach (DataRow dr in ds_picsData.Tables["Placemnt"].Rows)
{
if (ds_spreadsheetdata.Tables["EPABase"].AsEnumerable().Any(t => t.Field<string>("EPA_ORG_ID") == dr["NAME"].ToString()))
{
DataRow dr_EPA = ds_spreadsheetdata.Tables["EPABase"].AsEnumerable().FirstOrDefault(t => t.Field<string>("EPA_ORG_ID") == dr["NAME"].ToString());
dt_tempHold.Rows.Add(dr_EPA);
dr["ADDR1"] = dr_EPA["Contact_address1"].ToString();
dr["ADDR2"] = dr_EPA["Contact_address2"].ToString();
dr["ADDR3"] = dr_EPA["Contact_address3"].ToString();
dr["ADDR4"] = dr_EPA["Contact_address4"].ToString();
dr["POSTCODE"] = dr_EPA["Postcode"].ToString();
dr["PHONE"] = dr_EPA["Contact_number"].ToString();
dr["EMAIL"] = dr_EPA["Contact_email"].ToString();
dr["NAME"] = dr_EPA["EP_Assessment_Organisations"].ToString();
}
};

how to add some selected items and their indexes from listbox to datatable

I`m trying to use something like this:
I have 20 list items and I have to choose some of them, then add them to datatable in first column elements, in second - their indexes.
DataTable dt = new DataTable();
dt.Columns.Add("Фактор-Критерій", typeof(string));
dt.Columns.Add("Ранг", typeof(string));
ChoosenCriteria.DataSource = dt;
List<string> selectedItems = new List<string>();
foreach (string o in listBox1.SelectedItems)
selectedItems.Add(o);
List<int> selectedItemIndexes = new List<int>();
foreach (int o in listBox1.SelectedIndices)
selectedItemIndexes.Add(listBox1.Items.IndexOf(o));
DataRow dr = dt.NewRow();
dr[0] = selectedItems.ToString();
dr[1] = selectedItemIndexes.ToString();
dt.Rows.Add(dr););
I can not do this, all i have at the end is on screen:enter image description here
Move the DataSource binding statement after you have done with the modification like
for(int i=0; i<selectedItems.Count;i++
{
DataRow dr = dt.NewRow();
dr[0] = selectedItems[i].ToString();
dr[1] = selectedItemIndexes[i].ToString();
dt.Rows.Add(dr);
}
ChoosenCriteria.DataSource = dt;

C#, Looping through dataset and show each record from a dataset column

In C#, I'm trying to loop through my dataset to show data from each row from a specific column. I want the get each date under the column name "TaskStart" and display it on a report, but its just shows the date from the first row for all rows can anybody help?
foreach (DataTable table in ds.Tables)
{
foreach (DataRow dr in table.Rows)
{
DateTime TaskStart = DateTime.Parse(
ds.Tables[0].Rows[0]["TaskStart"].ToString());
TaskStart.ToString("dd-MMMM-yyyy");
rpt.SetParameterValue("TaskStartDate", TaskStart);
}
}
I believe you intended it more this way:
foreach (DataTable table in ds.Tables)
{
foreach (DataRow dr in table.Rows)
{
DateTime TaskStart = DateTime.Parse(dr["TaskStart"].ToString());
TaskStart.ToString("dd-MMMM-yyyy");
rpt.SetParameterValue("TaskStartDate", TaskStart);
}
}
You always accessed your first row in your dataset.
DateTime TaskStart = DateTime.Parse(dr["TaskStart"].ToString());
foreach (DataRow dr in ds.Tables[0].Rows)
{
//your code here
}
foreach (DataTable table in ds.Tables)
{
foreach (DataRow dr in table.Rows)
{
var ParentId=dr["ParentId"].ToString();
}
}
foreach (DataRow table in ds.Tables[0].Rows)
{
int ForType = Convert.ToInt32(table["Fortype"].ToString());
ds.Tables[0].DefaultView.RowFilter = "ForType ='" + ForType +"'";
rbtnQuestion.DataSource = ds.Tables[0].DefaultView;
rbtnQuestion.DataBind();
}

How Convert DataSet to List<ArrayList>?

I have a dataset ds and a List of ArrayList newpath i want to add(assign) ds to newpath
how is that possible.
public List<ArrayList> newpath
{
set { ViewState["newpath"] = value; }
get
{
if (ViewState["newpath"] == null)
return new List<ArrayList>();
else
return (List<ArrayList>)ViewState["newpath"];
}
}
i am trying with
foreach (DataRow dataRow in Ftb.Rows)//Ftb is datatable
{
newpath.Add(dataRow);//newpath is List<ArrayList>
}
and
foreach (DataRow dRow in ds.Tables[0].Rows)
{
newpath.Add(dRow);
}
if i am doing like above way then i am getting the error
"The best overloaded method match for 'System.Collections.Generic.List.Add(System.Collections.ArrayList)' has some invalid arguments"
Please help me if in someway.. how to do that
I assume you want each item in newpath to contain the column values of each row?
If so, have such code instead:
foreach (DataRow dataRow in Ftb.Rows)//Ftb is datatable
{
ArrayList values = new ArrayList();
foreach (object value in dataRow.ItemArray)
values.Add(value);
newpath.Add(values);
}
change newpath from
List<ArrayList>
to
List<DataRow>
From the code you've posted it looks as if your newpath variable is a list of ArrayLists. So when you try to add dRow which is DataRow you're getting an error as it's not an ArrayList.
If you want to add DataRows I think newpath should be a list of DataRow. If you wanted to populate the ArrayList with data from the DataRow you'd need something like this -
foreach (DataRow dataRow in Ftb.Rows)//Ftb is datatable
{
ArrayList myAL = new ArrayList();
myAL.Add(dataRow["your_column_name"]);
//add fields from DataRow to array list using your required logic
newpath.Add(myAL);
}
I have modified #Shadow Wizard code and now its working fine
List<ArrayList> newval = new List<ArrayList>();
foreach (DataRow dRow in ds.Tables[0].Rows)
{
ArrayList values = new ArrayList();
foreach (object value in dRow.ItemArray)
values.Add(value);
newval.Add(values);
}
newpath = newval;

Compare DataRow collection to List<T>

I have a List<string> and I have a DataTable.
One of the columns in a DataRow is ID. The List holds instances of this ID.
The DataTable gets populated on a Timer.
I want to return items from the List that are not in the DataTable into another list.
You will want to do something like this
var tableIds = table.Rows.Cast<DataRow>().Select(row => row["ID"].ToString());
var listIds = new List<string> {"1", "2", "3"};
return listIds.Except(tableIds).ToList();
You can cast the rows in the data table to be an IEnumerable collection and then select the "ID" column value from each of them. You can then use the Enumerable.Except extension method to get all of the values from the List that are not in the collection you just made.
If you need to get the values that are in the table but not the list, just reverse listIds and tableIds.
If your table was something like that:
DataTable dt = new DataTable();
dt.Columns.Add("ID");
DataRow dr = dt.NewRow();
dt.PrimaryKey = new DataColumn[] {dt.Columns[0]};
dr["ID"] = "1";
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["ID"] = "2";
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["ID"] = "3";
dt.Rows.Add(dr);
and the list was something like this:
List<string> ls = new List<string>{"1","2","4"};
we could get the items found in the list and not in the datatable this way:
var v = from r in ls
where !dt.Rows.Contains(r)
select r;
v.ToList();
With reasonable efficiency via HashSet<T> (and noting that the fastest way to get data out of a DataRow is via the DataColumn indexer):
HashSet<int> ids = new HashSet<int>();
DataColumn col = table.Columns["ID"];
foreach (DataRow row in table.Rows)
{
ids.Add((int)row[col]);
}
var missing = list.Where(item => !ids.Contains(item.ID)).ToList();

Categories