XDocument Traversal - c#

I'm new the the LINQ to XML world. I'm attempting to retrieve the value of Identity but only when the domain attribute of Credential is "NetworkID". Here's the code I'm testing with:
XML Snippet:
<Sender>
<Credential domain="NetworkID">
<Identity>MyIdentity</Identity>
<SharedSecret>MySharedSecret</SharedSecret>
</Credential>
<UserAgent>MyUserAgent</UserAgent>
</Sender>
C#:
var credential = xdoc.Descendants("Sender")
.Elements("Credential")
.Where(x => x.Attribute("domain").Value == "NetworkID").FirstOrDefault()
.Descendants("Identity").FirstOrDefault();
Question:
Obviously, if the Credential node is not found, the LINQ query will generate an error because I'm calling .Descendants() on null.
Is it possible to write the query so that it return Identity or null if either element is not found?

Just remove FirstOrDefault() after the Where():
var credential = xdoc.Descendants("Sender")
.Elements("Credential")
.Where(x => x.Attribute("domain").Value == "NetworkID")
.Descendants("Identity")
.FirstOrDefault();
Where() returns empty result set and FirstOrDefault() on empty result set returns null this is why .Where().FirstOrDefault().Descendants() caused null reference exception.

If you use
var identity =
xdoc.Descendants("Sender")
.Elements("Credential")
.Where(x => (string)x.Attribute("domain") == "NetworkID")
.Descendants("Identity")
.FirstOrDefault();
you should get what you want. Or you need to break the code up, doing one FirstOrDefault() in the first part e.g.
var credential = xdoc.Descendants("Sender").Elements("Credential").FirstOrDefault(c => (string)c.Attribute("domain") == "NetworkID");
var identity = credential != null ? credential.Element("Identity") : null;

Related

System.Linq.Queryable.FirstOrDefault<TSource>(...) returns null

When the DB Table is empty my request to access the result throws an error.
var resultEthnie = (from k in db.N_QONV
where k.qonv_fk_numvol == clientId &&
k.qonv_fk_eon_id == 64
select new { k.qonv_fk_num_question }
).Take(1);
return Convert.ToInt32(resultEthnie.FirstOrDefault().qonv_fk_num_question);
Is there a way to have a default return result value when the query result is empty?
Is there a way to have a default return result value when the query result is empty?
You are getting the error because you try to access the first element of the query result without check if it is empty or not.
To fix the issue use ? operator after the FirstOrDefault() method:
resultEthnie.FirstOrDefault()?.qonv_fk_num_question; // ? will escape accessing to
// qonv_fk_num_question if the result is null
However here I see a bit more elegant solution. Instead of using filtering, select and later trying to access the first element of the result, simple use FirstOrDefault() method lambda version:
var result = db.N_QONV.FirstOrDefault(k => (k.qonv_fk_numvol == clientId) &&
(k.qonv_fk_eon_id == 64));
return Convert.ToInt32(result?.qonv_fk_num_question);

MySQL Entity Framework With LinQ Correlated Query Not Executing

I am using Visual Studio 2012 with MySQL 5.7 Community Edition. I am getting object reference not set to an instance of object on the below query.
var oList = (
from dm in dbContext.document_master
join um in dbContext.user_master on dm.Alocated_CAA equals um.UserId
where (dm.DocumentHandle != null)
select new TaskLogReport
{
documentDate = dm.Document_Date,
documentHandle = dm.DocumentHandle,
fileNumber = dm.FileNumber,
statusRemarks = dbContext.statushistories
.Where(x => x.DocumentHandle == 12345678).FirstOrDefault().Remarks
}).ToList();
In the above query If I get change 12345678 to dm.DocumentHandle, then getting object reference not set to an instance object.
Try with MS-SQL server , working fine.
You get the error because FirstOrDefault() returns null, because there are no objects who's DocumentHandle equals dm.DocumentHandle. Changing dm.DocumentHandle to 12345678 works because there is one matching element.
This line is the problem:
.Where(x => x.DocumentHandle == 12345678).FirstOrDefault().Remarks
C#'s Enumerable.FirstOrDefault() method returns either the first matching element of an enumerable, or, if there aren't any, the default value of the type. In the case of nullable types, FirstOrDefault() returns null if no elements are found.
The reason you get no error when you use 12345678 is because there is at least one matching value with that DocumentHandle. However, when you change that to dm.DocumentHandle, no matching elements are found, causing FirstOrDefault to return null. Then you essentially do null.Remarks, which causes the error.
You should change your code to this:
.FirstOrDefault(x => x.DocumentHandle == dm.DocumentHandle)?.Remarks
There are two differences here:
Got rid of the where and moved the predicate to the FirstOrDefault call. This is just a cleaner way of doing what you were doing before.
Added the ? at the end of the FirstOrDefault call. That is the null propagation operator.
What it does is it turns this:
int foo;
if (bar != null)
{
foo = bar.foo;
}
Into this:
int foo = bar?.foo;
Now, if there are matching elements, statusRemarks will be equal to the first one's Remarks. Otherwise, statusRemarks will be null.
EDIT: The null propagation operator was implemented in C# 6.0, which is .Net 4.6 onwards, so it won't work in .Net 4.0.
You'll have to modify your query and implement a check, like so:
var oList = (
from dm in dbContext.document_master
join um in dbContext.user_master on dm.Alocated_CAA equals um.UserId
where (dm.DocumentHandle != null && dbContext.statushistories.Count(x => x.DocumentHandle == dm.DocumentHandle) > 0)
select new TaskLogReport
{
documentDate = dm.Document_Date,
documentHandle = dm.DocumentHandle,
fileNumber = dm.FileNumber,
statusRemarks = dbContext.statushistories.First(x.DocumentHandle == dm.DocumentHandle).Remarks
}).ToList();

Get ICollection property of generic type

I'm new in ASP.NET MVC 5, I need get the Icollection property and search into other property, if printed the result of the first search is fine, but when i go to search in the result is null.
what is the problem?
var userId = User.Identity.GetUserId();
var user = db.Users.Include( u=> u.Sucursales)
.Where(u => u.Id == userId)
.SingleOrDefault();
if( user != null )
{
var sucursal = user.Sucursales.Include(s => s.Emisor)
.Where(s => s.ID == suc)
.SingleOrDefault();
if (sucursal != null)
{
var tipoCfe = sucursal.Emisor.TiposCfe
.Where(t => t.ID == factura)
.SingleOrDefault();
Your query will take place right away since you are using SingleOrDefault(), see this StackOverflow question pertaining to SingleOrDefault() Your Include(s => s.Emisor) sticks out to me though. Since Emisor wasn't included when fetching the user, you will not be able to request that since your query is no longer of type IQueryable. Your query has already been executed.
In order to retrieve the data you require, you will have to obtain the data during your first query. I would do something similar to: db.Users.Include("Sucursales.Emisor") when you retrieve the user.
More on include method... MSDN Explanation of Include Method
I changed
var user = db.Users.Include( u=> u.Sucursales)
for
var user = db.Users.Include("Sucursales.Emisor")

How to check if array is not null in LINQ?

I Have this where statement in LINQ:
(users != null && users.Contains(x.Appointment.UserId))
users is an int[]. When i run this code i have an exception:
Unable to create a null constant value of type 'System.Int32[]'. Only
entity types, enumeration types or primitive types are supported in
this context.
What should i do?
I had a similar problem. Assuming you are starting with something like this:
var filtered = appointments
.Where(x => users != null && users.Contains(x.Appointment.UserId));
As #CarstenKönig suggests, try moving the null check outside of the Where clause:
var filtered = users != null ?
appointments.Where(x => users.Contains(x.Appointment.UserId)) :
appointments;
That means the null check is handled by C#, and LINQ to Entities doesn't attempt to convert it to SQL.
As others suggested you could move bool check outside the closure and use resulting bool in your Where statement:
var usersNotNull = users != null;
var users = users == null ? new string[0] : users;
query.Where(x => usersNotNull && users.Contains(x.Appointment.UserId));

Checking For null in Lambda Expression

In the code below I am trying to get the null, empty string, and source components out of a List. I have not tested this code yet but my intuition tells me it will break when filtering the List for source and empty string if it comes by a null value.
I tried to extract the null values first, but I am still filtering the base List. How can I re-write this code to accomplish what I am trying to do in the best way?
List<LineItem> nullList=itemsList.Where(s => s[Constants.ProductSource] == null)
.ToList();
NALineItems = itemsList.Where(s => s[Constants.ProductSource] == source
|| s[Constants.ProductSource] == String.Empty)
.ToList();
NALineItems = nullList.Union(NALineItems).ToList();
s[Constants.ProductSource] is an attachment property to Microsoft ECommerce PurchaseOrder object. Its basically another property of an object.
Based on "I am trying to get the null, empty string, and source components out of a List" I assume you mean you want a list with these 3 specific values.
var allItems = itemsList
.Where(s => string.IsNullOrEmpty(s[Constants.ProductSource])
|| s[Constants.ProductSource] == source)
.ToList()
Is there a reason you cannot combine the expression into one? I would also add a check that the key exists in the dictionary:
List<LineItem> NALineItems = itemsList.Where(s =>
s.ContainsKey(Constants.ProductSource) && (
String.IsNullOrEmpty(s[Constants.ProductSource]) ||
s[Constants.ProductSource] == source))
.ToList();

Categories