简体   繁体   中英

How do you pass values from a datareader in a while loop to a method in C#

I have 3 tables in a database that I am iterating through using a SQL statement. It searches for applications that need to have contracts renewed. I use SQL date math to check whether managers need to be notified of a contract renewal. If today's date = the date in the notificationDate field, the console app should send an email to the person listed as the analyst/manager of that application. Here is my code so far:

namespace ContractApp
{
    class Program
    {
        //initializes strings for storing information from the table
        static string aretheyManager;
        static string listedanalystEmail;
        static string listedmanagerEmail;

    static void Main(string[] args)
    {
        int warningWindow = 10;

        try
        {
            //connects to the AppInfo_dev table in the database
            SqlConnection conn = new SqlConnection("server=10.52.2.169\\sqlcluster,1206;uid=TannerAppsWriter;pwd=TannerAppsWriter;database=AppInfo_dev;");
            conn.Open();

            //sets up a sequal command called selectedValues
            SqlCommand selectValues = conn.CreateCommand();

            //Pulls information from three tables in the database (AppInfo_dev, SoftwareApp, IT_Personnel)
            //Takes the AppID from the Contracts list and compares it to AppID in the Apps list and displays matches
            //Then it finds employee information related to the Primary Analyst that is listed for that application
            //Adds a field called "notificationDate" that is filled by subtracting the "warningWindow" and "TerminationWindow" from the RenewalDate
            //Finds contracts listed that have a "notificationDate" that is the same as the current date
            //Takes the eMail fields and appends "@tanner.org" to the end of the text in the field
            selectValues.CommandText = "My SQL statement goes here...it works so I didn't bother posting it since it is really long"

            //Reads values in specified columns in the database
            using (SqlDataReader dataReader = selectValues.ExecuteReader())
            {
                if (dataReader.HasRows)
                {
                    while (dataReader.Read())
                    {
                        //Converts the values in the tables to strings
                        aretheyManager = Convert.ToString(dataReader["isManager"]);
                        listedanalystEmail = Convert.ToString(dataReader["analystEmail"]);
                        listedmanagerEmail = Convert.ToString(dataReader["managerEmail"]);
                    }
                }
            }
        }
        //If there is an error, catch it
        catch (SqlException e)
        {
        Console.WriteLine(e.Message);
        }
    }

    private void sendEmailNotification()
    {


        //Create an email to send notifying of contract termination
        MailMessage message = new MailMessage();

        //Check to see if the listed analyst is a manager
        //If they are, send the email to them
        //If they are not, send they email to their manager.
        if (aretheyManager == "True")
        {
            message.To.Add(listedanalystEmail);
        }
        else
        {
            message.To.Add(listedmanagerEmail);
        }

        message.Subject = "This contract requires your attention!";
        message.From = new MailAddress("no response email address goes here");
        message.Body = "There is an application contract that is in need of renewal.";

        message.Priority = MailPriority.Normal;

        SmtpClient client = new SmtpClient("client info goes here");
        client.Send(message);
    }
}

}

The SQL statements works as expected. It iterates through the rows in the table and pulls contracts with a notificationDate = the current date. I am having trouble with the datareader. It iterates through the contracts pulled by the SQL statement, but only stores the last value it reads into the strings. I need it to store any and all values it pulls so an email gets sent to each person if there are multiple people that need to be notified.

You are looping over dataSet but storing the values in string rather than some kind of list. That's why only last value is stored

  //create a class to hold the value
class SomeDTO
{
   public string aretheyManager;
   public string listedanalystEmail;
   public string listedmanagerEmail;
}
  //in your main
 //Reads values in specified columns in the database
            List<SomeDTO> collection = new List<SomeDTO>();
            using (SqlDataReader dataReader = selectValues.ExecuteReader())
            {
                if (dataReader.HasRows)
                {
                    while (dataReader.Read())
                    {
                       SomeDTO obj = new SomeDTO();
                        //Converts the values in the tables to strings
                        obj.aretheyManager = Convert.ToString(dataReader["isManager"]);
                        obj.listedanalystEmail = Convert.ToString(dataReader["analystEmail"]);
                        obj.listedmanagerEmail = Convert.ToString(dataReader["managerEmail"]);

                       collection.Add(obj);

                    }
                }
                dataReader.Close();
                dataReader.Dispose();
            }


//send email notification method
private void sendEmailNotification(List<SomeDTO> obj)
{
     //loop and send email
}

A datareader is not designed to hold data. It just iterates over data. If you want to store the results of the "read", add the data into an ArrayList or some other data structure that will allow you to perform further work on the data.

 con.Open();

    ArrayList al = new ArrayList();
    SqlDataReader dr = cmd.ExecuteReader();

    while(dr.Read()) {
        object[] values = new object[dr.FieldCount];
        dr.GetValues(values);
        al.Add(values);
    }

    dr.Close();
    con.Close();

First of all change your SendMail method to be more generic.
Receive parameters with the info on the people that should receive a mail

private void sendEmailNotification(string aretheyManager, 
                                  string listedanalystEmail, 
                                  string listedmanagerEmail)
{
    //Create an email to send notifying of contract termination
    MailMessage message = new MailMessage();

    //Check to see if the listed analyst is a manager
    //If they are, send the email to them
    //If they are not, send they email to their manager.
    if (aretheyManager == "True")
    {
        message.To.Add(listedanalystEmail);
    }
    else
    {
        message.To.Add(listedmanagerEmail);
    }

    message.Subject = "This contract requires your attention!";
    message.From = new MailAddress("no response email address goes here");
    message.Body = "There is an application contract that is in need of renewal.";

    message.Priority = MailPriority.Normal;

    SmtpClient client = new SmtpClient("client info goes here");
    client.Send(message);
}

Now in your loop while you read the data from the reader call the above method passing the appropriate values

    if (dataReader.HasRows)
    {
        while (dataReader.Read())
        {
            //Converts the values in the tables to strings
            aretheyManager = Convert.ToString(dataReader["isManager"]);
            listedanalystEmail = Convert.ToString(dataReader["analystEmail"]);
            listedmanagerEmail = Convert.ToString(dataReader["managerEmail"]);

            // For every record read, send the email
            sendEmailNotification(aretheyManager, 
                                  listedanalistEmail, 
                                  listedmanagerEmail)                        
        }
    }

Of course you could also store the retrieved values from the DataReader in some form of object collection (a List<Email> where EMail is a class that contains your three parameters) but this will lead to a double loop (one to read and one to send the emails) so, if it is not really required to store in memory all those email addresses, I suggest to send the mail while you read from your reader.

One solution would be to create a Person class

public class Person
{
    public bool IsManager { get; set; }
    public string AnalystEmail { get; set; }
    public string ManagerEmail { get; set; }
}

Then in your Program class you'd need to declare a List<Person> _personList = new List<Person>();

Finally, in your while loop :

while (dataReader.Read())
{
    _personList.Add(new Person {
        IsManager = Convert.ToBool(dataReader["isManager"]),
        AnalystEmail = Convert.ToString(dataReader["analystEmail"]),
        ManagerEmail = Convert.ToString(dataReader["managerEmail"])
    });
}

After that, you could use foreach(var person in _personList) or the like for your emailing.

       using (var reader = selectValues.ExecuteReader()) {
           return reader.Cast<IDataRecord>()
                        .Select(record => new SomeDTO {
                                  aretheyManager = Convert.ToString(record["isManager"]),
                                  listedanalystEmail = Convert.ToString(record["analystEmail"]),
                                  listedmanagerEmail = Convert.ToString(record["managerEmail"])
                               })
                        .ToList();
       }

no matter how manytimes you iterate over these your values will be updated each time and you will get only last updated values . because for each iteration you are assigning new values to your strings .

               while (dataReader.Read())
                {
                    //Converts the values in the tables to strings
                    aretheyManager = Convert.ToString(dataReader["isManager"]);
                    listedanalystEmail = Convert.ToString(dataReader["analystEmail"]);
                    listedmanagerEmail = Convert.ToString(dataReader["managerEmail"]);
                }

I think you should use some kind of collection for storing your values .

          List<string> aretheyManager = new List<string>(); 
          List<string> listedanalystEmail =new List<string>();  
         List<string> listedmanagerEmail = new List<string>();  


        while (dataReader.Read())
                {
                //Converts the values in the tables to strings
               aretheyManager.Add(Convert.ToString(dataReader["isManager"]));
               listedanalystEmail.Add( Convert.ToString(dataReader["analystEmail"]));
               listedmanagerEmail.Add(Convert.ToString(dataReader["managerEmail"]));
                }

Create a struct to hold all of your details and then create a List<yourstruct> .

Populate your struct within your loop.

When you drop out of your loop call your email method and pass the list.

In your email method foreach your list sending an email each time

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM