0

I am showing some sql table results in data grid view in winforms app. I normally use DbEntities but i had to use join in my query to get results from multiple results, so instead i used this code.

And i want to add a query and a textbox to search results while typing. How can i do that from what i already started?

        SqlConnection con = new SqlConnection("server=.; Initial 

        Catalog=winforms;Integrated Security=SSPI");

        DataTable dt = new DataTable();

        string sql = "SELECT Personel.ad, Personel.soyad, Personel.tc, Personel.dogum, Personel.isgiris, Birim.birimad AS [Birim], Sube.subead AS [Şube] FROM Personel JOIN Birim ON Birim.birimid = Personel.birimid JOIN Sube ON Sube.subeid = Personel.subeid";

        con.Open();
        SqlDataAdapter da = new SqlDataAdapter(sql, con);
        da.Fill(dt);
        dataGridView1.DataSource = dt;
Mert
  • 17
  • 8
  • Hello Mert, welcome to stackoverflow. What have you tried so far in code besides the SQL setup? – usselite Aug 22 '19 at 06:37
  • Do you mean you start the screen with the grid filled up and you want to do a client side filtering/search or do you want to retrieve data from sql every time? In any case, I think this question is a bit too broad. – AsheraH Aug 22 '19 at 06:42
  • Hello, sorry if i couldnt explain my problem properly. usselite, i tried stored procedure. AsheraH, your first sentence is exactly what i want. I am already starting the screen with the grid filled up, and i want to do a client side filtering/search to show results while i am typing. – Mert Aug 22 '19 at 06:44
  • simply filter the datatable `dt` in the `TextChanged` event of the textbox – GuidoG Aug 22 '19 at 06:46

3 Answers3

0

You can use TextChanged event for textbox and send the text to the function as parameter. Then add the text to the WHERE clause on SQL query.

Be careful about user inputs for querying SQL. This is just an example, not very safe.

void textBox1_TextChanged(object sender, EventArgs e)
{
    CallSQL(textBox1.Text);
}

void CallSQL(string filterText)
{
...
...
 string sql = string.Format("SELECT ... WHERE Personel.Ad = {0}", filterText);
...
...
}
Ömer Baş
  • 98
  • 1
  • 7
  • you could also just filter the datatable instead – GuidoG Aug 22 '19 at 06:45
  • Where in sql is definetly better but you could also search a DataTable `DataTable dtResult= tb.Select("Personel.Ad LIKE '%"+searchstring+"%'").CopyToDataTable();` – D. Dahlberg Aug 22 '19 at 06:46
  • I will try that, thank you. And will that work as i type the name in textbox? – Mert Aug 22 '19 at 06:47
  • If you use sql filtering, then never ever teach anyone here to use queries without parameters – GuidoG Aug 22 '19 at 06:48
  • You are right about parameters but it's just an example based on the code in question. – Ömer Baş Aug 22 '19 at 06:53
  • What do you mean by never teach anyone to use queries without parameters? – Mert Aug 22 '19 at 06:55
  • @Mert building a query (in any language) should always be parametrized, to avoid sql injection. – GuidoG Aug 22 '19 at 06:57
  • @GuidoG thank you i will keep that in mind, and what can you tell me about KeyUp event, i guess i can use that too. – Mert Aug 22 '19 at 07:05
  • @Mert I useally use the KeyDown event for this. in this event (or the KeyUp) you have more control, like for example only start the filtering after pressing enter – GuidoG Aug 22 '19 at 07:09
0

Found this answer to search in DataTable.

So for your solution you would need to implement

public static DataTable SearchInAllColums(this DataTable table, string keyword, StringComparison comparison)
{
    if(keyword.Equals(""))
    {
        return table;
    }
    DataRow[] filteredRows = table.Rows
       .Cast<DataRow>()
       .Where(r => r.ItemArray.Any(
       c => c.ToString().IndexOf(keyword, comparison) >= 0))
       .ToArray();

    if (filteredRows.Length == 0)
    {
        DataTable dtProcessesTemp = table.Clone();
        dtProcessesTemp.Clear();
        return dtProcessesTemp;
    }
    else
    {
        return filteredRows.CopyToDataTable();
    }
}

And then you could use it in your changeevent:

void textBox1_TextChanged(object sender, EventArgs e)
{
    SqlConnection con = new SqlConnection("server=.; Initial 

    Catalog=winforms;Integrated Security=SSPI");

    DataTable dt = new DataTable();

    string sql = "SELECT Personel.ad, Personel.soyad, Personel.tc, Personel.dogum, Personel.isgiris, Birim.birimad AS [Birim], Sube.subead AS [Şube] FROM Personel JOIN Birim ON Birim.birimid = Personel.birimid JOIN Sube ON Sube.subeid = Personel.subeid";

    con.Open();
    SqlDataAdapter da = new SqlDataAdapter(sql, con);
    da.Fill(dt);

    dataTable.SearchInAllColums(textBox1.Text, StringComparison.OrdinalIgnoreCase);

    dataGridView1.DataSource = dataTable;
}

HOWEVER: Doing it like this will cause alot of traffic to your sql server. I would strongly suggest you to also implement some form of cache here for getting all searchable data. If that's an option.

D. Dahlberg
  • 156
  • 1
  • 9
  • Thanks for your answer. I am going to try that. But i created a Stored Procedure for searching used that in winforms in order to fill the DataGridView. And i used that function in my TextChanged event and it worked. Do you think my way would cause a lot of traffic in my Sql Server or may this be insecure in any way? – Mert Aug 22 '19 at 08:28
  • @Mert ofcourse it will. Everytime the change event is triggered(add character or remove character) you go down and get data from db. As for "insecure", it would be secure if you used SqlParameters. ex. `da.SelectCommand.Parameters.Add( "@searchText", SqlDbType.VarChar).Value = textBox1.Text;` then ofcourse you need to define @searchText as a param in your sql query – D. Dahlberg Aug 22 '19 at 08:53
  • I see. I have two more questions. 1) I am aiming for a small app for a small company. That traffic in sql server you talked about, would it significantly effect my app? 2) I used AddWithValue instead of Add, is that similar to Add, security-wise? Thanks again – Mert Aug 22 '19 at 08:59
  • @Mert , That depends on your server. Also in the long run if the company grows and everyone uses it then it's bound to get slow. 2, read [this](https://stackoverflow.com/a/21110078/8380785). Not sure about security differences but it could cause other issues – D. Dahlberg Aug 22 '19 at 09:09
  • For now it looks like only one person is going to use it and company does not have more than 50 employees. I think that should not be a problem. – Mert Aug 22 '19 at 10:03
  • Then sure go ahead. I would still advice for cache because it will improve speed in your search since it only has to look in memory instead of db. If you do need live data then caching could get trickier since you need to recache on add, remove and update. Mark as answer if you found what you're looking for. – D. Dahlberg Aug 22 '19 at 10:13
0

just o add to the question and futures similiar problems:

Do not use SQL as "insta-search" on textchanged proprieties. Its bad for many reasons as people mentioned above. But first of all, you can have problems by locking up SQL tables for having people trying so search something and generating alot of traffic as consequence, and even for one user, its unsafe and unfriendly to resources.. Besides, you have a high traffic for SQL injection. There are some good programming practices to make it safer, i'll try to elucidate a little more.

Okay, you already know this piece of information. But how the Correct way to do it?

Use objects, DAL and cache info until its old enough and have to update it.

How:

First things first, you should create a DAL/DAO class that is used ONLY for sql querys and operations. Do some search on the subject and why is a bad idea to have your business rules and sql code scrambled togheter. Here some short text about it:About DAL/DAO

Then, create a class of objects. For example: PersonelInfo. Wich contains every attribute that you need, like: name,documents, etc.

Here some info about objects handling: Using Objects with C#

After having your object nice and done, use lists to store and pass it to datatable or directly to datagridview if you wich.

List<Objectname> listname = new List<Objectname>();

Then, use some loop to iterate through SQL data and fill your list.

Example:

while(dataReader.Read())
{
Object objectname = new Object();

objectname.attribute1 = dataReadet["columname"].ToString();
objectname.attribute2 = dataReadet["columname"].ToString();
objectname.attribute3 = dataReadet["columname"].ToString();
listname.Add(objectname);
}

at the end return your objectlist:

Return listname;

That way you have full organized object list that you can:

  • Use as base for cache. That list contains all information that user needs to search for. Search the list with a foreach loop and return desired values to the user. Just remember to update it when it gets old.
  • Use it as source for Datagridview or Datatable, its cheap.
  • Use it with JSON, it can be sent by API or simple UDP/TCP connection

Hope this short comment bring you some light with data handling.

Note that not every data is safe to keep that way. Passwords and protected stuff should not be stored in memory or other ways that can be exploited.