Linq to XML single or default - asp.net

I am querying an xml and i am storing the results using singleordefault
var query = from nm in xelement.Descendants("EmployeeFinance")
where (int)nm.Element("EmpPersonal_Id") == empID
select new AllowancePaid
{
gradeTaxId = nm.Element("Allow-GradeTax").Elements("Amount").Attributes("BenListId").Select(a => (int)a).ToList(),
gradeTaxAmt = nm.Element("Allow-GradeTax").Elements("Amount").Select(a => (double)a).ToList()
};
Debug.WriteLine("2");
var resultquery = query.SingleOrDefault();
now this line: var resultquery = query.SingleOrDefault(); works fine if it found in the xml file. However, i have a case where my query will result in a null. If i have no value, it would make an entry in the xml file and my query obviously results in null. My question is how do i cater for this without causing my programe to crash. obviously, singleordefault() doesnt work.
***************** EDITED *************************
I read what everyone said so far and it make sense but i am still having a problem.
if (query.Count() == 0)
{
Debug.WriteLine("NULL");
}
else {
var resultquery = query.SingleOrDefault();
Debug.WriteLine("NOT NULL");
}
OR
if (query == null)
{
Debug.WriteLine("NULL");
}
else {
var resultquery = query.SingleOrDefault();
Debug.WriteLine("NOT NULL");
}
OR
var resultquery = query.SingleOrDefault();
if (resultquery == null)
{
Debug.WriteLine("NULL Result");
}
else
{
Debug.WriteLine("NOT NULL");
}
I am getting a System.NullReferenceException error when the first part of the if statement is true. One user said to do this: var resultquery = query.SingleOrDefault(); then use my if..else statement to do the comparison. However i am getting the error at the point of assign query.singleofdefault() to resultquery. So i am lost.. hope someone can help. thank you

what i am trying to understand is this. the documentation states if the result query is 0 it will give a default value, if it is not, it will be a single value. so why doesnt this give a default value? [taken from the comments]
null is the default value for reference types. Apparently AllowancePaid is a reference type (a custom class).

What is the value you want when the there is no value found.
You could either do:
if (resultquery == null) {
// Logic for No result
} else {
// Logic for result found
}
Or you could force a default value
eg.
var resultquery = query.SingleOrDefault() ?? new AllowancePaid();
UPDATE
From the comments posted it appears that the null reference exception is actually caused within the query itself rather than by the assignment to resultquery and use of later.
This updated query should solve the issue
var query = from nm in xelement.Descendants("EmployeeFinance")
where nm.Element("EmpPersonal_Id") != null
&& (int)nm.Element("EmpPersonal_Id") == empID
&& nm.Element("Allow-GradeTax") != null
&& nm.Element("Allow-GradeTax").Elements("Amount") != null
select new AllowancePaid
{
gradeTaxId = nm.Element("Allow-GradeTax").Elements("Amount").Attributes("BenListId").Select(a => (int)a).ToList(),
gradeTaxAmt = nm.Element("Allow-GradeTax").Elements("Amount").Select(a => (double)a).ToList()
};
var resultquery = query.SingleOrDefault();
if (resultquery == null) {
Debug.WriteLine("NULL Result");
} else {
// Logic here
}

Related

ASP.NET & SQL Server: won't update but will append/insert

I am using a database-first approach with a custom html helper to get a state of a checkbox using ajax (without using form in the view). I have two tables:
Tbl_1 -> Id, state (true or false), name (name of checkbox)
Tbl_2 -> Id, user_guid, timestamp, Tbl_1Id (foreign_key)
When I do insert operations, it does without any problem but when I try to update it (based upon the logged in user as it also gets GUID, the table gets appended/inserted with new data).
My controller:
public ActionResult SetState(checkboxstate cbstate)
{
var UserId = new Guid(System.Security.Claims.ClaimsPrincipal.Current.FindFirst("sub").Value);
var ent = new StartopDatabaseEntities();
var cbs = ent.checkboxstates.Where(w => w.Name == "World").FirstOrDefault();
if (cbs == null) // when there are no records in the database
{
ent.checkboxstates.Add(cbstate);
ent.checkboxstateUpdates.SingleOrDefault(c => c.Id == cbstate.Id);
var cbsOp = new checkboxstateUpdates();
cbsOp.timestamp = DateTime.Now;
cbsOp.user_guid = UserId;
cbstate.checkboxstateUpdates.Add(cbsOp);
ent.SaveChanges();
} // record in database, update (I've only one user now, so has to update only this one)
else
{
var cbsOp = new checkboxstateUpdates(); // declare in global
var chc = new checkboxstate(); // to be declared in global
var newCbs = ent.checkboxstateUpdates.Include(c => c.checkboxstate).ToList();
foreach (var u in newCbs)
{
if(u.user_guid==UserId && u.CheckboxStateId == u.checkboxstate.Id)
{
chc.state = cbstate.state;
chc.name = cbstate.name;
ent.checkboxstates.Add(chc);
cbsOp.Tidspunkt = DateTime.Now;
cbsOp.OpdateretAfBruger = UserId;
ent.checkboxstateUpdates.Add(cbsOp);
ent.SaveChanges();
}
}
}
Can anyone explain please why it's not updating but appending/inserting same data with a new Id (primary key)? I have a simple view where Ajax sends a call to the controller with the state and name of the checkbox. I have also tried
Db.Entry(obj).state = EntityState.Modified
without any help
You have not written the code for the logic which want to achieve..
I am not clear on the logic of if block also but the else part can be fixed as following.
var newCbs = ent.checkboxstateUpdates.Include(c => c.checkboxstate).Where(u.user_guid == UserId).FirstOrDefault();
if(newCbs != null) {
newCbs.checkboxstate.state = cbstate.state;
newCbs.checkboxstate.name = cbstate.name;
newCbs.Tidspunkt = DateTime.Now;
newCbs.OpdateretAfBruger = UserId;
ent.SaveChanges();
}
Solved this with the help from #David & #Chetan:
I did some modify in the code as per David:
u.checkboxstate.state=cbstate.state;
u.checkboxstate.name=cbstate.name;
u.timestamp=DateTime.Now;
ent.saveChanges();
I was using the wrong logic i.e. getting instance of the class rather than the 'ent' object. Thanks guys for the help.

Check Cookies AND Session in Same IF Statement

I have a function that checks for Session and Cookies and redirects user based on those.
private void CheckRecruiterLogin()
{
List<string> list = new List<string>();
if (Session["Candidate"] != null ||
Request.Cookies["Candidate"] != null)
{
list = (List<string>)Session["Candidate"];
string status = list[1].ToString();
if (status.Equals("applicant") ||
Request.Cookies["Candidate"]["Status"].Equals("applicant"))
{
Response.Redirect("ApplicantHome.aspx");
}
if (status.Equals("preboarding") ||
Request.Cookies["Candidate"]["Status"].Equals("preboarding"))
{
Response.Redirect("PreboardingHome.aspx");
}
else if (status.Equals("hiring") ||
Request.Cookies["Candidate"]["Status"].Equals("hiring"))
{
Response.Redirect("HiringHome.aspx");
}
}
else if (Session["HR"] != null || Request.Cookies["HR"] != null)
{
list = (List<string>)Session["HR"];
string type = list[1].ToString();
if (type.Equals("preboarder") ||
Request.Cookies["HR"]["Type"].Equals("preboarder"))
{
Response.Redirect("PreboarderList.aspx");
}
else if (type.Equals("datamanager") ||
Request.Cookies["HR"]["Type"].Equals("datamanager"))
{
Response.Redirect("HiringList.aspx");
}
else if (type.Equals("admin") ||
Request.Cookies["HR"]["Type"].Equals("admin"))
{
Response.Redirect("AdminHome.aspx");
}
}
else if (Session["HR"] == null &&
Request.Cookies["HR"] == null)
{
Response.Redirect("index.aspx");
}
}
But the application throws a runtime exception saying Object reference not set to an instance of an object. I believe this is because there are no cookies present.
My question is: Should I separate the checking of sessions and cookies, or can I do it in one statement?
Thanks!
Your code requires both the cookie, and the session.
If this is intended, you want to change the condition to use && instead of ||.
However, it's more likely you intend the code to use session if available, and cookies if session isn't there. This is quite simply done by storing the value in a variable, and using that later:
if (Session["Candidate"] != null || Request.Cookies["Candidate"] != null)
{
var list = Session["Candidate"] as List<string>;
var status = list == null ? Request.Cookies["Candidate"]["Status"] : list[1];
if (status == "applicant")
{
...
}
...
}
That said, using cookies for security checks like this is a bad idea - they are user visible and user editable.
Also, there's no point in using Equals - just use ==. This isn't Java, .NET actually compares the value, not the reference. Although it's probably a better idea to actually do the comparison using invariant culture, case insensitive equality. There's also no point in creating new List<string> - the value is never used. Just declare the variable at the point where you already have something to fill it with.
You are directly checking that if Request has a cookie named "HR" which will throw exception if there is no cookie with this name. So you first need to check if CookieCollection have any cookie with name "HR". Here is method which checks if CookieCollection have a cookie with a given name.
if(Request.Cookies.Get("cookieNmae") !=null)
So change your if statement like this
if (Session["HR"] != null || Request.Cookies.Get("HR") !=null)

Is this an inefficient way to compare data across multiple tables?

I am using the following code to first check if a string is located somewhere within a column in my database. If it is, I am then needing to check if a few additional criteria are met by looking at different parts of the database (can be seen in the code below). I am not sure if this is an efficient method for doing this or if there is a much simpler way:
(from my Controller)
[HttpPost]
public ActionResult Index(FormCollection sampleKey)
{
string code = sampleKey["sampleCode"];
ViewBag.code = code;
// Need to check if this code is active
var order = db.Orders.SingleOrDefault(
o => o.OrderCode == code
&& o.Active == true);
if (order == null)
{
//Invalid
}
else
{
var orderIdent = db.OrderDetails.SingleOrDefault(
p => p.OrderDetailId == order.OrderId);
var barIdent = db.Drink.SingleOrDefault(
q => q.EstablishmentsID == orderIdent.DrinksId);
var barName = db.Establishment.SingleOrDefault(
r => r.EstablishmentsId == barIdent.EstablishmentsID);
ViewBag.barId = barName.name;
ViewBag.sample = order.Email;
var custProfile = CustomProfile.GetUserProfile();
if (custProfile.OwnedBar != barName.name)
{
//Not a match
}
else
{
//Match
}
}
return View();
}
Is this something to worry about? Is there a more efficient way of performing the actions that I am currently performing? Should I change the first table that is referenced to include data from the table I ultimately compare it to to avoid what seems to be an inefficient way of comparing information from different tables?
You should check the SQL query that gets generated. You can do that by e.g. outputting the queries to the console, which is done by setting db.Log = Console.Out;. There should be a similar method to output to the web page in your case. The lazy nature of LINQ makes things difficult to predict.
Other than that, you could make your life much easier if you create foreign key relationships between your tables, i.e. OrderDetails has Orders.OrderId as a FK. This will allow Entity Framework to generate navigational properties for your database. With them your code would look like this:
[HttpPost]
public ActionResult Index(FormCollection sampleKey)
{
string code = sampleKey["sampleCode"];
var detail = db.Orders.Where(o => o.OrderCode == code && o.Active == true)
.Select(o => new {
OrderCode = o.OrderCode,
BarId = o.Drink.Establishment.Select(n => n.name),
Sample = o.Email
})
.SingleOrDefault();
if (detail != null)
{
ViewBag.code = detail.OrderCode;
ViewBag.barId = detail.BarId;
ViewBag.sample = detail.Sample;
var custProfile = CustomProfile.GetUserProfile();
if (custProfile.OwnedBar == detail.BarId)
{
//Match
}
else
{
//Not a match
}
}
else
{
//Invalid
}
return View();
}

Picking out Just JSON Data Returned from ASP.NET MVC3 controller Update

I've got data returned from my JavaScript client that just includes the data that has changed. That is, I may have an array with each row containing 10 columns of JSON downloaded, but on the Update, only the data that is returned to me is the data that got updated. On my update, I only want to update those columns that are changed (not all of them).
In other words, I have code like below but because I'm passing in an instance of the "President" class, I have no way of knowing what actually came in on the original JSON.
How can I just update what comes into my MVC3 update method and not all columns. That is, 8 of the columns may not come in and will be null in the "data" parameter passed in. I don't want to wipe out all my data because of that.
[HttpPost]
public JsonResult Update(President data)
{
bool success = false;
string message = "no record found";
if (data != null && data.Id > 0)
{
using (var db = new USPresidentsDb())
{
var rec = db.Presidents.FirstOrDefault(a => a.Id == data.Id);
rec.FirstName = data.FirstName;
db.SaveChanges();
success = true;
message = "Update method called successfully";
}
}
return Json(new
{
data,
success,
message
});
}
rec.FirstName = data.FirstName ?? rec.FirstName;
I would use reflection in this case because the code will be too messy like
if (data.FirstName != null)
rec.FirstName = data.FirstName
.
.
.
and so on for all the fields
Using reflection, it would be easier to do this. See this method
public static void CopyOnlyModifiedData<T>(T source, ref T destination)
{
foreach (var propertyInfo in source.GetType().GetProperties())
{
object value = propertyInfo.GetValue(source, null);
if (value!= null && !value.GetType().IsValueType)
{
destination.GetType().GetProperty(propertyInfo.Name, value.GetType()).SetValue(destination, value, null);
}
}
}
USAGE
CopyOnlyModifiedData<President>(data, ref rec);
Please mind that, this won't work for value type properties.

default values in LINQ query

I have following Linq query/function in my MVC3 application.
public AuditTrail GetNamesAddressesEmployers(long registryId , int changedField) {
var otherNameAndAddress = (from a in context.AuditTrails
where a.ChangedField == changedField
&& a.RegistryId == registryId
select a).FirstOrDefault();
return otherNameAndAddress;
}
I want that if otherNameAndAddress = null then its properties should be assigned some values.
otherNameAndAddress has Name and description property. This GetNamesAddressesEmployers is being used at 3 places. I want to assign different values to name and description when otherNameAndAddress = null at all three locations.
You're already using FirstOrDefault() so why not specify the Default:
public AuditTrail GetNamesAddressesEmployers(long registryId, int changedField)
{
return context.AuditTrails
.Where(a => a.ChangedField == changedField
&& a.RegistryId == registryId)
.DefaultIfEmpty(new AuditTrail { /* fill properties here */ })
.FirstOrDefault();
}
Well, you could change the return statement to:
return otherNameAndAddress ?? new AuditTrail { Name = "Default",
Description = "Default };
or something like that... but you say you want to assign different default values for different calls. That means you'll either need to pass the default in, or perform the defaulting (e.g. in the same way, via the null-coalescing operator) at the call site.
For example:
public AuditTrail GetNamesAddressesEmployers(long registryId, int changedField,
AuditField defaultValue) {
var otherNameAndAddress = (from a in context.AuditTrails
where a.ChangedField == changedField
&& a.RegistryId == registryId
select a).FirstOrDefault();
return otherNameAndAddress && defaultValue;
}
or keep it as it currently is, and use this at the call site:
var auditTrail = GetNamesAddressesEmployers(registryId, changedField) ??
new AuditTrail { Name = "Foo", Description = "Bar" };
It's not really clear which is best based on your description.
EDIT: As mentioned by Justin, you could use DefaultIfEmpty instead (just before FirstOrDefault). That means you have to pass the value in rather than doing it at the call site, but other than that they're very similar solutions.

Resources