C# IQueryable not working - c#

I have a findAll function that gets all the records from a Contacts table in the Database and then filters them depending on which values the user selected in the search form. The results are filtered one filter at the time.
IQueryable<Contact> resultContacts = db.Contacts;
if(request['Name'] != "")
{
resultContacts = resultContacts.Where(a => a.Name.Contains(Name));
}
if(request['Phone'] != "")
{
resultContacts = resultContacts.Where(a => a.Phone.Equals(Phone));
}
if(request['Company'] != "")
{
resultContacts = resultContacts.Where(a => a.Company.Contains(Company));
}
return resultContacts;
The problem is that now this is not working. The resultContacts.Where inside each if is resetting to the original resultContacts I had on the first line for some reason. For instance: when I debug, the changes apply inside the 1st if (I end up with 10 out of 100 records), but when I go into the 2nd if, the code is querying the original resultContacts, not the 10 I had as a result of the first if.
This worked fine for over a year until 2 weeks ago. I don't know if something changed on my code... if I added a reference or something that make this change.
Any idea why?
Thank you!

var results = db.Contacts
.Where(a => request["Company"] == String.Empty || a.Company.Contains(Company))
.And(a => request["Phone"] == String.Empty || a.Phone.Equals(Phone))
.And(a => request["Name"] == String.Empty || a.Name.Contains(Name)));

Related

Most efficient way to create a dynamic LINQ query that depends on multiple search fields? [duplicate]

This question already has answers here:
How can I conditionally apply a Linq operator?
(13 answers)
Closed 4 years ago.
I'm creating a web application that retrieves data from the database based on the criteria entered.
The problem is that I have 10 different search fields and only one of them is required to be filled, the rest can be null.
So what I have is:
Textbox1
Textbox2
..
..
Textbox10
My current query is:
checked = false;
if (Textbox1.Text != null)
{
result = //query here
checked = true;
}
if (Textbox2.Text != null)
{
if(checked==false)
{
result = //new query here
checked = true;
}
else
{
result = results.Where(...new query to filter Textbox2 from previous
query)
}
}
and so on.
How can I build this in one query and ignore the textboxes that don't have values?
Thanks
As you mentioned in your question you only need to narrow your query on each step.
var result = //query here
if (Textbox1.Text != null)
{
result = result.Where(r=> r.x == Textbox1.Text);
}
if (Textbox2.Text != null)
{
result = result.Where(r=> r.y == Textbox2.Text);
}
...
return result;
An alternative approach is to do the null/empty check inside the query itself, using an || operator along with the conditional check if the text property has a value, inside parenthesis to form a "sub clause". Because the || operator will return true as soon as one side evaluates to true, and evaluation is done from left to right, always put the null/empty check first.
In this way, each "sub clause" returns true if the textbox text is null or empty, or it will returns the evaluation of the condition based on the text value of that textbox. Effectively, this "ignores" the text property for textboxes that are null or empty:
var result = data.Where(d =>
(string.IsNullOrEmpty(Textbox1.Text) || d.X == Textbox1.Text) &&
(string.IsNullOrEmpty(Textbox2.Text) || d.Y == Textbox2.Text) &&
(string.IsNullOrEmpty(Textbox3.Text) || d.Z == Textbox3.Text));

Use winform checkbox to linq query

Hope I am asking this question in the right way.
I am trying to determine the most efficient way to use checkboxes to alter what is returned from my linq query without having to code for every possible combination.
As an example, I have three checkboxes on my winform that represent three columns that I am trying to query
[ ] Year
[ ] Make
[ ] Model
I am using a linq statement to determine the distinct combinations of year make and model through EF
var uniquecombos = cb.MakeModelYear.Where(i => i.Year != null && i.Make != null && i.Model != null).Distinct().ToList();
What I would like to do is use the checkboxes on my winform to drive which fields I include in my query.
So
[x] Year
[x] Make
[ ] Model
would yield
var uniquecombos = cb.MakeModelYear.Where(i => i.Year != null && i.Make != null).Distinct().ToList();
Is there a good way to modify the inputs of the query without having to account for every combination of checkboxes through if statements?
Thanks in advance!
Since you have separate properties you still ned to hceck each one - but you can account for each checkbox combination at the same time:
.Where(i => (
(!cbxYear.Checked || i.Year != null) &&
(!cbxMake.Checked || i.Make != null) &&
(!cbxModel.Checked || i.Model != null)
)
You can do something like this :
var query = cb.MakeModelYear;
if (chkYear.Checked)
query = query.Where(i => i.Year != null);
if (chkMake.Checked)
query = query.Where(i => i.Make != null);
if (chkModel.Checked)
query = query.Where(i => i.Model != null);
var uniquecombos = query.Distinct().ToList();

Prevent Duplicates From Being Saved In Database

I have produced an console application which saves data using Entity Framework , I have a table which is designed like this:
ID People_ID People_Address People_Postcode
--- ---------- -------------- ----------------
1 2 76 Nation Road B27 8NT
2 7 88 Grimestone Road B45 9WG
3 12 45 Wallock Road B22 4UI
To ensure duplicates are not be stored within the table the following code has been written:
ppl.People_Address = Address;
ppl.People_Postcode = Postcode;
ppl.People_ID = usr.ID;
If(db.tbl_people.Any(x=> x.people_address != ppl.People_Address) && (db.tbl_people.Any(x=> x.people_postcode != ppl.People_Postcode) && (db.tbl_people.Any(x=> x.People_ID != ppl.People_ID) {
db.tbl_people.Add(ppl)
db.SaveChanges();
}
However nothing is being added regardless if nothing exists in the table to compare to , any help??
You will need to check for each of your fields if they are null. For example:
x.people_address != ppl.People_Address || x.people_adress == null
The problem is the condition
if (db.tbl_people.Any(x=> x.people_address != ppl.People_Address)
&& (db.tbl_people.Any(x=> x.people_postcode != ppl.People_Postcode)
&& (db.tbl_people.Any(x=> x.People_ID != ppl.People_ID)
it should really be
if (!db.tbl_People.Any(x => x.people_address == ppl.People_Address
&& x.people_postcode == ppl.People_Postcode
&& x.People_ID == ppl.People_ID))
{
// No duplicate
}
There are few problems with this code.
First, you should not cause the database many times per calling "db.tbl_people" property getter. Do it one time and don't retrieve whole db collection.
Second, for the empty database
db.tbl_people.Any(x=> x.people_address != ppl.People_Address)
returns false because there is no entities in the tbl_people collection.
And the third your condition is not really check duplicates in the database.
Your query can be looks like code below:
// if there is no entities with same properties
if(db.tbl_people.Count(p => p.people_address == ppl.People_Address
&& p.people_postcode == ppl.People_postcode
&& p.People_ID == ppl.People_ID) == 0)
{
// then save new entity
db.tbl_people.Add(ppl)
db.SaveChanges();
}
This code will generate query to the database which will return just scalar variable and it'll be better to performance and communication channel.

comparing 2 lists of objects and return changes in the new list

I have a web app that gives users a feature to update (no delete or add) multiple records on the same page. As users submit changes, I pull the original list from the database and use linq to compare it to the updated list. Any changed records will be put on a new list and send to database for update.
Below is my code to compare. As I debug, I can see the 2 lists are different but the code returns the Differences with comparer = null, first = null, second = null. Can you guys spot the bug?
var Differences = OriginalList.Where(x => !NewList.Any(x1 => x1.ServiceName == x.ServiceName
&& x1.ServiceDescription == x.ServiceDescription
&& x1.ServiceURL == x.ServiceURL
&& x1.OrderIndex == x.OrderIndex
&& x1.GroupID == x.GroupID
&& x1.Active == x.Active))
.Union(NewList.Where(x => !OriginalList.Any(x1 => x1.ServiceName == x.ServiceName
&& x1.ServiceDescription == x.ServiceDescription
&& x1.ServiceURL == x.ServiceURL
&& x1.OrderIndex == x.OrderIndex
&& x1.GroupID == x.GroupID
&& x1.Active == x.Active)));
return Differences;
You are probably looking for Linq's Except method.
https://msdn.microsoft.com/library/bb300779(v=vs.100).aspx
You'll need to define how to compare for equality of your "x1" object. Probably the easiest way to do that is to override Equals():
https://msdn.microsoft.com/en-us/library/ms173147(v=vs.80).aspx
Then to get the difference, you simply do:
var Differences = OriginalList.Except(NewList);

Improve Duplicate check method

Morning guys.
Using C sharp .net4, and MS Visual Studio 2010.
I have Developed a duplication checker for my windows form program.
It works perfectly and Is virtually Instant on my Datagrid when there are a couple hundred records.
The problem I've noticed is that when there are 6000 records displayed it is not efficient enough at all and takes minutes.
I was wandering if anyone has some good tips to make this method a lot faster either improving upon the existing design or, a different method all together that I've over looked.
Your help is once again much appreciated!
Here's the code:
public void CheckForDuplicate()
{
DataGridViewRowCollection coll = ParetoGrid.Rows;
DataGridViewRowCollection colls = ParetoGrid.Rows;
IList<String> listParts = new List<String>();
int count = 0;
foreach (DataGridViewRow item in coll)
{
foreach (DataGridViewRow items in colls)
{
count++;
if ((items.Cells["NewPareto"].Value != null) && (items.Cells["NewPareto"].Value != DBNull.Value))
{
if ((items.Cells["NewPareto"].Value != DBNull.Value) && (items.Cells["NewPareto"].Value != null) && (items.Cells["NewPareto"].Value.Equals(item.Cells["NewPareto"].Value)))
{
if ((items.Cells["Part"].Value != DBNull.Value) && (items.Cells["Part"].Value != null) && !(items.Cells["Part"].Value.Equals(item.Cells["Part"].Value)))
{
listParts.Add(items.Cells["Part"].Value.ToString());
dupi = true; //boolean toggle
}
}
}
}
}
MyErrorGrid.DataSource = listParts.Select(x => new { Part = x }).ToList();
}
Any Questions let me know and I will do my best to answer them.
If you can, you should try and do this on the underlying data rather than on the UI objects - however I have a hunch that you're seeding it from a set of DataRows, in which case you might not be able to do that.
I think a big part of the issue here is the repeated dereferencing of the cells by name, and the fact that you repeatedly deference the second set of cells. So do it all up front:
var first = (from row in coll.Cast<DataGridViewRow>()
let newpareto = row.Cells["NewPareto"].Value ?? DBNull.Value
let part = row.Cells["Part"].Value ?? DBNull.Value
where newpareto != DBNull.Value && part != DBNull.Value
select new
{ newpareto = newpareto, part = part }).ToArray();
//identical - so a copy-paste job (if not using anonymous type we could refactor)
var second = (from row in colls.Cast<DataGridViewRow>()
let newpareto = row.Cells["NewPareto"].Value ?? DBNull.Value
let part = row.Cells["Part"].Value ?? DBNull.Value
where newpareto != DBNull.Value && part != DBNull.Value
select new
{ newpareto = newpareto, part = part }).ToArray();
//now produce our list of strings
var listParts = (from f in first
where second.Any(v => v.newpareto.Equals(f.newpareto)
&& !v.part.Equals(f.part))
select f.part.ToString()).ToList(); //if you want it as a list.
There is an approach that will make this much more efficient. You need to compute a hash of each item. Items with different hashes can't possibly be duplicates.
Once you have the hashes, you could either sort by hash or use a data structure with efficient keyed retrieval (like Dictionary<TKey,TValue>) to find all the duplicates.

Categories

Resources