Counting the result LINQ - c#

I am using the following
var validLogin = from P in this.DataContext.Persons
where P.UserName.Equals(login) && P.Password.Equals(password)
select new
{
P.FirstName,
P.LastName,
P.EmailAddress
};
In this now i want to know, is there any result returned by this query? How to do this.

Don't use Count() - use Any() unless you actually care about the count.
You can actually simplify this a lot, because you don't use the rest of the results either:
bool validLogin = DataContext.Persons.Any(p => p.UserName == login &&
p.Password == password);
The nice thing about Any() is that whatever's processing the query can stop as soon as it's found any matching results - it doesn't need to keep looking for other potential matches. (Count() will work of course, it's just not as efficient, mostly because the operator itself isn't describing what you really care about as accurately.)

This should work:
if (validLogin.Count() > 0)
{
//do work
}

if (validLogin.Count() > 0){}

Related

Can anybody tell me why this linq query won't work?

Sorry if I'm missing something really obvious, I've been coding for a lot of hours in a row and my brain is crawling to a halt. I have the following statement:
var hcn = "";
var forename = "";
var surname = "";
foreach (var casenoteResult in casenoteResults)
{
personResults.AddRange(_ctx.People.Where
(x => x.PAS_INT_NO == casenoteResult.PAS_INT_NO
&& x.CSA_NO.Contains(hcn)
&& x.FORENAMES.ToLower().Contains(forename.ToLower())
&& x.SURNAME.ToLower().Contains(surname.ToLower()))
.ToList());
}
And I get no result. The only thing I'm really looking for is the casenote. Yet if I comment out each of the '&&'s, so I'm left with this:
foreach (var casenoteResult in casenoteResults)
{
personResults.AddRange(_ctx.People.Where
(x => x.PAS_INT_NO == casenoteResult.PAS_INT_NO)
.ToList());
}
I get 1 result, which is what I'm expected.
Can anyone help me? Why does the first statement not return this 1 result? Could it be that some of the fields that I'm comparing the empty strings to are null? The one record that gets found doesn't have any nulls in it. I'm lost here. Please help my poor battered brain!
If I were you, I would re-write this code like below. It's safer to build the queryable in parts to make sure you have a good handle on which values you are actually passing in to the query. The reason why you are not getting any rows is probably because the query values going in to the query is not what you think they are or your database doesn't treat empty string as a wildcard. (Because based on what you posted, you are checking if a string contains an empty string which is always true in C# but may not be true for your database provider).
var queryable = _ctx.People.Where(w => caseNoteResults.Select(s => s.PAS_INT_NO).Contains(w.PAS_INT_NO));
queryable = string.IsNullOrEmpty(hcn) ? queryable : queryable.Where(w => w.CSA_NO.Contains(hcn, StringComparison.InvariantCulture));
queryable = string.IsNullOrEmpty(forename) ? queryable : queryable.Where(w => w.FORENAMES.Contains(forename, StringComparison.InvariantCultureIgnoreCase));
queryable = string.IsNullOrEmpty(surname) ? queryable : queryable.Where(w => w.SURNAME.Contains(surname, StringComparison.InvariantCultureIgnoreCase));
personResults.AddRange(queryable.ToList());
The idea is, if your hcn, forename and surname are empty, no point in checking them.
Also, make sure that you handle nulls safely if each of these fields are nullable.

Can this be done entirely via linq?

I have a process where I identity rows in a list (unmatchedClient) then call a separate method to delete them (pingtree.RemoveNodes). This seems a little long winded and I could acheive the same thing by merely setting the value of the property "DeleteFlag" to true. But how do I set the value using linq?
var unmatchedClient = pingtree.Nodes.Where(x =>
_application.LoanAmount < x.Lender.MinLoanAmount ||
_application.LoanAmount > x.Lender.MaxLoanAmount ||
_application.LoanTerm < x.Lender.MinLoanTerm ||
_application.LoanTerm > x.Lender.MaxLoanTerm)
.Select(x => x.TreeNode)
.ToList();
pingtree.RemoveNodes(unmatchedClient);
Thanks in advance.
Like this?
pingtree.Nodes.Where(x =>
_application.LoanAmount < x.Lender.MinLoanAmount ||
_application.LoanAmount > x.Lender.MaxLoanAmount ||
_application.LoanTerm < x.Lender.MinLoanTerm ||
_application.LoanTerm > x.Lender.MaxLoanTerm)
.Select(x => x.TreeNode)
.ToList()
.ForEach(n=> n.DeleteFlag = true);
But how do I set the value using linq
You don't. Period.
Linq is a query language and querying is reading.
There is a back door that some people abuse to set values. In your case it would look like:
pingtree.Nodes.Where(...)
.Select(n => { n.DeleteFlag = true; return n; }
but this really is not done. Firstly because it is unexpected. Linq methods, including Select, are supposed to leave the source collection unchanged. Secondly because the statement itself does not do anything because of deferred execution. You'd have to force execution (e.g. by ToList()) to make it effective.
Maybe this looks like nitpicking, but when queries get a bit more complex it becomes a major point. It is not uncommon to do a projection (Select) followed by a filter (Where). You could have decided to do a filtering (where n.Deleted == false) after the projection for instance.
So, you query the objects using linq and then loop through them to do whatever needs to be done. ToList().ForEach() is one of the methods you can use to do that.
Side node: the back door that I showed would throw exceptions when using linq-to-sql or entity framework.

LINQ lambda expression append OR statement

If I want to append a AND statement to my query, I can do:
query = query.Where(obj=>obj.Id == id);
if(name.HasValue)
query = query.Where(obj=>obj.Name == name);
and it will give me:
query.Where(obj=>obj.Id == id && obj.Name == name)
How can I append a OR statement that will result in:
query.Where(obj=>obj.Id == id || obj.Name == name)
You can't do it natively. However, you can use PredicateBuilder to compose the query before you run it, and it supports ORs.
var predicate = PredicateBuilder.False<Product>();
predicate = predicate.Or (obj=>obj.Id == id);
if(name.HasValue) predicate = predicate.Or (obj=>obj.Name == name);
return query.Where(predicate);
Simply this if I'm not missing something:
query.Where(obj=>obj.Id == id || (obj.Name == name && name.HasValue))
You might want to read this question (my question...) and answer for more complicated scenarios:
How to filter IEnumerable based on an entity input parameter
I would just build this into a single condition:
if (name.HasValue)
query = query.Where(obj=>obj.Id == id && obj.Name == name);
else
query = query.Where(obj=>obj.Id == id);
I would use gdoron's solution, but if it seems unpractical for larger sets of queries, a slightly more complicated solution containing set operations might help you:
var queryById = query.Where(obj => obj.Id == id);
var queryByName = query.Where(obj => obj.Name == name);
query = queryById.Union(queryByName);
It gets much more difficult if your original query contains duplicate items.
Another way may be using Expression to formulate your queries. You can modify the expression tree before executing it, so you can add more conditions to the Where sub-tree. That is a whole lot of work and it's an overkill on 99.9% (rough estimate :) ) of cases.
Part of the problem is that you over write your original query. Your OR operation would be equivalent to:
subquery1 = query.Where(obj=>obj.Id == id);
subquery2 = query.Where(obj=>obj.Name == name);
query = subquery1.Concat(subquery2).Distinct();
As you can see, that becomes pretty unwieldy as well, however if You are going to do this form, then you must maintain the original sequence so that you can get both the right and left sides of the equation processed then you need to be sure duplicates get removed.
Instead of all that, I would try to figure a way to build up that conditional statement dynamically using lambdas e.g.
I haven't actually run this, but something like this should work.
var cond = obj=>obj.Id == id;
...
// need an or
cond = obj=>cond(obj) || obj.Name == name;
query = query.Where(obj=>cond(obj));
Hope this gives you an idea.

Best way to determined null or count 0

I have a iQueryable and I need to know if it's null or has no values.
IQueryable<people> L = (from p in people
where p.lastname.Contains("y")
select p);
if (L != null && L.Count() > 0) {
return "Something";
} else {
return "NOTHING";
}
Well if you use the L.Count() it will use more resources. Is there a better way? Something that does not use L.Count()
It's recommended that you use .Any().
IQueryable<people> L = (from p in people
where p.lastname.Contains("y")
select p);
if (L.Any()) {
return "Something";
} else {
return "NOTHING";
}
Does L need to be IQueryable<> ?
By using SingleOrDefault() it will be a single people (Person?) or null (presuming people is a class)
var result = (from p in people
where p.lastname.Contains("y")
select p).SingleOrDefault();
return result == null
? "NOTHING"
: "Something";
Other: Is SingleOrDefault() what you want to use or do you mean FirstOrDefault() or do you mean Any()?
Maybe LINQ: When to use SingleOrDefault vs. FirstOrDefault() with filtering criteria can help.
hth,
Alan.
An example of using the .Any method
return people.Any(p => p.lastname.Contains("y")) ? "something" : "nothing";
This is an example that would return an IQueryable if the .Any returns true, however it might be too ineffecient since it requires two round trips to the database. I'm sure a better method could be written, given enough time and thought.
return sis.Students.Any(p => p.LastName.Contains("y")) ?
people.Where(p => p.lastname.Contains("y")) : "nothing";
L.Any(), L.FirstOrDefault() will pretty much both have the same performance as they have almost identical implementation and are probably what you are looking for. Your SingleOrDefault is probably unintentional as it will throw an exception if there is more than one result.
Performance of LINQ Any vs FirstOrDefault != null
It's worth saying some of this depends on your provider. IQueryable just implies an intention. If It's Linq2Sql or something then yes L.Count() will request more resources - except that your also calling SingleOrDefault in the above line which means your null check is all you need, but your types don't match...
If I am running this statement against a Linq provider I write myself (or Amazons, or any other given LINQ provider) .Count() might be faster depending on what the provider is doing, but your assumptions hold if you're using the usual Microsoft Linq to SQL implementations.

get the names starts with numbers or special characters in linq to sql

I need to get the list of names that starts with special characters or numbers in the linq to sql query for my asp.net mvc(C#) application.
I have tried like this (Which may not be efficient):
public List<User> GetUsersStartingWithNonCharacter()
{
List<User> _dbUsers = this.GetAllUsers();
return _dbUsers.Where(p => ((p.FirstName != null && p.FirstName != string.Empty && !char.IsLetter(p.FirstName.ToLower()[0])) || (p.FirstName == null || p.FirstName == string.Empty))).ToList();
}
public List<Users> GetAllUsers()
{
return (from u in _context.pu_Users
where !u.Is_Deleted
select new User
{
UserId = u.User_Id,
Email = u.Email_Address,
FirstName = u.First_Name,
LastName = u.Last_Name
}).ToList();
}
Can anyone suggest the most efficient way to do this in linq to sql?
How do you know if it isn't already efficient? Use somekind of profiler tool, like SQL Server Profiler if you're using MSSQL, that way you can trace your call against the database and see the actual SQL. Of course you can only debug the code to see the generated SQL but it's easier with a profiler tool and you'll see how long time the query takes.
EDIT: I see one part in how you can make it more efficient:
public List<User> GetUsersStartingWithNonCharacter()
{
List<User> _dbUsers = this.GetAllUsers();
return _dbUsers.Where(p => ((p.FirstName != null && p.FirstName != string.Empty && !char.IsLetter(p.FirstName.ToLower()[0])) || (p.FirstName == null || p.FirstName == string.Empty))).ToList();
}
public IQueryable<Users> GetAllUsers()
{
return from u in _context.pu_Users
where !u.Is_Deleted
select new User
{
UserId = u.User_Id,
Email = u.Email_Address,
FirstName = u.First_Name,
LastName = u.Last_Name
};
}
Changing your GetAllUsersto return IQueryable will delay the query to execute until you've applied your filters. This might affect some other aspects of your design but you should consider it since that change might make your where clause run in the database instead of in the code which will result in less data traffic between your application and database. Again, use a profiler to see the difference :).
I'll use Regular Expression in this scenerio
Here is my sample code
return _dbUsers.Where(p=>p.FirstName!=String.Empty)
. Where(p => Regex.Match(p.Firstname[0].ToString(), "[a-zA-Z]").Success).ToList();
I suspect all rows will be retrieved and filted in your application due to the condition:
char.IsLetter(p.FirstName.ToLower()[0])
(Using a regular expression like suggested in another answer will also pull in all rows, and filter them on the client.)
It is possible to check characters in a string with the PATINDEX function, but it's seems only to be available for LINQ via the Entity framework.
You could write a stored procedure using PATINDEX directly to check for the first character to optimize your query. Sample queries can be found at http://www.databasejournal.com/features/mssql/article.php/3071531/Using-SQL-Servers-CHARINDEX-and-PATINDEX.htm.
Sometimes LINQ to whatever will not yield the most optimized solution, but that's just life. In most cases it will give clearer code, but special cases might require work arounds in order to use special operators of the underlying system.

Categories

Resources