Searching a access database for a part of a word - c#

I have an access database that contains columns such as Title, Director, And Year.
I have access database connected to the program. I am able to search the database and print out the title of the movie to a listBox only if the title contains the one word. For example, if I search for the movie "psycho" the movie will display in the listBox.
Now I'm wondering how I can search for a particular word like "the" and print all the movie titles with "the" in it to the listBox.
At that point, the text book I'm using fails to go into anything deeper.
Maybe I'm not using the right method for what I'm trying to do.
private void searchButton_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
string lowerCaseData = textBox1.Text.ToLower();
if (titleButton.Checked)
{
var query =
from m in this.moviesDataSet.Movies
where m.Title == lowerCaseData
select m;
foreach (var m in query)
{
listBox1.Items.Add(m.Title);
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'moviesDataSet.Movies' table. You can move, or remove it, as needed.
this.moviesTableAdapter.Fill(this.moviesDataSet.Movies);
}

Instead of exact match check for Contains
Depending on the LINQ provider, Contains check should be translated to SQL LIKE statement which will be case insensitive, so your check should be:
where m.Title.Contains(lowerCaseData)
However for in-memory collections, Contains would perform a case sensitive match. In that case String.IndexOf can be used like:
where m.Title.IndexOf(lowerCaseData, StringComparison.OrdinalIgnoreCase) >= 0)

Your where query is doing an exact match. Use Contains instead
where m.Title.ToLower().Contains(lowerCaseData)

Related

Clear Search Result in EntityFrameWork

I have a database called Employee and I am using entity framework version 6.1.3.
In my wpf application, I have button called Search, one textbox( searchField) for search field and a datagrid ( employeedatagrid)
When i enter input in search field, it gives expected output in datagrid view but after that when i enter again different input in searchfield, it just prints the new data just below the previous data. What I want is; When i enter different search field , then If there is already data in datagrid, I want to remove those old data from datagrid and prints only the new data.
Below is my C# Code
private void Search_Click(object sender, RoutedEventArgs e)
{
this.employeeDataGrid.ItemsSource = null;
this.employeeDataGrid.Items.Clear();
var text = SearchField.Text;
var query = employeeModel.Employees.Where(x => x.Country == text).Select(y => y);
foreach (var item in query)
{
employeeDataGrid.ItemsSource = employeeModel.Employees.Local;
}
}
Can anyone point out, what I am missing here ?
thanks.

I'm getting "System.Collections.Generic.List" instead of data from database

I'm working on a project to develop a UWP app. I have implemented Sqlite database to store information about products.
I have a combobox in my page that displays the serial number of all the products. I've written the code for SelectionChanged event of the combobox as:
private void InvoiceSerial_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var a = conn.Query<Product>
("select brand from product where serial=?", InvoiceSerial.SelectedItem.ToString());
InvoiceBrand.Text = a.ToString();
}
But instead of displaying the brand name, I'm getting this:
System.Collections.Generic.List`1[MyProject.Inventory+Product]
InvoiceBrand is a textbox
Even if the result of an SQL query is exactly one row and one column, query functions in any language are still required to return a full table, to handle the general case where a resultant table has multiple items. The object you're looking for should be the first object in the list.
Your a variable is probably of type List<MyProject.Product>, and that's why calling a.ToString() returns the string representation of the type!
What you should probably be doing is retrieving the first element (just use a[0]) and then output the value of the "brand" field.
Ok so I got it to work thanks to #TimSchmelter
Now my code looks like this:
private void InvoiceSerial_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var a = conn.Query<Product>
("select brand from product where serial=?", InvoiceSerial.SelectedItem.ToString());
Product p = a.FirstOrDefault();
InvoiceBrand.Text = p.Brand;
}

How to execute advance Listview Search

Using Windows forms, My 'listview' have multiple columns as shown in the picture.
I have been trying to make this txtbox_search to be advanced. When any character, word or number is inserted, i want Some columns of my listview to be traversed to look for the character, word, number and bring up data related to the input.
Like when i enter: txtbox_search.Text = "a"
It should travers column "Name" and fill Listview with data:
entire row that has a name which starts with "a" such as "Anwar"
entire row that has a name which starts with "a" such as "Anas"
so on with entire rows that has a name which starts with "A..."
when i enter: txtbox_search.Text = "1"
It should travers column "ID" and fill Listview with data:
entire row that has a ID which starts with "1" such as "1002"
entire row that has a ID which starts with "1" such as "1112"
so on with entire rows that has a ID which starts with "1..."
so far i have been trying this for 2 days and end up with this much:
private void textBox_DEC_Search_TextChanged(object sender, EventArgs e)
{
foreach(ListViewItem Items in listView_DEC_CustomerList.Items)
{
if(Items.Text == textBox_DEC_Search.Text)
{
listView_DEC_CustomerList.Items.Clear();
listView_DEC_CustomerList.Items.Add(Items);
}
}
if(textBox_DEC_Search.Text == "" || textBox_DEC_Search.Text == string.Empty)
{
CusList Cus = new CusList();
Cus.CustomersList(listView_DEC_CustomerList);
}
}
This code only travers first column and bring up data that matches the inserted ID, only if the Complete ID matches with txtbox_search.Text how can i make this possible? (i want it to be on client side, not from sql/database). Guides and sample code helps will be really appreciated. Thanks.
To distinguish between your 2 criteria you could use the following:
if (textBox_DEC_Search.Text.All(x => Char.IsNumber(x)))
{
Debug.WriteLine("Number");
// search through ID
}
else
{
Debug.WriteLine("Name");
// search through Name
}
It basically checks whether your input is solely numeric.
EDIT:
To check for similarity you cold use String.StartsWith of String.Contains to make the search a little more flexible
to look for the ID or NAME you need to access the subitems!
since ID is your first column check SubItems[0]
if(Items.SubItems[0].Text.StartsWith(textBox_DEC_Search.Text) ||
Items.SubItems[0]Text.Contains(textBox_DEC_Search.Text))
since NAME is your second column check SubItems[1]
if(Items.SubItems[1].Text.StartsWith(textBox_DEC_Search.Text) ||
Items.SubItems[1]Text.Contains(textBox_DEC_Search.Text))
One Problem is this line:
listView_DEC_CustomerList.Items.Clear();
because it will erase the first found result when the second is found.
So if you find 10 matches the previous 9 will be deleted!
I suggest to make first the entire search and then add the results if there are any:
private void textBox_DEC_Search_TextChanged(object sender, EventArgs e)
{
// index is 0 if numeric for ID or 1 if not for NAME
int ind = textBox_DEC_Search.Text.All(x => Char.IsNumber(x)) ? 0 : 1;
List<ListViewItem> matchlist = new List<ListViewItem>();
foreach(ListViewItem Items in listView_DEC_CustomerList.Items)
{
if(Items.SubItems[ind].Text.StartsWith(textBox_DEC_Search.Text) ||
Items.SubItems[ind]Text.Contains(textBox_DEC_Search.Text))
{
matchlist.Add(Items);
}
}
// if you have found something add the all results
if(matchlist.Any())
{
listView_DEC_CustomerList.Items.Clear();
listView_DEC_CustomerList.Items.AddRange(matchlist.ToArray());
}
}
Disclaimer: Although this solution should work I would vote to follow the advice of #RezaAghaei. It is less messy and confusing than directly manipulating the ListView
Instead of using == which looks for an exact match try one of the following (I am assuming 'Text' is the column name in the list containing the name - if not change it to Items.Name (for example)
if you want to search on 'starting with' then try
if (Items.Text.StartsWith(textBox_DEC_Search.Text.Trim())
if you want to search based on the fact that a part of the string should be looked up then try
if (Items.Text.Contains(textBox_DEC_Search.Text.Trim())
You can similarly do for any other column you would like to search on. if you want to make the search case insensitive then use .ToLower() on the string and the column name.

Search anywhere in list, not just the first letter

What I want to do, is to search in a ComboBox, for a word, or a part of a word like this:
For example I have these entries in my combobox:
abc
Abc
Dabc
adbdcd
And when I search for "abc", it should show me every one in the list, except "
adbdcd"
I fill my combobox from a mysql database, so my items are in a "Collection".
I have autocomplete enabled (mode: SuggestAppend, source: ListItems)
This is the code, I am using right now:
private void comboBox1_KeyPress(object sender, KeyPressEventArgs e)
{
comboKeyPressed();
}
private void comboBox1_TextChanged(object sender, EventArgs e)
{
if (comboBox1.Text.Length == 0) comboKeyPressed();
}
private void comboKeyPressed()
{
comboBox1.DroppedDown = true;
object[] originalList = (object[])comboBox1.Tag;
if (originalList == null)
{
// backup original list
originalList = new object[comboBox1.Items.Count];
comboBox1.Items.CopyTo(originalList, 0);
comboBox1.Tag = originalList;
}
// prepare list of matching items
string s = comboBox1.Text.ToLower();
IEnumerable<object> newList = originalList;
if (s.Length > 0)
{
newList = originalList.Where(item => item.ToString().ToLower().Contains(s));
}
// clear list (loop through it, otherwise the cursor would move to the beginning of the textbox...)
while (comboBox1.Items.Count > 0)
{
comboBox1.Items.RemoveAt(0);
}
// re-set list
comboBox1.Items.AddRange(newList.ToArray());
}
The problem with this code, is if I search for "abc" in my example list, "adbdcd" will show up too. And this code randomly crashes my program when I hit backspace in the combobox.
This is the root cause of crash:
while (comboBox1.Items.Count > 0)
{
// this is raising exception if you try to remove the last item
// Check the doc of RemoveAt
comboBox1.Items.RemoveAt(0);
}
use that instead:
comboBox1.Items.Clear();
However what you are trying to achieve is still unclear.
If Text of combox is empty, then nothing will ever happen apart from clearing and re adding the same items to the combo box.
My understanding is that you're trying to duplicate the completion behavior while having it enabled. It can raise exception too (AccessViolationException) since you try to modify the Items collection while the framework tries to do the same.
If you're not happy with the default auto completion behavior, disable it and try to implement it completely inside the comboKeyPressed method.
It means then calling it whenever text is modified.
Modification of your code to make it work (Disable auto completion though):
private void comboBox1_TextChanged(object sender, EventArgs e)
{
comboKeyPressed();
}
private void comboKeyPressed()
{
if (comboBox1.Text == lastFilter)
{
return;
}
object[] originalList = (object[]) comboBox1.Tag;
if (originalList == null)
{
// backup original list
originalList = new object[comboBox1.Items.Count];
comboBox1.Items.CopyTo(originalList, 0);
comboBox1.Tag = originalList;
}
// prepare list of matching items
string s = comboBox1.Text.ToLower();
IEnumerable<object> newList = originalList;
if (s.Length > 0)
{
newList = originalList.Where(item => item.ToString().ToLower().Contains(s));
}
// clear list (loop through it, otherwise the cursor would move to the beginning of the textbox...)
comboBox1.Items.Clear();
// re-set list
comboBox1.Items.AddRange(newList.ToArray());
comboBox1.Select(Text.Length -1, 0);
lastFilter = comboBox1.Text;
comboBox1.DroppedDown = true;
}
So, you want fulltext search.
Where is your data coming from? What kind of data is it? What are the edge cases?
For databases, I like to use Sphinx for fulltext indexing.
For in-memory data, efficient fulltext search algorithms include Suffix Arrays, Suffix Trees, and Patricia Tries. Implementing them can be a fun (and time-consuming) challenge. Or you might find a suitable implementation online. You can find barebones implementations of these algorithms, as well as more polished implementations of fulltext search, such as Lucene.
To give you a sketch of how they work, imagine taking every possible suffix of every word that you store, e.g. needle:
needle
eedle
edle
dle
le
e
Put all these suffixes into an ordered data structure, such as a sorted array or list (for static data) or a B-tree or SortedDictionary (if data is added regularly). After inserting needle, it would contain:
dle
e
edle
eedle
le
needle
Now we can search for any part of a word (e.g. edl) using binary search or better, and see if we have a hit.
To extract more information than just whether or not we have a hit, we could add data to, for example, the values of the SortedDictionary. (We used the suffixes as keys.) Interesting data could be the entire word, or perhaps the original text and location where the word was encountered.
If the number of entries to search from is always low - perhaps no more than a few hundred - then a simple implementation will suffice.
// Select all words that contain our query string
var matchingWords = wordList.Where(word => word.Contains(query));
This is the naive, linear implementation that will become very slow for large data. For small data, though, it is super easy. Just feed the new subset to your combo box.
You might want to add case-insensitivity to the Contains() call, using its optional second parameter.

Two conditions checking on listview group items

I have list view (with one column). I have divided this list view into two groups like in the figure below.
My problem is: how can I find selection event like this: If I click on odd group item ("one") and then if I click on even group item ("two"), I want to do something.
How can I check these two conditions in a single if statement? These two conditions are the ones that need to be done in a single if statement. Is it possible to use a single condition?
I am using C# and WinForms apps. Would anyone please help on this?
EDIT :
Category names
name 1
name 2
name 3
prices
>100
>200
300+
If I click on category name and then I click on the price range, I want to do something. Is it possible to do both in single condition checking?
Try using the SelectedIndexChanged event like so:
void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
var selectedItems = listView1.SelectedItems.Cast<ListViewItem>();
var passed = (selectedItems.Select(l => l.Group.Name).Distinct().Count() == 2 && selectedItems.Count() == 2);
if (passed)
{
//Do something...
}
}
Edit (based on comments)
To retrieve each selected item use the following:
Note: For the below code to work you would need to set the Name property of each of your ListViewGroup's to "Category" and "Prices" respectively.
void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
var selectedItems = listView1.SelectedItems.Cast<ListViewItem>();
var passed = (selectedItems.Select(l => l.Group.Name).Distinct().Count() == 2 && selectedItems.Count() == 2);
if (passed)
{
var categoryItem = selectedItems.Where(l => l.Group.Name.ToLower() == "category").Single();
var priceItem = selectedItems.Where(l => l.Group.Name.ToLower() == "prices").Single();
}
}

Categories