linq query and nulls - c#

I would like to query with linq some xml file. There are some required and some optional elements. Only required is name - everything else is optional.
If there is some NULL for example cageCode = NULL - it doesnt select anything - I need to add to List of strings - "" - I tried it like below, but it doesnt work. When I have everything filled it works fine, when there is something NULL it doesnt save to list anything.
Could you help me how to set "" to list where is null element?
Thanks!
var queryManufacturer = from dataManufaturer in input.Identification.Manufacturers.Manufacturer
select
new
{
dataManufaturer.name,
dataManufaturer.cageCode,
dataManufaturer.FaxNumber,
dataManufaturer.URL.OriginalString
};
foreach (var a in queryManufacturer)
{
data.Add(a.name);
if (a.cageCode == null) data.Add("");
else data.Add(a.cageCode);
if (a.FaxNumber == null) data.Add("");
else data.Add(a.FaxNumber);
if (a.OriginalString == null) data.Add("");
else data.Add(a.OriginalString);
}
It throws me a null exception if is some of elements in xml file missing - I dont wanna get this exception - I would like just add empty string beside missing element

try this in your Linq to XML query:
select new
{
name = dataManufaturer.name ?? "",
cageCode = dataManufaturer.cageCode ?? "",
FaxNumber = dataManufaturer.FaxNumber ?? "",
OriginalString = dataManufaturer.URL!=null ? dataManufaturer.URL.OriginalString : ""
};

Related

Do not return error since i expect null

Here i have example of getting inventory from json string.
inventory = JsonUtility.FromJson<InventoryModel>GFile.GetPlayer(FileComponent.PlayerInventory));
Since i am loading that string from file it is possible it is just blank and i want to first check if it is blank and i would do it like this:
if(GFile.GetPlayer(FileComponent.PlayerInventory) != " ")
{
inventory = JsonUtility.FromJson<InventoryModel>(GFile.GetPlayer(FileComponent.PlayerInventory));
}
So my question is if there is any more elegant way of doing this instead of typing if statement like this?
Why not like this? :
var player = GFile.GetPlayer(FileComponent.PlayerInventory);
if(!string.IsNullOrWhiteSpace(player)) {
inventory = JsonUtility.FromJson<InventoryModel>(player);
}
I'd suggest
string data = GFile.GetPlayer(FileComponent.PlayerInventory);
if(!string.IsNullOrWhiteSpace(data))
{
inventory = JsonUtility.FromJson<InventoryModel>(data);
}
This way you only call GetPlayer once, and it doesn't matter if the resulting data is an empty string or is full of whitespace - it still won't enter that block and set inventory.
Edit
For older versions of .Net, this will also work
string data = GFile.GetPlayer(FileComponent.PlayerInventory);
if(data != null && data.Trim().Length == 0)
{
inventory = JsonUtility.FromJson<InventoryModel>(data);
}

How can I check for a NullReferenceException in this C# LINQ to XML statement?

How can I check for a NullReferenceException in this C# LINQ to XML statement without wrapping the whole thing in a try/catch? If any of the properties are null, I would like it to still attempt to get the remaining data.
Thanks.
XElement doc = XElement.Load("test.xml");
var nodes =
from node in doc.Elements("Customer")
select new
{
Name = node.Element("FullName").Value,
Zip = node.Element("ZipCode").Value,
Active = node.Element("ActiveCustomer").Value,
};
Just use explicit cast. It will return null if the element wasn't found, won't cause an exception.
var nodes =
from node in doc.Elements("Customer")
select new
{
Name = (string)node.Element("FullName"),
Zip = (string)node.Element("ZipCode"),
Active = (string)node.Element("ActiveCustomer"),
};
Use the ternary operator.
Ternary Operator
XElement doc = XElement.Load("test.xml");
var nodes =
from node in doc.Elements("Customer")
select new
{
Name = node.Element("FullName") !=null ? node.Element("FullName").Value : null,
Zip = node.Element("ZipCode") !=null ? node.Element("ZipCode").Value : null,
Active = node.Element("ActiveCustomer") !=null ? node.Element("ActiveCustomer").Value : null
};
You could try this one:
select new
{
Name = node.Element("FullName")!=null ? node.Element("FullName").Value : null,
Zip = node.Element("ZipCode")!=null ? node.Element("ZipCode").Value : null,
Active = node.Element("ActiveCustomer")!=null ? node.Element("ActiveCustomer").Value : null
};
The ? is the conditional operator. For further documentation about this, please have a look here.
you can use ternary operator to check for null.
do like this:
var nodes =
from node in doc.Elements("Customer")
select new
{
Name = node.Element("FullName") !=null ? node.Element("FullName").Value : null,
Zip = node.Element("ZipCode") !=null ? node.Element("ZipCode").Value : null,
Active = node.Element("ActiveCustomer") !=null ? node.Element("ActiveCustomer").Value : null
};

Don't have a nullReferenceException on XML Parsing

I have wrote a c# function in order to parse an XML Stream.
My XML can have several nodes.
Example :
<Stream>
<One>nnn</One>
<Two>iii</Two>
<Three>jjj</Three>
</Stream>
But sometimes, it is :
<Stream>
<Two>iii</Two>
</Stream>
Here is my c# code :
var XML = from item in XElement.Parse(strXMLStream).Descendants("Stream") select item;
string strOne = string.Empty;
string strTwo = string.Empty;
string strThree = string.Empty;
if ((item.Element("One").Value != "")
{
strOne = item.Element("One").Value;
}
if ((item.Element("Two").Value != "")
{
strTwo = item.Element("Two").Value;
}
if ((item.Element("Three").Value != "")
{
strThree = item.Element("Three").Value;
}
With this code, if my Stream is full ( Node On, Two and three), there's no problem! But, if my Stream has only the node "Two", I get a NullReferenceException.
Is there a way to avoid this exception (I cannot change my Stream).
Thanks a lot :)
You should check if item.Element("anything") is null before accessing it's Value property.
if (item.Element("Three") != null && item.Element("Three").Value != "")
You need to do:
if (item.Element("One") != null)
{
strOne = item.Element("One").Value;
}
.Element(String) returns null if an element of the name you requested does not exist.
Checking if value != "" is pointless, because all you are preventing is the reassignment of an empty string to the strOne variable, which is already an empty string. Also, if you really needed to do the empty string check, using String.IsNullOrEmpty(String) method is the preferred way.
Instead of accessing Value property (which raises NullReferenceException if element not exist, as you already know) cast elements to strings. You can use ?? to provide default value for non-existing elements:
string strOne = (string)item.Element("One") ?? String.Empty;
string strTwo = (string)item.Element("Two") ?? String.Empty;
string strThree = (string)item.Element("Three") ?? String.Empty;

convertion issue with DateTime being null in a LINQ query

Here is the configuration of my datatables that I use in my linq query:
I have 2 dataset files (all the columns of all the tables have a DataType specified and their AllowDbNull property set to True):
* deposit_position_imbalance.xsd:
Contains 2 datables : - Imbalance
- ImbalanceDetailForRealTime
* dep_pos_imbalance_detail.xsd:
Contains 1 datatable : - Table
In the code below, the problem lies in the 2 lines "deal_date = b.deal_date".
Indeed, when I retrieve from the database b.deal_date that has a null value, it says in deposit_position_imbalance.Designer.cs :
"StrongTypingException was unhandled by user code"
"The value for column 'deal_date' in table 'ImbalanceDetailForRealTime' is DBNull."
"Specified cast is not valid".
Here is where it throws the error:
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public System.DateTime deal_date {
get {
try {
return ((global::System.DateTime)(this[this.tableImbalanceDetailForRealTime.deal_dateColumn]));
}
catch (global::System.InvalidCastException e) {
throw new global::System.Data.StrongTypingException("The value for column \'deal_date\' in table \'ImbalanceDetailForRealTime\' is DBNull." +
"", e);//ERROR THROWN HERE
}
}
set {
this[this.tableImbalanceDetailForRealTime.deal_dateColumn] = value;
}
}
I have tried to replace the line "deal_date = b.deal_date" by
"deal_date = (DateTime?)b.deal_date"
But I get 2 compilation errors: "The best overloaded method match for dep_pos_imbalance_detail.TableDataTable.AddTableRow(string, System.DateTime)' has some invalid arguments"
and "Argument '2': cannot convert from 'System.DateTime?' to 'System.DateTime'"
I have also tried to replace the line "deal_date = b.deal_date" by
"deal_date = b.deal_date == null ? (DateTime)DBNull.Value : b.deal_date"
But I get a compilation error: "Cannot convert type 'System.DBNull' to System.DateTime'"
I have then tried to replace the line "deal_date = b.deal_date" by
"deal_date = b.deal_date == null ? (DateTime?)DBNull.Value : b.deal_date"
But I get a compilation error: "Cannot convert type 'System.DBNull' to System.DateTime?'"
I have tried another thing : replacing "deal_date = b.deal_date" by
"deal_date = b.Isdeal_dateNull() ? default(DateTime?) : b.deal_date"
But again, I have the following errors:
"The best overloaded method match for dep_pos_imbalance_detail.TableDataTable.AddTableRow(string, System.DateTime)' has some invalid arguments"
and "Argument '2': cannot convert from 'System.DateTime?' to 'System.DateTime'"
The following image (sorry I am not yet allowed to insert an image in stackoverflow, so I put the link instead) shows the definition of my column deal_date in my dataset:
https://lh5.googleusercontent.com/-TEZZ9Hdnkl4/T1aRxF_i7II/AAAAAAAAAAg/BwzrVXIlOHE/s323/deal_date.jpg
We can see that I don't seem to have the possibility to set "System.DateTime?" but only "System.DateTime". And I don't want anything else than null as default value (do we have to put something else than the default value "" in order to make it work?)
UPDATE--> I've tried to put null instead of and the designer gives this error : "The string was not recognized as a valid DateTime. There is a unknown word starting at index 0.".
So I don't understand how I can manage to retrieve null values (I didn't put it in the code, but I have the same problem with the type double). I have the impression that my columns are set to enable null values but obviously not...
Also, when I try to modify the NullValue property to go from "(Throw Exception)" to "(Empty)" or "(Null)", the designer gives this error: "The value entered is not valid for the current data type."
Thank you for your help.
Here is my LINQ query:
deposit_position_imbalance.ImbalanceDataTable dtImbalanceForRealTime;
deposit_position_imbalance.ImbalanceDetailForRealTimeDataTable dtImbalanceDetailForRealTime;
dtImbalanceForRealTime = (deposit_position_imbalance.ImbalanceDataTable)(((deposit_position_imbalance)(dataManager.GetConfig(grid1).ParentDataSource)).Imbalance);
dtImbalanceDetailForRealTime = this.detailForRealTime;
// we separate security_id null and not null
// Security id is not null
deposit_position_imbalance.ImbalanceDataTable iWithSecurityIdNotNull = new deposit_position_imbalance.ImbalanceDataTable();
deposit_position_imbalance.ImbalanceRow[] dr1 = (deposit_position_imbalance.ImbalanceRow[])dtImbalanceForRealTime.Select("security_id is not null");
if (dr1.Count<deposit_position_imbalance.ImbalanceRow>() > 0)
{
DataTable looselyTypedDT1 = dr1.CopyToDataTable<deposit_position_imbalance.ImbalanceRow>();
iWithSecurityIdNotNull.Merge(looselyTypedDT1, true);
}
// Security id is null
deposit_position_imbalance.ImbalanceDataTable iWithSecurityIdNull = new deposit_position_imbalance.ImbalanceDataTable();
deposit_position_imbalance.ImbalanceRow[] dr2 = (deposit_position_imbalance.ImbalanceRow[])dtImbalanceForRealTime.Select("security_id is null");
if (dr2.Count<deposit_position_imbalance.ImbalanceRow>() > 0)
{
DataTable looselyTypedDT2 = dr2.CopyToDataTable<deposit_position_imbalance.ImbalanceRow>();
iWithSecurityIdNull.Merge(looselyTypedDT2, true);
}
var queryWithSecurityIdFound =
from a in iWithSecurityIdNotNull
join b in dtImbalanceDetailForRealTime
on new
{
a.situation_date,
a.security_id,
a.deposit_location_id,
a.account_keeper_id
}
equals new
{
b.situation_date,
b.security_id,
b.deposit_location_id,
b.account_keeper_id
}
where a.situation_date == situation_date
&& a.security_id == security_id
&& a.deposit_location_id == deposit_location_id
&& a.account_keeper_id == account_keeper_id
select new
{
name = a.bo_source_name,
deal_date = b.deal_date
};
var queryWithSecurityIdNotFound =
from a in iWithSecurityIdNull
join b in dtImbalanceDetailForRealTime
on new
{
a.situation_date,
a.security_code,
a.deposit_location_id,
a.account_keeper_id
}
equals new
{
b.situation_date,
b.security_code,
b.deposit_location_id,
b.account_keeper_id
}
where a.situation_date == situation_date
&& a.security_id == security_id
&& a.deposit_location_id == deposit_location_id
&& a.account_keeper_id == account_keeper_id
select new
{
name = a.bo_source_name,
deal_date = b.deal_date
};
var query_final = queryWithSecurityIdFound.Union(queryWithSecurityIdNotFound);
//We fill the 'dep_pos_imbalance_detail Table'
grid1.Clear();
foreach (var item in query_final)
{
((dep_pos_imbalance_detail.TableDataTable)grid1.DataSet.Tables["Table"]).AddTableRow(item.name, item.deal_date);
}
If this is a strongly typed DataSet, it autogenerates properties for nullable columns like Isdeal_dateNull which you should use instead.
if (!row.Isdeal_dateNull)
{
//do something
}
Efficient Coding With Strongly Typed DataSets
Checking for DBNull throws a StrongTypingException
I found a way to solve my issue. In my LINQ queries, I replace "deal_date = b.deal_date" by
"deal_date = b.Field('deal_date')". The convertion can then be made. I can then not use the Designer auto-generated method "AddTableRow" because it doesn't expect the right types. But I write this, a little bit longer but effective:
dep_pos_imbalance_detail.TableDataTable dt = ((dep_pos_imbalance_detail.TableDataTable)grid1.DataSet.Tables["Table"]);
dep_pos_imbalance_detail.TableRow dr = dt.NewTableRow();
foreach (var item in query_final)
{
dr = dt.NewTableRow();
dr.name = item.name;
if (item.deal_date.HasValue)
dr.deal_date = item.deal_date.Value;
else
dr.Setdeal_dateNull();
dt.AddTableRow(dr);
}

Remove element from XML based on attribute value?

I was trying to remove a descendant element from an XElement (using .Remove()) and I seem to get a null object reference, and I'm not sure why.
Having looked at the previous question with this title (see here), I found a way to remove it, but I still don't see why the way I tried 1st didn't work.
Can someone enlighten me ?
String xml = "<things>"
+ "<type t='a'>"
+ "<thing id='100'/>"
+ "<thing id='200'/>"
+ "<thing id='300'/>"
+ "</type>"
+ "</things>";
XElement bob = XElement.Parse(xml);
// this doesn't work...
var qry = from element in bob.Descendants()
where element.Attribute("id").Value == "200"
select element;
if (qry.Count() > 0)
qry.First().Remove();
// ...but this does
bob.XPathSelectElement("//thing[#id = '200']").Remove();
Thanks,
Ross
The problem is that the collection you are iterating contains some element that don't have the id attribute. For them, element.Attribute("id") is null, and so trying to access the Value property throws a NullReferenceException.
One way to solve this is to use a cast instead of Value:
var qry = from element in bob.Descendants()
where (string)element.Attribute("id") == "200"
select element;
If an element doesn't have the id attribute, the cast will returns null, which works fine here.
And if you're doing a cast, you can just as well cast to an int?, if you want.
Try the following:
var qry = bob.Descendants()
.Where(el => el .Attribute("id") != null)
.Where(el => el .Attribute("id").Value = "200")
if (qry.Count() > 0)
qry.First().Remove();
You need to test for the presence of the id attribute before getting its value.

Categories

Resources