0

The below code is storing patients id in both text box 1 and text box 2. It should store the name of the patient in textbox 2. I have tried changing the values in dr.GetValue(1).ToString(), but it's not working! Can anyone please help?

 private void button1_Click(object sender, EventArgs e)
        {
            SqlConnection con = new SqlConnection(@"Data Source=DESKTOP-A85V0ME\SQLEXPRESS;Initial Catalog=Hospitalmanagement;Integrated Security=True");

            con.Open();
            if (textBox1.Text != "")
            {
                try
                {
                    string getCust = "select id,name,gen,age,date,cont,addr,disease,status,r_type,building,r_no,price from patient where id=" + Convert.ToInt32(textBox1.Text) + " ;";

                    SqlCommand cmd = new SqlCommand(getCust, con);
                    SqlDataReader dr;
                    dr = cmd.ExecuteReader();
                    if (dr.Read())
                    {
                        textBox2.Text = dr.GetValue(0).ToString();
                        if (dr[1].ToString() == "Male")
                        {
                            radioButton1.Checked = true;
                        }
                        else if (dr[1].ToString() == "Female")
                        {
                            radioButton2.Checked = true;
                        }

                        textBox3.Text = dr.GetValue(1).ToString();
                        textBox3.Text = dr.GetValue(3).ToString();
                        textBox4.Text = dr.GetValue(4).ToString();
                        textBox5.Text = dr.GetValue(5).ToString();
                        textBox6.Text = dr.GetValue(6).ToString();
                        textBox7.Text = dr.GetValue(7).ToString();
                        textBox8.Text = dr.GetValue(8).ToString();
                        textBox9.Text = dr.GetValue(10).ToString();
                        textBox10.Text = dr.GetValue(9).ToString();
                        textBox11.Text = dr.GetValue(11).ToString();
                        textBox12.Text = dr.GetValue(12).ToString();

                        //      textBox12.Text = dr.GetValue(12).ToString();


                    }
                    else
                    {
                        MessageBox.Show(" Sorry, This ID, " + textBox1.Text + " Staff is not Available.   ");
                        textBox1.Text = "";
                    }
                }
                catch (SqlException excep)
                {
                    MessageBox.Show(excep.Message);
                }
                con.Close();
            }
        }

Output

  • Are you aware that you're allowed to rename controls after you drop them on the form? Please always do it; code that is full of "textBox57" is effectively obfuscated i.e. meaningless garbage and it's incredibly difficult for someone on the internet to understand. In 6 months time it will be incredibly hard for YOU to understand. *Always* call your controls something meaningful – Caius Jard Jan 24 '21 at 08:14
  • **You should be disposing your connection and reader, see [C# Data Connections Best Practice?](https://stackoverflow.com/questions/17552829/c-sharp-data-connections-best-practice)** You are also concatenating SQL queries instead of using parameters, this can cause SQL injection attacks – Charlieface Jan 24 '21 at 13:15
  • You set `textBox3.Text = dr.GetValue(1).ToString();`, then again `textBox3.Text = dr.GetValue(3).ToString();` ? Typo. – dr.null Jan 24 '21 at 18:54

4 Answers4

1

Your sql is:

select id,name,gen,age,date,cont

Which means, in terms of column numbering, that 0 is id, 1 is name...

You said:

It should store the name of patient in the textbox 2

And you wrote:

textBox2.Text = dr.GetValue(0).ToString();

0 is the id.

Perhaps you should switch to names, for everything including giving your controls sensible names. Look how much easier it makes it to understand the code:

nameTextBox.Text = dr["name"].ToString();
Caius Jard
  • 72,509
  • 5
  • 49
  • 80
0

Maybe this is true textBox2.Text = dr.GetValue(1).ToString();

Meysam Asadi
  • 6,438
  • 3
  • 7
  • 17
0

If you would separate you concerns, and let every method do only one thing, it would be easy to create tests to see why your code is not working.

Consider to separate your database handling from displaying fetched data. This way you can easily change where you fetch your data or change how you use the fetched data.

Apart from that this will help you to find the source of your problems, it will also make your code better to understand, easy to reuse and change.

You should especially take care that you separate your data (= model) from how you display it (= view) and how you store it.

class Patient
{
    public int Id {get; set;}
    public string Name {get; set;}
    public Gender Gender {get; set;}         // Gender is an enum
    public DateTime BirthDate {get; set;}
    ...
}

Of course you don't save the patient's age in the database. If you did, you'd have to update your database daily.

public int Age => // some formula to get the Age from the current Date

Use DateTime.ToDay, Patient.BirthDate, and Today.DayOfYear >= BirthDate.DayOfYear

Fetching data from the database is done in a repository class. All that users of the class (= code, not operators) want to know is, that they can Store Patients in it, and fetch them back, even if the program is restarted. They don't care whether you store it in a database, or in an XML file, or maybe even store it somewhere in the internet.

This will also give you the freedom to change this, without users noticing.

class PatientRepository
{
    public string DbConnectionString {get; set;}

    public Patient FetchPatient(int patientId)
    {
        const string sqlTextFetchPatient = "select top 1"
        + " id,name,gen,age,date,cont,addr,disease,status,r_type,building,r_no,price"
        + " from patient"
        + " where id = @Id;";

        using (var connectedDb = new SqlConnection(this.DbConnectionString)
        {
            using (var dbCommand = connectedDb.CreateCommand())
            {
                dbCommand.CommandText = sqlTextFetchPatient;
                dbCommand.Parameters.AddWithValue("@Id", patientId);
                connectedDb.Open();

                using (var dbReader = dbCommand.ExecuteReader())
                {
                    // expect only one Patient or null
                    if (dbReader.Read())
                    {
                        // there is a Patient:
                        return new Patient
                        {
                            Id = dbReader.GetInt32(0),
                            Name = dbReader.GetString(1),
                            Gender = (Gender)dbReader.GetInt32(2),
                            BirthDate = dbReader.GetDateTime(3),
                            ...
                        }
                    }
                }
            }
        }
    }
}

Of course your PatientRepository will also have methods to Add / Update / Remove Patients.

By the way, did you see that I used using for every IDisposable object? This way you can be certain that the objects are Disposed as soon as you don't need them anymore, even after exceptions.

Furthermore, I made patientId a parameter and I only selected Top 1.

It seems that you want to show several Patients in a DataGridView. Add the following to your PatientRepository:

IEnumerable<Patient> FetchAllPatients()
{
    ... same as above
    while (dbreader.Read())
    {
        yield return new Patient
        {
            Id = dbReader.GetInt32(0),
            ...
        }
    }
}

Or maybe You want to fetch Patients "per page"

IEnumerable<Patient> FetchPatientPage(int pageNr, int pageSize)

Do OrderBy and Skip PageNr * PageSize items and Select PageSize items. How to do this depends on your Sql dialect.

Now that we have a method to Fetch a Patient, you can easily unit test it. If you did, you will probably have found your error.

Display fetched patients

Somewhere in your form you have a method to fetch the Patients that you want to show:

private readonly string dbConnectionString = ...

protected Repository PatientRepository {get;} = new PatientRepository(this.dbConnectionString);

protected IEnumerable<Patient> FetchPatients()
{
    this.PatientRepository.FetchPatients();
    // or fetch per page
}

You want to show them in a DataGridView. Using visual studio designer, you have code like this:

DataGridView dgv1 = new DataGridView();
DataGridViewColumn columnId = new DataGridViewColumn();
DataGridViewColumn columnName = new DataGridViewColumn();
DataGridViewColumn columnGender = new DataGridViewColumn();
...

columnId.DataPropertyName = nameof(Patient.Id);
columnName.DataPropertyName = nameof(Patient.Name);
columnGender.DataPropertyName = nameof(Patient.Gender);

If you only want to Display the Patients:

this.dgv1.DataSource = this.FetchPatients().ToList();

This is display only. If you want to enable editing you should put the Patients in an object that implements IBindingList, like a BindingList

this.dgv1.DataSource = new BindingList(this.FetchPatients().ToList());

Now all changes that the operator makes: edit cells / add new row / delete rows, etc are automatically updated in the BindingList.

A proper design would add the following methods to your form:

BindingList<Patient> DisplayedPatients
{
    get => (BindingList<Patient>)this.dgv1.DataSource;
    set => this.dgv1.DataSource = value;
}

And if you want to handle items in selected item

Patient CurrentPatient => this.dgv1.CurrentRow?.DataBoundItem as Patient;

IEnumerable<Patient> SelectedPatients => this.dgv1.SelectedRows
    .Select(row => row.DataBoundItem)
    .Cast<Patient>();

After this, handling removed / added / changed Patients will be one-liners.

To display a Patient in your text boxes:

void DisplayPatient(Patient patient)
{
    this.TextId = patient.Id;
    this.TextBoxName = patient.Name;
    ...
}

To Display the current Patient in your text boxes:

public void DataGridViewCurrentCellChanged(object sender, ...)
{
    this.DisplayPatient(this.CurrentPatient);
}
Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116
0

You could use Dapper Makes Life Easy with less Code;

       using Dapper;

create a class like

          public class Patient
        {
         public int id { get; set; }
         public string name { get; set; }
         public string gen { get; set; }
         public int age { get; set; }
           }

create a method to get Data

  var ConnectionString=  @"Data Source=DESKTOP-A85V0ME\SQLEXPRESS;Initial 
         Catalog=Hospitalmanagement;Integrated Security=True");

         public Patient GetPatient(int id)
            {
              using (IDbConnection con = new SqlConnection(ConnectionString))
             {
                 if (con.State == ConnectionState.Closed)
                     con.Open();
                   return con.QueryFirstOrDefault<Patient>("select * from Patient 
                          where id=@id", new {id},
                commandType: CommandType.Text);
        }

    }

call your method on Button Click event like

    private void button1_Click(object sender, EventArgs e)
    {
          var id = Convert.ToInt32(textBox1.Text);
          var data = GetPatient();
          if (data != null)
           {
               textBox1.Text = data.id.ToString();
               textBox2.Text = data.name;
               textBox2.Text = data.age.ToString();
                if (data.gen == "Male")
                {
                   radioButton1.Checked = true;
                  }
                  else if (data.gen == "Female")
                 {
                     radioButton2.Checked = true;
                  }
           // ...............etc
        }
    }