Send Daily Emails via single nested loops function - c#

I am creating a web page that will be run once a day to send email notices to supervisors. I want each supervisor to get a single email that contains data about all of their employees, of which might have multiple events.
I have some data like this:
supervisorEmail | employeeID | eventDate | eventDetails
===================================================================================================
george#blah.org | jones | 2014-03-18 | Watch a movie
george#blah.org | jones | 2014-03-20 | Convention registration
george#blah.org | smith | 2014-03-20 | Convention registration
george#blah.org | smith | 2014-03-20 | Convention registration
gayle#blah.org | nloya | 2014-03-13 | some other stuff
gayle#blah.org | nloya | 2014-03-25 | this and that
I start by retrieving all the above data and put into a DataTable.
Next I need to group by supervisor so each gets an email.
Within each email I need the rows filtered for that supervisor. I see how LINQ can be used for some of this. I'm lost at the moment for all of it. Could I get a shove in the right direction at least?

You can group the data by supervisorEmail:
var groups = data.GroupBy(d => d.supervisorEmail);
foreach(var g in groups)
{
SendEmail(g.Key, g); // g is an IEnumerable<some type> with the data for that supervisor
}
public void SendEmail(string supervisorEmail, IEnumerable<some type> data)
{
// send data to supervisor
}

Related

Linq Account Hierarchy Drill Down

I have two tables, one an invoice table and the other a hierarchy table for the accounts on the invoice
Invoice Table:
| InvoiceNo| AccNo| InvoiceAmount |
--------------------------------------
| A1234| 345| 100.00 |
| A1235| 346| 95.00 |
| A1236| 347| 15.50 |
| A1237| 348| 20.10 |
Hierarchy Table
| AccNo| HierAccNo| Level|
--------------------------------------
| 123| | 1 |
| 789| 123| 2 |
| 890| 123| 2 |
| 345| 789| 3 |
| 346| 789| 3 |
| 347| 890| 3 |
| 348| 890| 3 |
What I'm trying to do is to roll up the amounts from the invoice table to the highest level AccNo which is Level1 and then on a seperate instance from the highest account number roll back down to the next levels.
So far I am able to roll up to the highest band number by the following :
var BandL2 = from invoice in db.Invoices//Roll up to level 2
join ban in db.HierarchyTable
on invoice.AccNo equals ban.Ban
where invoice.GlobalInvoiceID == globalInvoice.Id
group invoice by ban.HierAccNo into bandHierarchy
select new
{
Level2Band = bandHierarchy.Key,
Amount = bandHierarchy.Sum(m=> m.InvoiceAmount)
};
var bandHierarchyTable = db.HierarchyTable.AsQueryable();
var BandL1 = from band2 in BandL2 // Roll Up to level 1
join band1 in bandHierarchyTable
on band2.Level2Band equals band1.Ban
group band2 by band1.HierAccNo into bandL1
select new
{
Level1Band = bandL1.Key,
Amount = bandL1.Sum(m => m.Amount)
};
But now I'm having an issue reversing the process and drilling down from Level 1 as the only details from the form is the AccNo of Level 1(eg. 123).
I'm trying to do this on the fly using pop up modals as I'm drilling.
How do I drill down again so that I can get level by level amounts?
Example:
Ouput Table from Above Code
| AccNo| Amount|
--------------------------------------
| 123| 230.60 |
Then
| AccNo| Amount|
--------------------------------------
| 789| 195 |
| 890| 35.60|
And then clicking on one of the AccNo.
| AccNo| Amount|
--------------------------------------
| 345| 100|
| 346| 95 |
Thanks!
Looks like only leaf accounts can have invoices attached to it, so get the account number, check if it is leaf account, if it is leaf it should be something like that;
var hierAccNo = 123;
var details = from invoice in db.Invoices
join ban in db.HierarchyTable
on invoice.AccNo equals ban.Ban
where invoice.GlobalInvoiceID == globalInvoice.Id
and ban.HierAccNo = HierAccNo;
if it is not leaf you want your original query on level 1 I guess to get the subtotals.
var BandL2 = from invoice in db.Invoices//Roll up to level 2
join ban in db.HierarchyTable
on invoice.AccNo equals ban.Ban
where invoice.GlobalInvoiceID == globalInvoice.Id and ban.HierAccNo = hierAccNo // dont skip this
group invoice by ban.HierAccNo into bandHierarchy
select new
{
Level2Band = bandHierarchy.Key,
Amount = bandHierarchy.Sum(m=> m.InvoiceAmount)
};

LINQ Grouping By with Left Join Results

If I got this list
PersonPhone
------------------------------------------------------------
| **PersonId** |**Name** | **PhoneId** | **PhoneNumber** |
------------------------------------------------------------
| 1 | John Doe | 1 | 111-55-5855 |
------------------------------------------------------------
| 1 | John Doe | 2 | 111-55-5521 |
------------------------------------------------------------
| 2 | Mary Jane| 3 | 254-565-855 |
------------------------------------------------------------
| 3 | J. Watson| NULL| NULL|
------------------------------------------------------------
I need to mapping to this object:
public class PersonContactInfo {
public int Id { get; set; }
public string Name { get; set; }
public List<string> Phones { get; set; }
}
With LINQ, how can I get one row for each person, with his phones in a List and paging?
I already have a query which result is like the PersonPhone result set, but I don't know how to grouping by PersonId and then join all the PhoneNumbers to List, and paging. For example, if I want a page size of three, how to make a sql query to get John Doe, Mary Jane and J. Watson with their phones, if the actual query returns 4 rows?
Note: I'm not (and can't) using Entity Framework, what I'm doing is and sql query that populate a list of PersonPhone, just like EF does.
Applying a group by:
var query= PersonPhoneSet
.GroupBy(p=>new {p.PersonId, p.Name})
.Select(g=> new PersonContactInfo
{
Id=g.Key.PersonId,
Name=g.Key.Name,
Phones= g.Select(p=>p.PhoneNumber).ToList()
}
);

Save datagridview dynamically filled in C#

I'm searchin for a way to solve my problem, in relation with a previous question.
I have to manage different payment methods in Datagridview.
An user (cashier for example) have to check all money they have at the end of their service.
In a parent form, i display payment methods names, automatically amounts from an other database, two empty columns and a column with buttons "details".
Initially the datagridview in parent form looks like this :
PAYMENT | QTY | AUTOMATIC | MANUAL | DIFF. | DETAILS |
_____________|_________|_____________|__________|__________|___________|
CREDIT CARD | 2 | 46.80 | | | [DETAILS] |
CHECK | 1 | 25.65 | | | [DETAILS] |
BANK TRANSFER| 1 | 150.25 | | | [DETAILS] |
When the user click on a details button, i display a child form with an other datagridview with details of a payment method. I load the form like this in the parent form :
var details = new FrmDetails("FormName", "IdOfPaymentMethod");
details.ShowDialog();
For the credit card for example, i get a datagridview in the child form like this :
DATE/HOUR | TICKET NUMBER | AMOUNT | CHECK |
_____________________|_______________|__________|_________|
01/11/2015 - 08:23 | 138170 | 12.90 | |
01/11/2015 - 09:45 | 138191 | 33.90 | v |
These are the two payments by credit card for the date that user has selected beforehand. The sum of both is what you can see in the column "AUTOMATIC" in parent form. The last column "CHECK" contains checkboxes, users checks if they have the payment with them.
In my example, user check only the second line with 33.90 and not the other one.
When they close this details form, the parent datagridview update like this :
PAYMENT | QTY | AUTOMATIC | MANUAL | DIFF. | DETAILS |
_____________|_________|_____________|__________|__________|___________|
CREDIT CARD | 2 | 46.80 | 33.90 | -12.90 | [DETAILS] |
CHECK | 1 | 25.65 | | | [DETAILS] |
BANK TRANSFER| 1 | 150.25 | | | [DETAILS] |
This is the simple operation of the application.
The problem is that I have to save each datagridview "details" in a SQL database (SQL Server). The user has to enter other information before these payments so the solution that I thought was to save the previous datas in a table "ENTRIES" then retrieve the ID max, and save each datagridview "details" with a link ID_ENTRY as a foreign key.
I can do that with a single datagridview "details" but i lose all the check/uncheck when i press on others details button on the parent form.
Is there a way to keep each datagridview "details" until the final recording?
I hope my message was clear and comprehensive.
The scope of each instance of FrmDetails is only the scope of the button's click event - hence the data is gone.
Either you'll have to keep around a collection of FrmDetails instances for each payment method row:
var details = new List<FrmDetails>();
foreach (var row in dataGridView1.Rows)
{
var detail = new FrmDetails("FormName", "IdOfPaymentMethod");
details.Add(detail);
}
// And when clicking on a Details button:
details[e.ColumnIndex].ShowDialog();
Or a collection of their equivalent data (I used List here, but I'd recommend something bindable - pending your source code):
var detailsData = new List<DetailsDataSources>();
foreach (var row in dataGridView1.Rows)
{
var details = GetThisRowsDetails();
detailsData.Add(details);
}
// And when clicking on a Details button, somehow set the DataSource:
var details = new FrmDetails("FormName");
details.childDataGridView1.DataSource = detailsData[e.ColumnIndex];
details.ShowDialog();
/*
* Ensure the changes made in the details form are then afterwards
* reflected in detailsData[e.ColumnIndex]
*/

Inputing Value in sql after counting c#

I'm kind of new to this but I'll try to give as much detail as possible. This is my SQL table.
Customers
Customers_Id (PK) | First | Last | Address | Phone | Tech_Id (FK) |
-------------------+-------+-------+--------------+----------+--------------+
1 | Bob | Smith | 123 Fake St. | 3298492 | 1 |
2 | John | Man | 123 Noe St. | 2930482 | 1 |
3 | Tom | Lee | 123 Polk St. | 9308523 | 2 |
...
Tech
Tech_Id (PK) | First | Last | Phone | Customer_Count |
--------------+-------+-------+---------+----------------+
1 | Tim | Bo | 9384027 | |
2 | Andy | Wong | 9374927 | |
3 | Jack | Help | 2183847 | |
...
I'm trying to find the best way to count how many customer that each tech has either using SQL Query or C# coding. I was thinking of doing query with Count and then insert into the Customer_Count in Tech table.
I'm using visual studio 2012 and SQL is created locally in visual studio. Please help!
You can do it through SQL - using a GROUP BY clause to group the result by each tech. You can use the COUNT function to return the number of customers assigned to each tech. You can put this in an UPDATE statement to update the customer_count field in the tech table for each tech.
For example:
UPDATE t
SET t.customer_count = COUNT(c.customer_id)
FROM tech t
INNER JOIN customers c ON c.tech_id = t.tech_id
GROUP BY c.tech_id
Remove the Customer_Count column from the tech table. It's best not to make columns which duplicate available data unless there's a valid performance reason. If you want it displayed as such, then create a view:
SELECT t.tech_id,
t.first,
t.last,
t.phone,
(SELECT COUNT(c.customer_id)
FROM customers c
WHERE c.tech_id = t.tech_id) AS Customer_Count
FROM tech t
Now you can query it like a table, but you're not tasked with maintaining data which is always up to date through this view.
I prefre to using Sql ,but failed...Disappionted..
But I am sure that you can use Ado.net to do this job.
Here is C# demo code.
//query from db use C#
var allCus = new List<Customers>();
var gps = allCus.GroupBy(w => w.Tech_Id);
foreach(var gp in gps) {
var techId = gp.Key;
var cnt = gp.Count();
//update Tech set Customer_Count = cnt where Tech_Id = techId
}
Here is Sql version
update Tech set Customer_Count = (select IdAndCnt.cnt from (select Tech_Id,count (Tech_id) as cnt from Customers group by Tech_Id ) as IdAndCnt where Tech.Tech_Id = IdAndCnt.Tech_Id)
Holp it works.

how to structure data that will be fed into dropdown boxes?

I have denormalized data:
+----+----------+------+--------+
| pk | name | type | animal |
+----+----------+------+--------+
| 1 | alex | car | cat |
| 2 | alex | bike | cat |
| 3 | liza | car | dog |
| 4 | danielle | bike | dog |
| 5 | danielle | bus | dog |
+----+----------+------+--------+
I would like to have 3 dropdown boxes.
name
type
animal
after the user chooses the option for the first, there should be a cascade effect for the other dropdowns.
example: if the user chooses danielle for the name, the only two options for type would be bike and bus and the only option for animal would be dog
How should I structure the SQL tables? Should I denormalize?
I'd say that your solution depends on how much data do you have in this table.
If this table is relatively small, you could load it into memory, fill comboboxes by distinct values and then filter data by chosen field.
If it large, you maybe should denormalize your table as #astander says, fill comboboxes with data from reference tables and then when value changes, select filters from SQL like:
declare #name_id int -- input parameter, fill it with id of chosen name
-- filter for type combo
select distinct type_id from main_table where name_id = #name_id
-- filter for animal combo
select distinct animal_id from main_table where name_id = #name_id

Categories