linq: how to check if the value of one attribute exists - c#

if statement to check the value of an attribute doesn't work.
if (element.Elements(ns + "list").Where(x => x.Attribute("name").Value == "myProject") != null)
Is there other way to check if the value of an attribute exists?

you can use firstordefault
var element = element.Elements(ns + "list").Where(x => x.Attribute == "myProject");
// return if null
if(element == null) return;
// do your stuff
Sorry for messy indentation as I'm typing on mobile :)

Related

Shorten code that contains a sequence of 'null' tests

Can I somehow connect two assignments to temp into one condition (with &) in the if statement?
node temp = new node();
temp = queue.Find(match => match.Check_node_state(element.state));
if (temp == null)
temp = explored_nodes.Find(match => match.Check_node_state(element.state));
if (temp == null)
You can chain the null coalescing operator.
node temp = queue.Find(match => match.Check_node_state(element.state))
?? explored_nodes.Find(match => match.Check_node_state(element.state))
?? someOtherFind()
?? anotherFind();
if (temp == null)
throw new Exception("This thing really does not exist!");
In C#, the operator you want is ?? which allows you to provide an alternate value in case the first is null. The statement would look something like this:
node temp = queue.Find(match => match.Check_node_state(element.state))
?? explored_nodes.Find(match => match.Check_node_state(element.state));
Well, you certainly can do:
if (queue.Find(match => match.Check_node_state(element.state)) == null &&
explored_nodes.Find(match => match.Check_node_state(element.state)) == null)
But I don't see it as a huge improvement...
Note that you need to use && instead of & to make the code equivalent because && short-circuits, while & will evaluate both conditions even if the first is true.
You can use Any to make code even more readable:
if (!queue.Any(match => match.Check_node_state(element.state)) &&
!explored_nodes.Any(match => match.Check_node_state(element.state)))

Linq Query Crash if Return Null

I run this query And if The Query is return with empty values the programme is crashed.
var cust = db.Customers.FirstOrDefault(x => x.telephone == txtTel.Text);
if (cust.BlackList == 1)
{
MessageBox.Show("This customer is blacklisted, Do you wish to continue with this job?");
}
Please Suggest me Some Efficient solution
Thanks.
You are getting a null pointer because FirstOrDefault returns the default value of the object if the result is not found (in this case it is null):
var cust = db.Customers.FirstOrDefault(x => x.telephone == txtTel.Text);
if (cust != null && cust.BlackList == 1)
{
MessageBox.Show("This customer is blacklisted, Do you wish to continue with this job?");
}
You need to check for null because that's what FirstOrDefault returns if there is no record that satisfies your condition:
if(cust != null && cust.BlackList == 1)
FirstOrDefault will return a default value if there is no element in the list which satisfy the condition, in this case it will be null. As you call a property on the null value it will naturally cause an exception.
You should check if cust is null, like:
if(cust != null && cust.BlackList == 1)
Of course you can display another message if the user doesn't exist based on the logic of your application.

FirstOrDefault returns NullReferenceException if no match is found

Here is my code:
string displayName = Dictionary.FirstOrDefault(x => x.Value.ID == long.Parse(options.ID)).Value.DisplayName;
The code works fine if x.Value.ID matches options.ID. However, I get a NullReferenceException if it doesn't.
FirstOrDefault returns the default value of a type if no item matches the predicate. For reference types that is null. Thats the reason for the exception.
So you just have to check for null first:
string displayName = null;
var keyValue = Dictionary
.FirstOrDefault(x => x.Value.ID == long.Parse(options.ID));
if(keyValue != null)
{
displayName = keyValue.Value.DisplayName;
}
But what is the key of the dictionary if you are searching in the values? A Dictionary<tKey,TValue> is used to find a value by the key. Maybe you should refactor it.
Another option is to provide a default value with DefaultIfEmpty:
string displayName = Dictionary
.Where(kv => kv.Value.ID == long.Parse(options.ID))
.Select(kv => kv.Value.DisplayName) // not a problem even if no item matches
.DefaultIfEmpty("--Option unknown--") // or no argument -> null
.First(); // cannot cause an exception
You can use a combination of other LINQ methods to handle not matching condition:
var res = dictionary.Where(x => x.Value.ID == someID)
.Select(x => x.Value.DisplayName)
.DefaultIfEmpty("Unknown")
.First();
Simply use the question mark trick for null checks:
string displayName = Dictionary.FirstOrDefault(x => x.Value.ID == long.Parse(options.ID))?.Value.DisplayName ?? "DEFINE A DEFAULT DISPLAY NAME HERE";
That is because FirstOrDefaultcan return null causing your following .Value to cause the exception. You need to change it to something like:
var myThing = things.FirstOrDefault(t => t.Id == idToFind);
if(myThing == null)
return; // we failed to find what we wanted
var displayName = myThing.DisplayName;
To add to the solutions, here is a LINQ statement that might help
Utilities.DIMENSION_MemTbl.Where(a => a.DIMENSION_ID == format.ContentBrief.DimensionID).Select(a=>a.DIMENSION1).DefaultIfEmpty("").FirstOrDefault();
The result will be an empty string if the result of the query is a null..
This answer is for those of us who need a visual write up (like me :)
In the code screenshot below, a NullReferenceException will be thrown, the root cause is the ReferenceIdentification_02 property.
When debugging, we see that the orderLine.REF array, I am querying does not include a matching object whose ReferenceIdentificationQualifier_01 value == "RU", so at that point FirstOrDefault() return value is NULL
to prevent the NullReferenceException, I do a FirstOrDefault() on the orderLine.REF array first. If the returned value is not null then I retrieve the value.
i assume you are working with nullable datatypes, you can do something like this:
var t = things.Where(x => x!=null && x.Value.ID == long.Parse(options.ID)).FirstOrDefault();
var res = t == null ? "" : t.Value;
you can use with 'Where' statement with FirstOrDefault().
like this.
var modelItem = _dbcontext.ModelName.Where(n => n.NewsTagId == newsTag.Id).FirstOrDefault();
It returns first item if does not match query.
It is better practice to check the NULL after query.
if(modelItem == null)
{
return "Not Found."
}
else
{
// continue process
}

XDocument Querying using Lambda

I have XML as shown below
<NodeName Foo="True" Foobar="False" />
<NodeName Foo="False" Foobar="False" />
<NodeName Foo="True" Foobar="False" />
I am querying this to find NodeName's with a Foo value of 'True' using:
.Where(node => node.Attribute("Foo").Value = "True");
However there is the possibility that the attribute Foo may not exist and this causes an exception.
The question is how do you implement logic to check if the attribute exists and then check for the value if it does exist?
I have tried the following however not sure what goes in the else bracket to return nothing as currently it wont compile with an error of not returning a value on all paths.
.Where(node =>
{
if (node.Attribute("Foo") != null)
{
node.Attribute("Foo").Value == "True";
}
else { }
});
However there is the possibility that the attribute Foo may not exist and this causes an exception.
This is where the explicit conversion from XAttribute (and indeed XElement) to string and a number of other types comes in handy:
.Where(node => (string) node.Attribute("Foo") == "True");
The conversion will return null when there's no such attribute. This is much more convenient than finding the attribute twice - once for presence and once for the value.
Alternatively, you could use the conversion to bool? which will also return null if the attribute is missing, so you need to use the null-coalescing operator to effectively provide a default:
.Where(node => (bool?) node.Attribute("Foo") ?? false);
EDIT: In terms of why your statement-lambda approach doesn't work, you don't have any return statements. This would work, although obviously it's not what I'd recommend:
.Where(node =>
{
if (node.Attribute("Foo") != null)
{
return node.Attribute("Foo").Value == "True";
}
else
{
return false;
}
});
The lambda must return a boolean value to determine whether the node will be in the result set.
Try this:
xml.Where(node => node.Attribute("Foo") != null && node.Attribute("Foo").Value == "True");
just do this
.Where(node => node.Attribute("Foo") == null ? false : node.Attribute("Foo").Value == "True");

c# dealing with all possible null and non null values

I have the following method:
public IQueryable<Profile> FindAllProfiles(string CountryFrom, string CountryLoc)
{
return db.Profiles.Where(p => p.CountryFrom.CountryName.Equals(CountryFrom,
StringComparison.OrdinalIgnoreCase));
}
What is the best way to write the where clause that would filter all the possible combinations of input parameters in one statement:
BOTH CountryFrom and CountryLoc = null
Only CountryFrom null
Only CountryLoc null
BOTH CountryFrom and CountryLoc are not null.
Soon .. I would need to filter out profiles by Age, Gender, Profession .. you name it.
I am trying to find a way to write it efficiently in C#. I know how to do it in a clean manner in TSQL. I wish I knew the way. Thanks for all the responses so far.
A good old binary XNOR operation will do the trick here:
db.Profiles.Where(p => !(p.CountryFrom == null ^ p.CountryTo == null))
It's effectively equating two booleans, though to me it's more direct, less convoluted even, than writing ((p.CountryFrom == null) == (p.CountryTo == null))!
I would use this simple LINQ syntax...
BOTH CountryFrom and CountryLoc = null
var result = from db.Profiles select p
where (p.CountryFrom == null) && (p.CountryLoc == null)
select p
Only CountryFrom null
var result = from db.Profiles select p
where (p.CountryFrom == null) && (p.CountryLoc != null)
select p
Only CountryLoc null
var result = from db.Profiles select p
where (p.CountryFrom != null) && (p.CountryLoc == null)
select p
BOTH CountryFrom and CountryLoc are not null.
var result = from db.Profiles select p
where (p.CountryFrom != null) && (p.CountryLoc != null)
select p
Hope it helps ;-)
I wouldn't call this elegant:
public IQueryable<Profile> FindAllProfiles(string CountryFrom, string CountryLoc)
{
return db.Profiles.Where(p =>
{
p.ContryFrom != null &&
p.CountryFrom.CountryName != null &&
p.CountryFrom.CountryName.Equals(CountryFrom, StringComparison.OrdinalIgnoreCase)
});
}
I may be missing something, but as written, your combination of operators will either let all values through or no values through depending on whether you use || or && to combine them together.
I'm in favor of not trying to cram too much logic into a linq expression. Why not contain your comparison logic in a separate function like this?
EDIT: I provided an example implementation of the MatchesCountry function.
class Example
{
public IQueryable<Profile> FindAllProfiles(string CountryFrom, string CountryLoc)
{
return db.Profiles.Where(p => p.MatchesCountry(CountryFrom, CountryLoc));
}
}
public static class ProfileExtensions
{
public static bool MatchesCountry(this Profile profile, string CountryFrom, string CountryLoc)
{
// NOTE: Your comparison logic goes here. Below is an example implementation
// if the CountryFrom parameter was specified and matches the profile's CountryName property
if(!string.IsNullOrEmpty(CountryFrom) && string.Equals(profile.CountryName, CountryFrom, StringComparison.OrdinalIgnoreCase))
return true; // then a match is found
// if the CountryLoc parameter was specified and matches the profile's CountryCode property
if (!string.IsNullOrEmpty(CountryLoc) && string.Equals(profile.CountryCode, CountryLoc, StringComparison.OrdinalIgnoreCase))
return true; // then a match is found
// otherwise, no match was found
return false;
}
}

Categories