How to check if IQueryable element/ item contains a property in C#? - c#

I have an IQueryable as follows
var issues = from i in jira.Issues.Queryable
where i.Project == project.Key
orderby i.Created
select i;
I am trying to get the count where issue type is Bug like this:
TotalIssues = issues.ToList().Where(i => i.Type.Name == "Bug").Count();
The problem here is there are some issues without a type. How can I check if the issue type exists?

You can try null propagation ?. in order to have null for Name if any item or item.Type are null:
TotalIssues = issues
.AsEnumerable() // Linq to objects from now on; no need in materialization
.Count(item => "Bug".Equals(item?.Type?.Name)); // just count

You don't want issues without type. You can keep code simple by not taking issues without type into account.
var bugsCount = issues.AsEnumerable()
.Where(issue => issue.Type != null)
.Count(issue => issue.Type.Name == "Bug");
You can chain as much .Where clauses as you wish, items will be still enumerated only once.

What do you mean? Some issues don't have Type Property? Or Some issues's property Type is null?
If it is some issues don't have Type Property, I think you can specify issues's class or interface. Or you can use reflection.
If it is some issues's property Type is null, you can check Type is not null first.
From your comment, I think i may be null too.
i!=null && i.Type!=null && i.Type.Name=="Bug"

Related

Determine if record exists where two fields must match in MVC

I have a table (and a corresponding class) for this solution that has only two fields a UserId and a TicketId. Now I need to test if a record exists in this table where the UserId matches the logged in individual and TicketId matches the passed value. This is the code I tried:
bool subscriptionExists = db.TicketSubscriptions.Any(ts => ts.TicketId.Equals(db.Tickets.FirstOrDefault(t => t.TicketNumber == ticketNumber).TicketId))
.Where(ts => ts.UserId == db.Users.FirstOrDefault(u => u.NTUserName.Equals(User.Identity.Name)).UserId);
However, I am getting the following error:
'bool' does not contain an extension method for 'where' and no
extension method 'where' accepting a first argument of type 'bool'
could be found (are you missing a using directive or an assembly
reference?
Am I on the right track? or is there a much better way to test this?
You are using Where on a bool value instead of a List. Any() returns bool. You can try like following. Hope this will help you.
var ticketId=db.Tickets.FirstOrDefault(t =>t.TicketNumber==ticketNumber).TicketId;
var userId=db.Users.FirstOrDefault(u=>u.NTUserName.Equals(User.Identity.Name)).UserId;
bool subscriptionExists = db.TicketSubscriptions.
Any(ts => ts.TicketId.Equals(ticketId) && ts.UserId == userId);
You're calling the .Where on the result of the .Any, which is a boolean value. Try combining your clauses and then calling .Any on the whole thing:
bool subscriptionExists = db.TicketSubscriptions.Any(
ts => ts.TicketId.Equals(db.Tickets.FirstOrDefault(t => t.TicketNumber == ticketNumber).TicketId) &&
ts.UserId == db.Users.FirstOrDefault(u => u.NTUserName.Equals(User.Identity.Name)).UserId);
TicketSubscriptions.Any() returns a Bool.
It is result is a True or False. So you cannot continue to query with a where. Write the code more readable. You can see mistakes easier. In any() function you need a boolean statement like if statements. You can use || or && signs simply.
var userId = User.Identity.Name;
var passedValue = ... // I dont know if it is from a parameter.
bool subscriptionExists = TicketSubscriptions.Any(ts => ts.NTUserName == userId && ts.TicketId == passedValue );
your problem is that Any() returns a bool, so you can't call Where() on it.
Where, returns another IEnumerable, so if you put Where before Any(), you won't have that problem.
You can also put both conditions inside the Any() I.E. someEnumerable.Any(/*condition1*/ && /*condition1*/);
on another note, I'd make use of Navigation Properties if I were you. You can google search for "navigation properties" and the name of whatever database framework you're using(like entity framework or linq to sql) to find more information.
That will let you do things like
subscriptionExists = db.TicketSubscriptions
.Any(ts => ts.Ticket.TicketNumber == ticketNumber
&& ts.User.NTUserName == User.Identity.Name);
on yet another note, I believe that User.Identity is going to have the user id, so you don't even have to bother accessing the users table like that. Intellisence can help you find out how to access that.
Complementing the #Azim answer
When you use .FirstOrDefault must verify returned values. Otherwise if you have sure that the return value never is null must use .First
var ticketId=db.Tickets.FirstOrDefault(t =>t.TicketNumber==ticketNumber).TicketId;
varuserId=db.Users.FirstOrDefault(u=>u.NTUserName.Equals(User.Identity.Name)).UserId;
if(ticketId != null && userId != null)
{
bool subscriptionExists = db.TicketSubscriptions.
Any(ts => ts.TicketId.Equals(ticketId) && ts.UserId == userId)
}

LINQ to Entities does not recognize the method IsNullOrWhiteSpace

I have the below code:
var countries = from c in db.Countries
where (string.IsNullOrWhiteSpace(searchAlpha2) || (c.Alpha2 ?? string.Empty).ToUpper().Contains(searchAlpha2.ToUpper()))
&& (string.IsNullOrWhiteSpace(searchAlpha2) || (c.Alpha3 ?? string.Empty).ToUpper().Contains(searchAlpha3.ToUpper()))
&& (string.IsNullOrWhiteSpace(searchName) || (c.Name ?? string.Empty).ToUpper().Contains(searchName.ToUpper()))
select c;
This code uses Entity Framework v6 Code First over a SQL database.
Aside from performance, if I don't include the IsNullOrWhitespace I get no results when the filter criteria are blank (I've tested both null and blank values); however when a value is present this works as expected.
I'm getting the error:
LINQ to Entities does not recognize the method 'Boolean IsNullOrWhiteSpace(System.String)' method, and this method cannot be translated into a store expression.
I'm trying to use the searchXXX strings to filter on columns. I've tried using RegEx.IsMatch, SqlMethods.Like, and the code below, but all give me errors saying those functions are not allowed (errors come from either EntityFramework.SqlServer or from Linq to Entities). I've seen numerous posts on here where this has been done successfully though - so wonder if I'm missing something fundamental?
If you want to use your statement in current form you might want to replace
string.IsNullOrWhiteSpace(searchAlpha2)
to
!(searchAlpha2 == null || searchAlpha2.Trim() == string.Empty)
and all the other values too, for it to get translated to working SQL.
Update: Copied from comment by #DavidKempfner
As of EntityFramework.6.2.0 it generated SQL that checked for
!(searchAlpha2.Trim() == string.Empty),
I.E. It ignored the searchAlpha2 == null || part.
Use this instead:
!string.IsNullOrEmpty(entity.searchAlpha2.Trim())
I would suggest a different approach - use the ability to build queries up on the fly, and thus avoid passing optional query parameters to the expressions altogether - this will result in improved query plans when parsed to sql and executed on the database.
Also, if your database (?SqlServer) is not set to case sensitive collation (i.e. xx_CI_xx), you can avoid the casing conversion as well, as it is redundant:
var myQueryable = db.Countries.AsQueryable();
if (!string.IsNullOrWhiteSpace(searchAlpha2))
{
myQueryable = myQueryable.Where(c => c.Alpha2.Contains(searchAlpha2));
}
...
var countries = myQueryable.ToList();
You can get this and a bunch more functionality using PredicateBuilder
Update
JB: based on StuartLC's answer, here's the code amended to use PredicateBuilder:
var predicate = PredicateBuilder.True<Country>();
if (!string.IsNullOrWhiteSpace(searchAlpha2))
predicate = predicate.And(c => c.Alpha2 != null ? c.Alpha2.Contains(searchAlpha2) : false);
if (!string.IsNullOrWhiteSpace(searchAlpha3))
predicate = predicate.And(c => c.Alpha3 != null ? c.Alpha3.Contains(searchAlpha3) : false);
if (!string.IsNullOrWhiteSpace(searchName))
predicate = predicate.And(c => c.Name != null ? c.Name.Contains(searchName) : false);
IQueryable<Country> countries = db.Countries.AsExpandable().Where(predicate);
when you use linq in Entity Framework to get data from DataBase you need to use only with functions that the Entity Framework can convert to sql query.
I know that there an already accepted answer for this question but I got an idea to share.
Instead of putting multiple checks in the LINQ or using if statement to apply where clause on list result, you can use a simple trick. Just declare a bool variable and assign IsNullOrWhitespace of add to linq like:
bool isNull = string.IsNullOrWhiteSpace(searchAlpha2);
var countries = db.Countries.Where(c => isNull || c.Alpha2.Contains(searchAlpha2)).ToList();

Issue with checking nullable xml values when converting to linq

I'm trying to convert an xml feed to linq, but I'm having trouble checking if an element is null or not before retrieving that element's data. I was convinced my following code is correct, but one of the xml's rows is missing the element "ElementOne" and it's child "Element", so it's throwing the whole script when executed.
This snippet is incomplete but this is the part that's causing the whole script to error, can anyone spot why this would error?
from c in s.Element("ElementOne").Elements("ElementTwo")
where s.Element("ElementOne") != null &&
s.Element("ElementOne").Elements("ElementTwo") != null
select new{
Id = (c.Attribute("Id") == null) ? 0 : (int)c.Attribute("Id")
}
I would just change it to:
var query = s.Elements("ElementOne").Elements("ElementTwo")
.Select(c => (int?) c.Attribute("Id") ?? 0);
(Unless you really need the anonymous type, why bother with it?)
If there are no ElementOne elements, this will just give you an empty result.
If you want to only use the first ElementOne element even if there are multiple ones, you can use:
var query = s.Elements("ElementOne").Take(1).Elements("ElementTwo")
.Select(c => (int?) c.Attribute("Id") ?? 0);

String.IsNullOrEmpty in LINQ To SQL query?

My DBML exposes a record set that has a nullable nvarchar field. This nullable nvarchar field is represented as a string in my C# code.
Sometimes this field is null, sometimes it is an empty string, and sometimes it actually has a value.
Does String.IsNullOrEmpty() work in LINQ To SQL? For instance, would the following work:
var results = from result in context.Records
where String.IsNullOrEmpty(result.Info) == false
select result;
Curiously, per MSDN String.IsNullOrEmpty is supported (by virtue of it not being unsupported), yet I can only find complaints about it not being supported.
However, if it does work you should not explicitly compare it to a boolean value, instead:
var results = from result in context.Records
/*XXX broke :( where !String.IsNullOrEmpty(result.Info) */
where !(result.Info == null || result.Info.Equals(""))
select result;
I don't know if that works, but I'm sure this does:
where (result.Info ?? "") != ""
(strongly recommend the parens, query generator can get confused without them)
It is not supported since attempting to use it results in a NotSupportedException being thrown with this message:
Method 'Boolean IsNullOrEmpty(System.String)' has no supported
translation to SQL.
Instead, you can use this approach to do the same thing:
var results = from result in context.Records
where result.Info != null && result.Info.Length > 0
select result;
You may also use result.Info != String.Empty instead of checking the length. Both approaches will work.
I had problems with all answers except for #ahmad-mageed's answer.
Ended up using a more concise syntax of:
where (result.Info ?? "").Length > 0
Or
result => (result.Info ?? "").Length > 0
You can use a function as argument to the Where method if you use a Linq query, e.g.
var results = context.Records.Where(string.IsNullOrEmpty);
But in this case that would give you all null or empty elements, instead of the opposite. Then create an extension method to the string class (e.g. string.IsNotNullOrEmpty) or do something like this:
var results = context.Records.Except(context.Records.Where(string.IsNullOrEmpty));

Linq returns list or single object

I have a Linq to Entities query like this one:
var results = from r in entities.MachineRevision
where r.Machine.IdMachine == pIdMachine
&& r.Category == (int)pCategory
select r;
Usually, I use the code below to check if some results are returned:
if (results.Count() > 0)
{
return new oMachineRevision(results.First().IdMachineRevision);
}
However, I'm getting NotSupportedException in the if condition.
The error message is: Unable to create a constant value of type 'Closure type'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
Note that pCategory is an Enum type.
EDIT: Based on your update, the error may be related to an enum in your entity class. See this blog entry for more information and a work-around. I'm leaving my original answer as an improvement on your query syntax.
Try doing the selection of the first entity in the query itself using FirstOrDefault and then check if the result is null.
int compareCategory = (int)pCategory; // just a guess
var result = (from r in entities.MachineRevision
where r.Machine.IdMachine == pIdMachine
&& r.Category == compareCategory
select r).FirstOrDefault();
if (result != null)
{
return new oMachineRevision(result.IdMachineRevision);
}
Why not just use FirstOrDefault() instead, and check for null? I can't see the benefit in querying for the count and then taking the first element.
In the standard implementation of linq, the operators "select" and "where" map to methods that return an IEnumerable or IQueryable. So standard linq methods when used should always return an IEnumerable from your query not a single object.
But linq methods that are candidates for the linq operators are not restricted to methods returning IEnumerables, any method returning anything can be chosen.
In case you have instance methods named "Select" and "Where" that return a single object or extensions methods that are specific to your class and return a single object those will be used instead of the standard linq ones.
My guess is that either a "Select" or "Where" method defined in your class is making linq return a single value instead of a IEnumerable<T>.
I didn't know different anonymous objects would be created depending on the query result. I guess they just wanted results to be of type IEnumerable
How about using a foreach?
var results = from r in entities.MachineRevision
where r.Machine.IdMachine == pIdMachine
&& r.Category == pCategory
select r;
foreach( var r in results )
{
yield return new oMachineRevision( r.IdMachineRevision );
}
This goes for all implicit types too. I must admit I keep forgetting this and that's how I came across this post.
if you have
class ClassA {
...
private string value;
...
public static implicit operator string(ClassA value)
{
return value.ToString();
}
...
}
you need to explictly cast the class to astring for comparison.
so I usually do this
var myClassAStr = myClassA.ToString();
var x = (from a in entites where a.ValToCompare == myClassAStr select a).first();
// do stuff with x
...
try using
IENumerable<MachineRevision> results = from r in entities.MachineRevision
...
instead.
I think its the var that's causing your issue.
Edit:
Read the error message. "Unable to create a constant value of type 'Closure type'. Only primitive types ('such as Int32, String, and Guid') are supported in this context."
One of these comparisions is with a type that is not int, string or guid. I'm guessing the Category.
r.Machine.IdMachine == pIdMachine && r.Category == pCategory
Interestingly, LinqToSql will allow this construction. Don't know why LinqToEntities does not support this.
I think you could also select the item you want another, simpler way by using lambda expressions.
var result = entities.MachineRevision
.Where(x => x.Machine.IdMachine == pIdMachine)
.Where(y => y.Category == (int)pCategory)
.FirstOrDefault();
if (result != null)
{
return new oMachineRevision(result.IdMachineRevision);
}
and then proceeding as you would normally

Categories