I have list with items like this:
selCountry[0] = {IdCountry = 1, LongName = "Austria", CountryUrl = "austria"}
selCountry[1] = {IdCountry = 5, LongName = "Brasil", CountryUrl = "brasil"}
I know CountryUrl and I need to find IDcountry
I tried these ways:
int idCountry;
string country = "brasil";
idCountry = Convert.ToInt32(selCountry.FirstOrDefault(m => m.CountryUrl == country).IdCountry);
idCountry = selCountry.Find(x => x.CountryUrl == country).IdCountry;
idCountry = selCountry.SingleOrDefault(x => x.CountryUrl == country).IdCountry;
Every time I get error
Object reference not set to an instance of an object
If I debug it I can see something similar like this:
System.Linq.Enumerable.SingleOrDefault(...) returned null.
Where did I make a mistake?
PS: My question isn’t about, how can I manage problem with null, but, where is problem in my code, because in my example "brasil" exists in the list, so, how can I get IdCountry? If I use only only First instead FirstOrDefault I get System.InvalidOperationException: 'Sequence contains no matching element' So how is it possible, that there is not matching element?
Declaration of my list
List<CountriesListModel> selCountry = new List<CountriesListModel>();
selCountry = listOfCoutry.CountriesList(24);
My model:
public class CountriesListModel
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int IdCountry { get; set; }
[Required]
public string LongName { get; set; }
public string CountryUrl { get; set; }
}
My debug result:
https://www.dropbox.com/s/3m8a81ltxn6kiew/listproblem.jpg?dl=0
here is the solution:
selCountry.Where(w=>w.CountryUrl.Equals(country)).select(s=>s.IDcountry)
As you see above you need to use .select(s=>s.IDcountry) because the result of Single of Where is one item which looks like
{IDcountry = 1, LongName = "Austria", CountryUrl = "austria"}
and from that you need to select IDcountry attribute.
(You can use Single instead of Where if you are sure you will have the country always if not you need to check if we have result and it is not null then select)
System.Linq.Enumerable.SingleOrDefault(...) returned null.
to fixed null value
var ID = selCountry.Where(x => x.IDcountry == 1).Select(s=>s.LongName ).FirstOrDefault();
I thank all of you. I'm stupid idiot - only problem was with - declaration string country - brasil vs. brazil. Really thanx to #NineBery. You saved my night....
Related
I am using an api for a shopping cart that has some complex json (very complicated to me) data structured like in my screenshot below. In this scenario in my code I am trying to fix an error which I am going to explain by illustrating the data and how its structured as I am very new to JSON and arrays.
This is from the Visual Studio json reader of the data that belongs to an order placed by a customer. This item at the index of [0] has a customFields which has a value.
When a customer completes a purchase, some items they bought can have custom fields, like the size of a shirt (Large) or (Medium) or (Small) etc... In the JSON these customFields have a value which in this case is the size of the shirt for me to display at the thank you page so the customer knows what size he bought. Essentially I am trying to have the data ready to pass to the thank you page view.
When I am calling for these items in my controller, the code only works if ALL the items that were purchased have a customFields. If the customer buys something like a coffee mug that has NO custom fields, then the application breaks because I guess my code is only accounting for items that actually have customFields.
This is the code that I have so far that only works when ALL items that were purchased have a custom field. This is inside my controller.
public ActionResult Thankyou(string token)
{
int itemsCountAddedToCart = (int)obj["items"].Count();
var items = obj["items"].Select(o =>
new Item
{
name = o["name"].ToString(),
quantity = int.Parse(o["quantity"].ToString()),
price = double.Parse(o["price"].ToString()),
image = o["image"].ToString(),
url = o["url"].ToString(),
//This customFields is what works, but only if all items had custom fields.
customFields = o["customFields"][0]["value"].ToString(),
});
thankYouViewModel.OrderItems = items;
}
//ThankYou View Model that loads hold the data to be able to show in the view.
public class ThankYouViewModel
{
public IEnumerable<Item> OrderItems { get; set; }
}
public class Item
{
public string name { get; set; }
public double price { get; set; }
public int quantity { get; set; }
public string image { get; set; }
public string url { get; set; }
//customFields
public string customFields { get; set; }
}
So that code above works, but breaks when I have items that do not have customFields. This is the error that I get:
System.ArgumentOutOfRangeException: 'Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index'
So how should my code look where its currently breaking so that it can account for situations where one of the items from the JSON does not have a customFields attribute? I am very stuck and have tried to add some conditional statements but did not work because I am dealing with some complex json I do not understand very well yet.
If you want to forget the possibility of more than one element in the customFields array, and only cast the first element value to a string, then use this:
customFields = (o["customFields"] == null || o["customFields"].Count() == 0)?null:o["customFields"][0]["value"].ToString(),
With customFields = o["customFields"][0]["value"].ToString(), you directly receive the value from the customFields Array. If there is no Array in your case then there is nothing to get.
I would recommend you to check if your customFields exists:
var item = new Item ();
item.name = o["name"].ToString();
item.quantity = int.Parse(o["quantity"].ToString());
item.price = double.Parse(o["price"].ToString());
item.image = o["image"].ToString();
item.url = o["image"].ToString();
if(o["customFields"] != null)
{
item.customFields = o["customFields"][0]["value"].ToString();
}
I have List<ParametersDetails>. Parameters and ParametersDetails class is like -
public class ParameterDetails
{
public string Name { get; set; }
public List<Parameter> Parameters{get;set;}
}
public class Parameter
{
public string Name { get; set; }
public string Type { get; set; }
public string Value { get; set; }
public string AccountName { get; set; }
}
I want ParameterDetails list should not contain any parameter with duplicate name. If any duplicate parameter name found I want to replace the name with Parametername+ parameterDetails name from the dictionary.
I can do it by traversing items and then modify items but I want to do it with lesser code.
The problem is how to traverse and find duplicates from list ..?
Is it possible in Linq?
What I am doing right now - I have taken all the parameters in 1 list and find out duplicates
var hasDupes = dflist.GroupBy(x => new { x.Name })
.Where(x => x.Skip(1).Any()).ToArray();
Next, I am selecting the item from List
parameterdetails.Select(x => x.Parameters.Where(p => p.Name == dupeList.Key.ToString())).ToList();
Now I don't want to loop through ParameterDetials List to modify the items.
Is any easier way?
Ex-
I am having 2 items in ParameterDetails like -
ParameterDetails:
[
{
name: "test1",
Parameters:[
{
"Name":"param1",
"Type":"paramtype1",
"Value":"value1",
"AccountName":"accname1"
},
{
"Name":"param2",
"Type":"paramtype2",
"Value":"value2",
"AccountName":"accname2"
}]
},
{
name: "test2",
Parameters:[
{
"Name":"param1",
"Type":"paramtype11",
"Value":"value11",
"AccountName":"accname11"
},
{
"Name":"param2",
"Type":"paramtype22",
"Value":"value22",
"AccountName":"accname22"
}]
}]
If I am having param1 as a duplicate name so in that I want to replace it as "param1+test2" so that it will be unique.
Yo find they duplicated items in a list you can use LINQ, this is the code using it:
var duplicates = dflist.GroupBy(s => s) .SelectMany(grp => grp.Skip(1));
That code will return all duplicated items in dflist. If you want to select all object that have an unique attribute value, you can use this code line:
var withoutNameDuplicates = dflist.GroupBy(s => s.Name).Select(grp => group.First());
Then you can change the objects Name attribute to the duplicated objects by, using this code:
var nameChangedDuplicates = duplicates.Select( s => {s.Name = s.Name + "something"; }).ToList();
If you only want to get all the items from the list without duplicates, you can apply Dinstinct() method to dflist, that method will return an IEnumerable<T> result:
var withoutDuplicates = dflist.Distinct();
And, if you want to return a List<T> instead IEnumerable<T>, you must use ToList() method like this:
var withoutDuplicates = dflist.Distinct().ToList();
You can get more information about it in these pages:
c# - How to get duplicate items from a list using LINQ?
Enumerable.DistinctMethod (IEnumerable)
C# - Update all objects in a collection using LINQ
Something weird is happening and I am not able to understand why.. here's the scenario -
I have a model with few properties when I populate the model the properties in model does have values set (checked by putting breakpoints). It comes on the view also but it is not being shown on textbox. It is showing the default value (guessing by seeing the item textbox on the page as it has 0).
Below is my model -
public class PriceEnquiryModel
{
[DisplayName("Item")]
public int item { get; set; }
[DisplayName("Description")]
public string description { get; set; }
[DisplayName("UOP")]
public string uop { get; set; }
[DisplayName("UOS")]
public string uos { get; set; }
[DisplayName("Pack Description")]
public string pack_description { get; set; }
[DisplayName("Pack Size")]
public string PackSize { get; set; }
}
This is the controller;s code -
public ActionResult Search(PriceEnquiryModel price)
{
var priceEnquiryModel = new PriceEnquiryModel();
// Read parameter values from form.
int item = Convert.ToInt32(Request.Form["txtSearch"].ToString());
int maxrow = Convert.ToInt32(Request.Form["txtmaxrow"].ToString());
string priceType = !string.IsNullOrWhiteSpace(price.priceType) && price.priceType.ToUpper().Equals("STA") ? "N" : "Y";
// Get the price information
var operationResult = priceBal.SearchPriceEnquiry(0, item, price.price_scheme, priceType, maxrow);
var priceEnquiryDomList = (List<PriceEnquiryDom>)operationResult[0].Result;
// Check if we have something
if (priceEnquiryDomList != null && priceEnquiryDomList.Count > 0)
{
// Parse the model.
priceEnquiryModel = helper.ConvertDomToModel(priceEnquiryDomList[0]);
// Prepare the list.
priceEnquiryModel.PriceEnquiryModelList = new List<PriceEnquiryModel>();
foreach (var priceEnquiryDom in priceEnquiryDomList)
{
var priceEnquiryModelListItem = helper.ConvertDomToModel(priceEnquiryDom);
priceEnquiryModel.PriceEnquiryModelList.Add(priceEnquiryModelListItem);
}
Session["mainModel"] = priceEnquiryModel;
}
// Prepare product drop down list items if searched by product desc
if (TempData.Count > 0 && TempData["Products"] != null)
{
var products = TempData["Products"] as List<ProductSearchByDescModel>;
ViewBag.Products = products;
}
return View("Index", priceEnquiryModel);
}
This is the model on the View (while debugging) -
This is how I am rendering the model on the view -
This is the page after running -
Does anyone has any idea what is going on ? I have done the same thing on multiple pages and all run as expected.
Thanks in Advance.
Rohit
The issue is that your method has parameter PriceEnquiryModel price but then you return a new instance of PriceEnquiryModel (named priceEnquiryModel). The process of model binding includes binding your model and adding its values to ModelState (along with any validation errors).
When you return the view, the html helper methods use the values from ModelState (not the models values) so attempting to change the values (which I assume is what priceEnquiryModel = helper.ConvertDomToModel(priceEnquiryDomList[0]); is doing) is ignored by the helpers.
For an explanation of why this is the default behavior, refer the second part of this answer
One option to call ModelState.Clear() before setting new values for the properties of PriceEnquiryModel
I want to sort the List where the objects properties are of string type.
One of the property is a time of string type, and when i try to sort it sorts like below.
1:12, 13:24, 19:56, 2:15, 26:34, 8:42.
Here the sorting is happening on string basis.
Now i want to convert that sting to double (1.12, 13.24, 19.56, 2.15, 26.34, 8.42) and sort it. Then populate the data by replacing the '.' with ':'.
I tried some thing like below, but still the sorting is happening on string basis.
public class Model
{
public string Duration { get; set; }
public string Dose { get; set; }
}
List<Model> lsModelData = new List<Model>();
//Added some model objects here
// query for sorting the lsModelData by time.
var sortedList = lsModelData.OrderBy(a => Convert.ToDouble(a.Duration.Replace(":", ".")));
I am trying to replace the time ":" with "." and then convert that to double to perform the sort operation.
Can any one please correct this statement to work this sorting properly.
If you want to sort data according to duration try this. its tested surely works for you.
public class Models
{
public string Duration { get; set; }
public string Dose { get; set; }
}
List<Models> lstModels = new List<Models>();
lstModels.Add(new Models { Duration = "101:12" });
lstModels.Add(new Models { Duration = "13:24" });
lstModels.Add(new Models { Duration = "19:56" });
List<Models> sortedList = (from models in lstModels
select new Models
{
Dose = models.Dose,
Duration = models.Duration.Replace(':','.')})
.ToList()
.OrderBy(x=>Convert.ToDouble(x.Duration))
.ToList();
I'm not sure what you really want, but if you want to return only the duration, then select it after sort
var sortedList = lsModelData.OrderBy(a => Convert.ToDouble(a.Duration.Replace(":", "."))).Select(a=> a.Duration).ToList();
or
var sortedList = lsModelData..Select(a=> a.Duration).OrderBy(a => Convert.ToDouble(a.Replace(":", "."))).ToList();
In cases like this it works best to order by length and then by content:
var sortedList = lsModelData.OrderBy(a => a.Duration.Length)
.ThenBy(a => a.Duration)
Converting database data before sorting (or filtering) always makes queries inefficient because indexes can't be used anymore.
I'm trying to display some text from a list depending on the key:
<td>#x.OutcomeSummary</td>
<td>#Model.SummaryOutcomes.FirstOrDefault(c => c.Value == x.OutcomeSummary).Name</td>
<td>#Model.SummaryOutcomes.FirstOrDefault(x.OutcomeSummary).Name</td>
In this case x.OutcomeSummary is 7 and I would like for it to get the relevant text from SummaryOutcomes with a key of 7.
The second line gives me the following error: System.NullReferenceException: Object reference not set to an instance of an object.
And the third line gives me an error saying that the FirstOrDefault command has invalid arguments.
It imports the following model:
public class DogSummaryView
{
public IEnumerable<DogIncident> Incidents { get; set; }
public IEnumerable<Category> SummaryOutcomes { get; set; }
public IEnumerable<Category> DogBreeds { get; set; }
}
This is the category class:
public class Category
{
public string Value { get; set; }
public string Name { get; set; }
public bool InUse { get; set; }
}
And this is the controller:
public ActionResult Summary()
{
var vm = new DogSummaryView
{
Incidents = repository.GetAllRecords().OrderByDescending(x => x.DateRecieved),
SummaryOutcomes = repository.GetAllSummaryOutcomes()
};
return View("Summary", vm);
}
And finally here you can see that the list is populated and initialized:
Is there anyway of getting it so that instead of displaying 7, it displays the correct summary outcome?
Thanks
Thank you so so much to fourpastmidnight for his persistent help with this, and not only helping me to find a solution, but also helping me to understand just exactly where the problem lied. Here's an updated (working!) solution:
#foreach (var x in Model.Incidents)
{
var summaryOutput = "";
var firstOutcomeSummary = Model.SummaryOutcomes.FirstOrDefault(c => c.Value == x.OutcomeSummary);
if (firstOutcomeSummary != null) { summaryOutput = Model.SummaryOutcomes.FirstOrDefault(c => c.Value == x.OutcomeSummary).Name.ToString(); }
<tr>
<td>#Html.Raw(summaryOutput)</td>
</tr>
}
Ok, the problem is you're trying to compare a string to an int.
Change the second line as follows:
#Model.SummaryOutcomes.FirstOrDefault(c => c.Value == x.OutcomeSummary.ToString()).Name;
// You could also use '.Value'.
That should solve your problem.
UPDATE
Hmm, maybe x.OutcomeSummary.ToString() is resulting in the type name of the enumeration and not the integer value of the enumeration constant value.
Try updating the above line to the following:
#Model.SummaryOutcomes.FirstOrDefault(c => c.Value == ((int)x.OutcomeSummary).ToString()).Name;
UPDATE 2014-03-21
According to the OP's latest comment, try the following:
// If x.OutcomeSummary is the outcome summary name, then....
var firstOutcomeSummary = #Model.SummaryOutcomes.FirstOrDefault(c => c.Name == x.OutcomeSummary)
if (firstOutcomeSummary != null)
// Do something here.
// Else, if x.OutcomeSummary is the outcome summary value, e.g. "7", then...
var firstOutcomeSummary = #Model.SummaryOutcomes.FirstOrDefault(c => c.Value == x.OutcomeSummary)
if (firstOutcomeSummary != null)
// Do something here.
FirstOrDefault will do just that return the first element that matches the predicate or return default, i.e. null. Calling .Name on a null object will throw a NullReferenceException
In sum, the behavior you are describing will occur if there's no instance of Category in the enumeration SummaryOutcomes whose value is 7.