I have the following C# code and I have no idea why it's not working (I'm getting a NullReferenceException error). If I define Recipe as new List() everything starts working OK.
foreach (XElement element in document.Descendants("vegetables"))
{
VegetablesList = (
from vegetables in element.Elements()
select new FoodItem()
{
Name = (vegetables.Element("name") == null) ? null : vegetables.Element("name").Value.ToString(),
Bcg = (vegetables.Element("bcg") == null) ? null : vegetables.Element("bcg").Value.ToString(),
Info = (vegetables.Element("info") == null) ? null : vegetables.Element("info").Value.ToString(),
Recipes = (
from recipes in element.Element("recipes").Elements()
select new Recipe()
{
Name = (recipes.Element("name") == null) ? null : recipes.Element("name").Value.ToString(),
Text = (recipes.Element("text") == null) ? null : recipes.Element("text").Value.ToString()
}
).ToList()
}
).ToList();
VegetablesListBox.ItemsSource = VegetablesList;
}
Thanks for your help!
My guess is that element.Element("recipes") returns null, which means that the recipes element does not exist for that iteration.
Related
I have got 5 different sources of data(request, lsitCC, listSEDI, listSEDIFees and XMLRoot loaded into respective C# Array list objects). I need to construct a JSON request by combining the data from all of those sources based on certain conditions. I have written below code in C# using NewtonSoft.JSON. The cyclomatic complexity for this LINQ query is coming around 40 which is at a higher side. Could anyone please advice on how the complexity can be reduced. Thanks in advance.
I presume the query is pretty user readable, Please let me know if inline comments are required.
var input = from RequestNode in request
select new
{
Documents = (from objCC in lsitCC
where objCC.ID == RequestNode.ID
select new
{
Request = (from objSEDI in listSEDI
where objSEDI.ID == objCC.ID && RequestNode.POSTAL.Count(p => p.PID == objSEDI.PID) > 0
join Config in RequestNode.POSTAL on objSEDI.PID equals Config.PID
select new
{
ReqItem = (Config.ReqItem == null) ? "" : Config.ReqItem,
Code = (RequestNode.Code == null) ? "" : RequestNode.Code,
Camp = (RequestNode.Camp == null) ? "" : RequestNode.Camp,
CCT = new
{
ID = (objCC.ID == null) ? "" : objCC.ID,
Band = (RequestNode.Band == null) ? "" : RequestNode.Band,
Context = (RequestNode.Context == null) ? 0 : RequestNode.Context,
IsActive = (RequestNode.IsActive == null) ? false : RequestNode.IsActive,
MaxLimit = (objCC.MaxLimit == null) ? 0 : objCC.MaxLimit,
MinLimit = (objCC.MinLimit == null) ? 0 : objCC.MinLimit
},
User = RequestNode.User,
POSTAL = new
{
PID = (objSEDI.PID == null) ? "" : objSEDI.PID,
Type = (Config.Type == null) ? "" : Config.Type,
Amount = (Config.Amount == null) ? 0 : Config.Amount,
IsValid = (Config.IsValid == null) ? false : Config.IsValid,
Code = (Config.Code == null) ? "" : Config.Code,
Infos = new
{
Info = (from objRoot in XMLRoot
where objRoot.ID == objCC.ID && objRoot.Channel == "Channel1" && objRoot.Group == "GROUP_1" && objRoot.Code == Config.Type.Substring(0, 3) && objRoot.PIDCode == Config.Type.Substring(3, 1)
select new
{
InfoFrom = (objRoot.InfoFrom == null) ? "" : objRoot.InfoFrom,
Selection = (objRoot.Handling == null) ? "" : objRoot.Selection,
Rate = (objRoot.Rate == null) ? "" : objRoot.Rate
})
},
POSTALFee = from objSEDIFee in listSEDIFees
where objSEDIFee.ID == objCC.ID && objSEDIFee.PID == objSEDI.PID
select new
{
BaseValue = (objSEDIFee.BaseValue == null) ? 0 : objSEDIFee.BaseValue,
UpdatedValue = (objSEDIFee.UpdatedValue == null) ? 0 : objSEDIFee.UpdatedValue,
BaseType = (objSEDIFee.BaseType == null) ? "" : objSEDIFee.BaseType,
UpdatedType = (objSEDIFee.UpdatedType == null) ? 0 : objSEDIFee.UpdatedType
},
OutputRoot = new
{
Output = from output in outputroot
select new
{
Type = 0,
SubType = 0,
OutputReference = 0
}
}
},
})
})
};
var streamRead = JsonConvert.SerializeObject(input, Newtonsoft.Json.Formatting.Indented);
This seems like simply a case of adding the appropriate amount of translators to your code base. Yes Translators are tedious, but if you feel you have too much logic in one query here, I suggest that could be the way for you to go.
This will mean that you will have to either ditch the anon types, or embrace the dynamic keyword (would that even work?!)
You may also need to look at some sort of build pattern or intermediate state.
On further inspection, it appears that you introduce some global variable halfway down the query e.g. XMLRoot & listSEDIFees. It might be nicer if this was more explicit. You could also cut down on excessive work by pre filtering XMLRoot with the static part of your where clause (objRoot.Channel == "Channel1" && objRoot.Group == "GROUP_1") instead of re-running that each time. Maybe something like
var channel1Group1Info = XMLRoot.Where(objRoot=>objRoot.Channel == "Channel1" && objRoot.Group == "GROUP_1").ToArray();
The rest I would just pick off one piece at a time, reducing the amount of work this query is doing.
private void getUserLoginDepartment(string AccessID, string UserPROFid)
{
try
{
DBWPAccountRecordsDataContext DBACCOUNT = new DBWPAccountRecordsDataContext();
var query = (from i in DBACCOUNT.WP_UserAccessPorts
join
z in DBACCOUNT.WP_Departments on i.AccessPortID equals z.Dept_ID
where i.AccessPortID == AccessID && i.ProfileUser_ID == UserPROFid
select new
{
PORT1 = i.AccessPoint1,
PORT2 = i.AccessPoint2,
PORT3 = i.AccessPoint3,
PORT4 = i.AccessPoint4,
DEPT = z.Dept_DESC,
DEPTPORT = z.Dept_PortNo
}).FirstOrDefault();
if (query.PORT1.ToString() != null || query.PORT1.ToString() != string.Empty)
{ Session["Port1"] = query.PORT1; }
else { Session["Port1"] = ""; }
if (query.PORT2.ToString() != null || query.PORT2.ToString() != string.Empty)
{ Session["Port2"] = query.PORT2; }
else { Session["Port2"] = ""; }
if (query.PORT3.ToString() != null || query.PORT3.ToString() != string.Empty)
{ Session["Port3"] = query.PORT3; }
else { Session["Port3"] = ""; }
if (query.PORT4.ToString() != null || query.PORT4.ToString() != string.Empty)
{ Session["Port4"] = query.PORT4; }
else { Session["Port4"] = ""; }
}
finally
{
}
}
The Error occures when i reach break point 1st IF Statement the record on my database shows that its not empty which its value is "WebAdmin" but then suppost to be it should pick it up and store it to the Session["PORT1"] that i have made is there something i missed or i'm doing it wrong on my linq Query. NOTE:*This is an ASP.NET C# Application
EDIT 10/2/2013 0420PM:
It's still an Error After using that method sir.
1) you should check query for null when you use FirstOrDefault
2) you need to check each PORTX for null
3) use string.IsNullOrEmpty( ) to check if the string of PORTX is null
var query = ( ... ).FirstOrDefault( );
if( query != null )
{
if( query.PORT1 != null && !string.IsNullOrEmpty( query.PORT1.ToString( ) ) )
{
}
else { ... }
}
You have to check query.PORT1 for null before calling ToString on it, you can use String.IsNullOrEmpty to check both conditions. Before checking query.PORT1 you need to check if query is null or not. You also need to use && instead of or operator as || will cause the right side of or operator to be evaluated if left is false and on right side calling ToString on null will again through exception.
if (query != null && query.PORT1 != null && query.PORT1.ToString() != string.Empty)
{ Session["Port1"] = query.PORT1; }
Using IsNullOrEmpty
if(query != null && !String.IsNullOrEmpty(query.PORT1))
{
Session["Port1"] = query.PORT1;
}
I have the following tables in an SQL2008 database:
Accommodation
code varchar(18)
name varchar(80)
This table has more columns but I have removed them here for simplicity.
Attributes
code int
name varchar(50)
AccommodationAttributes
AccommodationCode varchar(18)
AttributeCode int
As you may get, AccommodationAttributes describes the many to many relationship between Accommodations and Attributes.
I have created my model (EF5) using database first, and it has created two classes linked with a navigation property.
All this seems correct.
What I am trying to do is add values in the db, but though I am able to add Accommodations and Attributes, I don't seem to be able to make it add the corresponding values in the AccommodationAttributes table.
I am reading from an XML file.
EDIT
Below is the code I am using exactly as it is:
public static void UpdateAccommodation(string file)
{
InterHomeEntities ih = new InterHomeEntities();
Stopwatch sw = new Stopwatch();
ih.Configuration.AutoDetectChangesEnabled = false;
ih.Configuration.ValidateOnSaveEnabled = false;
ih.Configuration.LazyLoadingEnabled = false;
XElement xe = XElement.Load(file);
DateTime DayToProcess = DateTime.Now.AddDays(Properties.Settings.Default.InterHome_DaysToProcess);
var Attributes = xe.XPathSelectElements("//attribute").Select(x => x.Value).Distinct();
foreach (var attribute in Attributes)
{
Attribute at = ih.Attributes.Where(x => x.name == attribute).SingleOrDefault();
bool newEntry = at == null ? true : false;
at = newEntry ? new Attribute { name = attribute } : at;
ih.Attributes.Attach(at);
ih.Entry(at).State = newEntry ? System.Data.EntityState.Added : System.Data.EntityState.Modified;
ih.SaveChanges();
}
var Accommodations = from c in xe.Elements("accommodation") select c;
int AccomodationCount = Accommodations.Count();
int AccomodationIndex = 0;
foreach (var accommodation in Accommodations)
{
AccomodationIndex++;
var AccCode = accommodation.Element("code").Value;
try
{
Accommodation a = ih.Accommodations.Where(x=>x.code == AccCode).SingleOrDefault();
bool newAccommodation = a == null ? true : false;
a = !newAccommodation ? a :
new Accommodation
{
code = accommodation.Element("code") == null ? null : accommodation.Element("code").Value,
name = accommodation.Element("name") == null ? null : accommodation.Element("name").Value,
country = accommodation.Element("country") == null ? null : accommodation.Element("country").Value,
region = accommodation.Element("region") == null ? null : accommodation.Element("region").Value,
place = accommodation.Element("place") == null ? null : accommodation.Element("place").Value,
zip = accommodation.Element("zip") == null ? null : accommodation.Element("zip").Value,
type = accommodation.Element("type") == null ? null : accommodation.Element("type").Value,
quality = accommodation.Element("quality") == null ? (byte?)null : Convert.ToByte(accommodation.Element("quality").Value),
details = accommodation.Element("details") == null ? null : accommodation.Element("details").Value,
brand = accommodation.Element("brand") == null ? null : accommodation.Element("brand").Value,
pax = accommodation.Element("pax") == null ? (double?)null : Convert.ToDouble(accommodation.Element("pax").Value),
sqm = accommodation.Element("sqm") == null ? (double?)null : Convert.ToDouble(accommodation.Element("sqm").Value),
floor = accommodation.Element("floor") == null ? (double?)null : Convert.ToDouble(accommodation.Element("floor").Value),
rooms = accommodation.Element("rooms") == null ? (double?)null : Convert.ToDouble(accommodation.Element("rooms").Value),
bedrooms = accommodation.Element("bedrooms") == null ? (double?)null : Convert.ToDouble(accommodation.Element("bedrooms").Value),
toilets = accommodation.Element("toilets") == null ? (double?)null : Convert.ToDouble(accommodation.Element("toilets").Value),
bathrooms = accommodation.Element("bathrooms") == null ? (double?)null : Convert.ToDouble(accommodation.Element("bathrooms").Value),
lat = accommodation.Element("geodata") == null || accommodation.Element("geodata").Element("lat") == null ? null : accommodation.Element("geodata").Element("lat").Value,
lng = accommodation.Element("geodata") == null || accommodation.Element("geodata").Element("lng") == null ? null : accommodation.Element("geodata").Element("lng").Value,
LastUpdated = DateTime.Now
};
foreach (var attribute in accommodation.Elements("attributes").Elements("attribute").Select(x=>x.Value))
{
Attribute at = ih.Attributes.Where(x => x.name == attribute).SingleOrDefault();
a.Attributes.Add(at);
}
if (newAccommodation)
{
ih.Accommodations.Add(a);
}
else
{
ih.Entry(ih.Accommodations.Where(x => x.code == a.code).SingleOrDefault()).CurrentValues.SetValues(a);
ih.Entry(ih.Accommodations.Where(x => x.code == a.code).SingleOrDefault()).State = System.Data.EntityState.Modified;
}
ih.SaveChanges();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
ih.SaveChanges();
}
After running this code I run the following in SQL:
select COUNT(*) from Accommodations
select COUNT(*)from Attributes
select COUNT(*)from AccommodationAttributes
But though I see entries in the two tables, the link table comes with 0 rows.
I have tried other variations, like attaching the objects to the context, or implicitly specifying that it is a modified object.
By the time that this code will run I am sure that the Attributes are already inserted in the db, but the Accommodation is either an Insert or Update.
UPDATE
After further investigation, it seems that it works when I add a new Accommodation, but it fails when the Accommodation is already in the db and I just add new attributes. In my case in the process of developing I had first added the Accommodation and in a later step of development I created the process to import attributes. So I need to find a way to update the relationship when both accommodation and attribute are already in the db.
I am eager to hear your thoughts,
Giannis
make sure you set the following:
In table Accomodation PK is code.
In table Attrrrribute PK is code.
In table AccomodationAtrribute PK is AccomodationCode+AttributeCode.
In table AccomodationAttribute set a foriegn key of AccomondationCode to colum code in table Accomodation.
In table AccomodationAttribute set a foriegn key of AttributeCode to colum code in table Attribute.
also for the linking table to be filled you need to link an attribute instance to an accomodation or vice versa in the code. somtheing like:
accomodation.Attrbutes.Add(attribute);
What would be the best practice for setting a status depending on several other "columns" retrieved in a linq query.
var result = (from q in query
select new Item
{
ApprovedDate = q.ApprovedDate,
CreatedDate = q.CreatedDate,
DeclinedDate = q.DeclinedDate,
Status = 0
});
I'd like to set the status to either 0, 1, 2.
(ApprovedDate == null and DeclinedDate == null) --> 0
(ApprovedDate != null and DeclinedDate == null) --> 1
(DeclinedDate != null) --> 3
So perhaps something like:
var result = (from q in query
select new Item
{
ApprovedDate = q.ApprovedDate,
CreatedDate = q.CreatedDate,
DeclinedDate = q.DeclinedDate,
Status = (q.CreatedDate == null && q.DeclinedDate == null) ? 0 : (q.ApprovedDate != null && q.DeclinedDate == null) ? 1 : 2
});
I might add even more status combinations, so should I try and do this in the linq select query, in my repository object.. Or later on in the controller where I would do a .ToList() and then foreach the list to set the correct status code?
Having even more than 3 statuscodes, the linq query gets "hard" to read.
What about moving status calculation to Item class? If status property depends on other properties value, then it's definitely calculated property:
var result = from q in query
select new Item
{
ApprovedDate = q.ApprovedDate,
CreatedDate = q.CreatedDate,
DeclinedDate = q.DeclinedDate
});
And
public class Item
{
// other properties
public int Status
{
get
{
if (ApprovedDate == null and DeclinedDate == null)
return 0;
if (ApprovedDate != null and DeclinedDate == null)
return 1;
if (DeclinedDate != null)
return 3;
// etc
}
}
}
Actually I think it's best option, because in this case status calculation logic will be close to required data. If (for some reason) you can't use this approach, then move setting statuses to local items collection:
var items = result.ToList().ForEach(i => i.Status = CalculateStatus(i));
Maybe wrapped all in a function An do a linq like this
var result = (from q in query sele q).AsEnumerable()
.Select( x => new Item()
{
ApprovedDate = x.ApprovedDate,
CreatedDate = x.CreatedDate,
DeclinedDate = x.DeclinedDate,
Status = MyStatusFunction(x.CreatedDate,q.DeclinedDate)
});
public int MyStatusFunction(DateTime ApprovedDate , Datetime DeclinedDate)
{
if (ApprovedDate == null and DeclinedDate == null) return 0;
else if(ApprovedDate != null and DeclinedDate == null) return 1;
else if (DeclinedDate != null) return 3;
}
Attempting to recursively add XElements stepping through a category list.
XElement dataResponse = new XElement("Categories",
from c in db.Categories
where c.CatTypeID.Equals(catTypeID) && c.ParentID.Equals(null)
select new XElement("Category",
c.CatID == null ? null : new XAttribute("CatID", c.CatID),
c.ParentID == null ? null : new XAttribute("ParentID", c.ParentID),
c.CatTitle == null ? null : new XAttribute("CatTitle", c.CatTitle),
c.CatTypeID == null ? null : new XAttribute("CatTypeID", c.CatTypeID),
c.shortDesc == null ? null : new XAttribute("shortDesc", c.shortDesc),
c.longDesc == null ? null : new XAttribute("longDesc", c.longDesc),
c.CatImage == null ? null : new XAttribute("CatImage", c.CatImage)));
internalData = FillSubCatagories(dataResponse).ToString();
Thats the first list of categories now i want to recursively pull all sub categories and nest them in my Xelements FillSubCatagories() method:
private XElement FillSubCatagories(XElement cat) {
IEnumerable<XElement> list = cat.Descendants();
int catTypeID = c.Attribute("CatTypeID") == null ? 1 : Int32.Parse(cat.Attribute("CatTypeID").Value);
foreach (XElement c in list) {
int parentID = Int32.Parse(cat.Attribute("CatID").Value);
XElement sub = new XElement("sub",
from s in db.Categories
where s.CatTypeID.Equals(catTypeID) && s.ParentID.Equals(parentID)
select new XElement("Category",
s.CatID == null ? null : new XAttribute("CatID", s.CatID),
s.ParentID == null ? null : new XAttribute("ParentID", s.ParentID),
s.CatTitle == null ? null : new XAttribute("CatTitle", s.CatTitle),
s.CatTypeID == null ? null : new XAttribute("CatTypeID", s.CatTypeID),
s.shortDesc == null ? null : new XAttribute("shortDesc", s.shortDesc),
s.longDesc == null ? null : new XAttribute("longDesc", s.longDesc),
s.CatImage == null ? null : new XAttribute("CatImage", s.CatImage)));
c.Add(sub);
FillSubCatagories(c);
}
return cat;
}
Alright so the problem comes when I run through the foreach the second time through the method. On int parentID = Int32.Parse(cat.Attribute("CatID").Value); returns a nullreferenceException - "Object reference not set to an instance of an object"
Still getting used to c# coming from java, so be gentle. I'm sure its a glaring error but I haven't seen a clean reason why.
<<<<<<<<<>>>>>>>>>>>>>>
EDITED
new FillSubCategories() looks like this
private XElement FillSubCatagories(XElement cat) {
IEnumerable<XElement> list = cat.Descendants();
int catTypeID = cat.Attribute("CatTypeID") == null ? 1 : Int32.Parse(cat.Attribute("CatTypeID").Value);
foreach (XElement c in list) {
int parentID = Int32.Parse(c.Attribute("CatID").Value);
XElement sub = new XElement("sub",
from s in db.Categories
where s.CatTypeID.Equals(catTypeID) && s.ParentID.Equals(parentID)
select new XElement("Category",
s.CatID == null ? null : new XAttribute("CatID", s.CatID),
s.ParentID == null ? null : new XAttribute("ParentID", s.ParentID),
s.CatTitle == null ? null : new XAttribute("CatTitle", s.CatTitle),
s.CatTypeID == null ? null : new XAttribute("CatTypeID", s.CatTypeID),
s.shortDesc == null ? null : new XAttribute("shortDesc", s.shortDesc),
s.longDesc == null ? null : new XAttribute("longDesc", s.longDesc),
s.CatImage == null ? null : new XAttribute("CatImage", s.CatImage)));
c.Add(sub);
if (sub.Descendants() != null) {
FillSubCatagories(sub);
}
}
return cat;
}
this got me a lot further but I still end up hitting null.
EDIT WORKING METHOD
private void FillSubCategories(XElement cat) {
IEnumerable<XElement> list = cat.Descendants();
foreach (XElement c in list) {
try {
int catTypeID = Int32.Parse(c.Attribute("CatTypeID").Value);
int parentID = Int32.Parse(c.Attribute("CatID").Value);
XElement sub = new XElement("sub",
from s in db.Categories
where s.CatTypeID.Equals(catTypeID) && s.ParentID.Equals(parentID)
select new XElement("Category",
s.CatID == null ? null : new XAttribute("CatID", s.CatID),
s.ParentID == null ? null : new XAttribute("ParentID", s.ParentID),
s.CatTitle == null ? null : new XAttribute("CatTitle", s.CatTitle),
s.CatTypeID == null ? null : new XAttribute("CatTypeID", s.CatTypeID),
s.shortDesc == null ? null : new XAttribute("shortDesc", s.shortDesc),
s.longDesc == null ? null : new XAttribute("longDesc", s.longDesc),
s.CatImage == null ? null : new XAttribute("CatImage", s.CatImage)));
try {
string i = sub.Element("Category").Value;
c.Add(sub);
FillSubCategories(sub);
} catch (Exception) {
continue;
}
} catch (Exception) {
continue;
}
}
}
That doesn't look good. Are you sure that there are things that are not in any category in your table? If so you shouldn't be selecting them since you are doing all the operation on the categoryId. I guess as Chris mentioned, you are getting this exception because you are on a parent category which doesn't have another parent. You need to put an if condition and not parse if it is a parent category. Something like this:
private XElement FillSubCatagories(XElement cat) {
IEnumerable<XElement> list = cat.Descendants();
int catTypeID = c.Attribute("CatTypeID") == null ? 1 : Int32.Parse(cat.Attribute("CatTypeID").Value);
foreach (XElement c in list) {
if(!String.IsNullOrEmpty(cat.Attribute("CatID").Value))
{
int parentID = Int32.Parse(cat.Attribute("CatID").Value);
XElement sub = new XElement("sub",
from s in db.Categories
where s.CatTypeID.Equals(catTypeID) && s.ParentID.Equals(parentID)
select new XElement("Category",
s.CatID == null ? null : new XAttribute("CatID", s.CatID),
s.ParentID == null ? null : new XAttribute("ParentID", s.ParentID),
s.CatTitle == null ? null : new XAttribute("CatTitle", s.CatTitle),
s.CatTypeID == null ? null : new XAttribute("CatTypeID", s.CatTypeID),
s.shortDesc == null ? null : new XAttribute("shortDesc", s.shortDesc),
s.longDesc == null ? null : new XAttribute("longDesc", s.longDesc),
s.CatImage == null ? null : new XAttribute("CatImage", s.CatImage)));
c.Add(sub);
FillSubCatagories(c);
}
}
return cat;
}
There is no attribute "CatId" on the node specified by "cat". Maybe you've hit the top of the hierarchy?
The problem is that cat.Attribute("CatID") is null. You are doing a cat.Attribute("CatID").Value on a null gives you that error.
You could put in a check saying that if it is not null then proceed. Or was there another question?