ArgumentOutOfRangeException when writing to a model - c#

I'm trying to write to a model for the first time to use in my view: the first time I write to the model I get an ArgumentOutOfRangeException.
Getting error on first write to array:
private IAdditionalQuestionsService _service;
private SelectedAdditionalQuestionAnswerModel _model;
private void InitializeController()
{
_service = GetObject<IAdditionalQuestionsService>();
//GetPageHeaderText(inst);
ViewBag.GetPageTitle = "Additional Questions";
}
[HttpGet]
public virtual ActionResult Edit()
{
Institution inst = _service.GetInstitution(State.GetInstitutionRecordId());
_model = GetObject<SelectedAdditionalQuestionAnswerModel>();
_model.AddQuestAnswModel = new List<AdditionalQuestionAnswerModel>();
GetPageConfiguration1(inst);
return View(_model);
}
AdditionalQuestionAnswerModel m = GetObject<AdditionalQuestionAnswerModel>();
int c = 0;
foreach (var x in inst.AdditionalQuestions)
{
foreach (var y in x.AdditionalQuestionAnswers)
{
// Error is happening on next line *************
_model.AddQuestAnswModel[c].QuestionText = x.QuestionText;
_model.AddQuestAnswModel[c].InstitutionId = x.InstitutionId;
_model.AddQuestAnswModel[c].AdditionalQuestionId = x.Id;
_model.AddQuestAnswModel[c].AnswerText = y.AnswerText;
_model.AddQuestAnswModel[c].IsSelected = false;
c++;
}
}

You can't use _model.AddQuestAnswModel[c] because you never added any items to your list.
Instead of that, create a new object and set its values and then add the item to your list.
Something like this:
AdditionalQuestionAnswerModel newItem = new AdditionalQuestionAnswerModel();
//set the values here to newItem
_model.AddQuestAnswModel.Add(newItem);

You're firstly instantiating your list
_model.AddQuestAnswModel = new List<AdditionalQuestionAnswerModel>();
then you try to access to the first element
_model.AddQuestAnswModel[c] // c == 0
without adding any element to the list.
Add an element before trying to access to a list by index, or more simple:
foreach (var y in x.AdditionalQuestionAnswers)
{
AdditionalQuestionAnswerModel newObj = new AdditionalQuestionAnswerModel
{
QuestionText = x.QuestionText;
InstitutionId = x.InstitutionId;
AdditionalQuestionId = x.Id;
AnswerText = y.AnswerText;
IsSelected = false;
};
_model.AddQuestAnswModel.Add(newObj);
}

Ir means that there no item in your _model.AddQuestAnswModel at the indicated postition, and from your code, I see that _model.AddQuestAnswModel has only be initiated with new List<AdditionalQuestionAnswerModel>(), so it does not contain items (unless you're doing it in the contructor).
You need to fill it like so :
_model.AddQuestAnswModel.Add(item);

Related

C# Calculate field inside LINQ Query

I need some help to calculate a property inside my Linq query.
I know I need to use "let" somewhere, but I can't figure it out!
So, first I have this method to get my list from Database:
public BindingList<Builders> GetListBuilders()
{
BindingList<Builders> builderList = new BindingList<Builders>();
var ctx = new IWMJEntities();
var query = (from l in ctx.tblBuilders
select new Builders
{
ID = l.BuilderID,
Projeto = l.NomeProjeto,
Status = l.Status,
DataPedido = l.DataPedido,
DataPendente = l.DataPendente,
DataEntregue = l.DataEntregue,
DataAnulado = l.DataAnulado
});
foreach (var list in query)
builderList.Add(list);
return builderList;
}
Then, I have a function to calculate the Days between Dates accordingly to Status:
public int GetDays()
{
int Dias = 0;
foreach (var record in GetListBuilders)
{
if (record.Status == "Recebido")
{
Dias = GetBusinessDays(record.DataPedido, DateTime.Now);
}
else if (record.Status == "Pendente")
{
Dias = GetBusinessDays(record.DataPedido, (DateTime)record.DataPendente);
}
else if (record.Status == "Entregue")
{
Dias = GetBusinessDays(record.DataPedido, (DateTime)record.DataEntregue);
}
else if (record.Status == "Anulado")
{
Dias = GetBusinessDays(record.DataPedido, (DateTime)record.DataAnulado);
}
}
return Dias;
}
I need to call the GetDays in a DataGridView to give the days for each record.
My big problem is, How do I get this? include it in Linq Query? Calling GetDays() (need to pass the ID from each record to GetDays() function)!?
Any help?
Thanks
I think it would be easier to create an extension method:
public static int GetBusinessDays(this Builders builder) // or type of ctx.tblBuilders if not the same
{
if (builder == null) return 0;
switch(builder.status)
{
case "Recebido": return GetBusinessDays(builder.DataPedido, DateTime.Now);
case "Pendente": return GetBusinessDays(builder.DataPedido, (DateTime)builder.DataPendente);
case "Entregue": return GetBusinessDays(builder.DataPedido, (DateTime)builder.DataEntregue);
case "Anulado": GetBusinessDays(builder.DataPedido, (DateTime)builder.DataAnulado);
default: return 0;
}
}
Then, call it like that:
public BindingList<Builders> GetListBuilders()
{
BindingList<Builders> builderList = new BindingList<Builders>();
var ctx = new IWMJEntities();
var query = (from l in ctx.tblBuilders
select new Builders
{
ID = l.BuilderID,
Projeto = l.NomeProjeto,
Status = l.Status,
DataPedido = l.DataPedido,
DataPendente = l.DataPendente,
DataEntregue = l.DataEntregue,
DataAnulado = l.DataAnulado,
Dias = l.GetBusinessDays()
});
foreach (var list in query)
builderList.Add(list);
return builderList;
}
To do better, to convert a object to a new one, you should create a mapper.
Why does it need to be a part of the query? You can't execute C# code on the database. If you want the calculation to be done at the DB you could create a view.
You're query is executed as soon as the IQueryable is enumerated at the foreach loop. Why not just perform the calculation on each item as they are enumerated and set the property when you are adding each item to the list?

Get values out of an object into properties of another class

i have a gridview
INSEE1 Commune
------ -------
10002 AILLEVILLE
10003 BRUN
i have a script that return a list of object.
List<object> Temp = ASPxGridView_Insee.GetSelectedFieldValues("INSEE1");
my Temp is a list of object of INSSE1 that i have selected.
but now i add Commune also, so my script become:
List<object> Temp = ASPxGridView_Insee.GetSelectedFieldValues("INSEE1","Commune");
and my Temp is list of object of INSEE1 and Commune look at image:
how can i acces 10002 and AILLEVILLE ?
i have try with cast it of my Pers_INSEE class:
public class Pers_InseeZone
{
string _Code_Insee;
public string Code_Insee
{
get { return _Code_Insee; }
set { _Code_Insee = value; }
}
string _Commune;
public string Commune
{
get { return _Commune; }
set { _Commune = value; }
}
}
foreach (var oItem in Temp )
{
Pers_InseeZone o = (Pers_InseeZone)oItem;
}
but I not work, I can not cast it.
I have tried like this:
foreach (var oItem in Temp )
{
var myTempArray = oItem as IEnumerable;
foreach (var oItem2 in myTempArray)
{
string res= oItem2.ToString();
....
the value of res = 10002, but how can I get the value of AILEVILLE ?
the value of Temp[0].GetType(); is:
Thanks in advance
Ok I thought so, so as already mentioned in the comments you have a array of objects inside each object so you need to cast first every object in your list into an array of objects: object[] then you can access each part. Here is an example that recreates your problem:
object[] array = new object[] {10002, "AILEEVILLE"};
List<object> Temp = new List<object> {array};
And the solution:
// cast here so that the compiler knows that it can be indexed
object [] obj_array = Temp[0] as object[];
List<Pers_InseeZone> persList = new List<Pers_InseeZone>();
Pers_InseeZone p = new Pers_InseeZone()
{
Code_Insee = obj_array[0].ToString(),
Commune = obj_array[1].ToString()
};
persList.Add(p);
Applied to your code it would look something like this:
List<object> Temp = ASPxGridView_Insee.GetSelectedFieldValues("INSEE1","Commune");
List<Pers_InseeZone> persList = new List<Pers_InseeZone>();
foreach (object oItem in Temp )
{
object [] obj_array = oItem as object[];
Pers_InseeZone p = new Pers_InseeZone()
{
Code_Insee = obj_array[0].ToString(),
Commune = obj_array[1].ToString()
};
persList.Add(p);
}
The problem is down to the fact your class doesn't match the same structure as the data you are getting, so it can't be cast into it.
Instead why don't you just iterate over the results and build a new instance of the class?
var tempList = new List<Pers_InseeZone>();
foreach (var oItem in Temp)
{
tempList.Add(new Pers_InseeZone(oItem[0], oItem[1]));
}
You will need to add a constructor to your Pers_InseeZone class, and assign the variables there.

Combine two Lists C# does not exist in current context

In c# I have 2 lists.
First List is like so:
respondent.PrescreenerResponses[i].Response[j] = {[12, some response]}
Second List is like so:
projects.Prescreeners[i].Questions[j] = {Prescreener Questions: Question}
What I want to do is create one list probably like:
Prescreeners[i].Responses[j]
Prescreeners[i].Questions[j]
My code though is somehow wrong:
foreach (var screener in respondent.PreScreenerResponses)
{
var responses = screener;
}
foreach (var screener in project.PreScreeners)
{
var questions = screener;
}
List<string> prescreenerResponses = new List<string>();
prescreenerResponses.Add(questions);
It tells me questions does not exist in the current context. Same goes for responses when I try to use it. I am pretty sure it the wrong data type but not sure what else it would be?
I am pretty sure it the wrong data type
No, it's scope. You declare the var responses and var questions in their respective foreach block. As soon as control leaves those blocks, the variables don't exist anymore.
Declare them first:
IEnumerable<PrescreenerResponses> responses = new List<PrescreenerResponses>;
foreach (...)
{
responses.Add(...)
}
Anyway you can also call AddRange() if you declase responses as List, so you can skip the loop:
responses.AddRange(respondent.PreScreenerResponses);
And it's even more advisable to create a DTO:
class QuestionAndAnswer
{
public PreScreener Question { get; set; }
public PreScreenerResponse Response { get; set; }
}
And use a loop with a counter to fill a List<QuestionAndAnswer>:
var result = new List<QuestionAndAnswer>();
for (int i = 0; i < projects.Prescreeners.Count; i++)
{
result.Add(new QuestionAndAnswer
{
Question = projects.Prescreeners[i],
Answer = respondent.PrescreenerResponses[i],
});
}
Try it like this
List<string> prescreenerResponses = new List<string>();
foreach (var screener in respondent.PreScreenerResponses)
{
var responses = screener;
}
foreach (var screener in project.PreScreeners)
{
prescreenerResponses.Add(screener);
}
You are accessing variable "questions" which is declared outside the scope,
Try this:
List<string> prescreenerResponses = new List<string>();
foreach (var screener in respondent.PreScreenerResponses)
{
var responses = screener;
}
foreach (var screener in project.PreScreeners)
{
var questions = screener;
prescreenerResponses.Add(questions);
}
It´s because 'questions' is declared inside your loop. You could try the code below:
private class QuestionAndResponses
{
public List<Response> Responses {get;set;}
public List<Question> Questions {get;set;}
}
List<QuestionAndResponses> prescreenerResponses = new List<QuestionAndResponses>();
for (var i = 0; i < project.preScreeners.Count(); i++)
{
prescreenerResponses.Add(new QuestionAndResponses ()
{
Responses = new List<Response>(project.preScreenerResponses[i].Response),
Questions = new List<Question>(project.preScreeners[i].Questions)
});
}

Object reference error adding a new select list item

I'm having a problem with the List<SelectListItem>. Whenever the code hits the foreach it says:
object reference not set to an instance of an object.
Am I missing something or can anyone explain why it is failing there?
public ActionResult HammerpointVideos(string category, string type)
{
var stuff = Request.QueryString["category"];
var ItemId = (from p in entities.EstimateItems
where p.ItemName == category
select p.EstimateItemId).FirstOrDefault();
var Videos = (from e in entities.EstimateVideos
where e.EstimateItemId == ItemId
select new Models.HammerpointVideoModel
{
VideoName = e.VideoName,
VideoLink = e.VideoLink
}).ToList();
var model= new Models.HammerpointVideoListModel();
List<SelectListItem> list = model.VideoList;
foreach (var video in Videos)
{
list.Add(new SelectListItem()
{
Selected=false,
Value = video.VideoLink,
Text = video.VideoName
});
}
}
Is ViedoList initialized before? I assume it is not. Create new list add items to it and after that add reference to it in your model:
var model = new Models.HammerpointVideoListModel();
List<SelectListItem> list = new List<SelectListItem>();
foreach (var video in Videos)
{
list.Add(new SelectListItem()
{
Selected=false,
Value = video.VideoLink,
Text = video.VideoName
});
}
model.VideoList = list;
Probably You didn't initialized VideoList in the parameterless constructor of HammerpointVideoListModel class, so it is NOT an empty list.
Put
VideoList = new List<SelectedListItem>();
in the constructor.

Adding properties of an Object together in a collection

I have an app that creates ContactList Objects and adds them to a Dictionary collection. My ContactList objects have a property called AggLabels which is a collection of AggregatedLabel objects containg Name and Count properties. What I am trying to do is change the "else" case of my code snippet so that before adding a new AggregatedLabel it will check whether the AggLabel.Name exists in the AggregatedLabel collection and if this is true it will not add the AggLabel.Name again. Instead it will add the value of AggLabel.Count (type int) to the existing AggregatedLabel object. So for an existing object, if the first Count value was 3 and the second value is 2 then the new Count value should be 5. In simple terms I want to have unique AggLabel Names and add together the Counts where the Names are the same. Hope that makes sense - would appreciate any help. Thanks!
Code snippet
Dictionary<int, ContactList> myContactDictionary = new Dictionary<int, ContactList>();
using (DB2DataReader dr = command.ExecuteReader())
{
while (dr.Read())
{
int id = Convert.ToInt32(dr["CONTACT_LIST_ID"]);
if (!myContactDictionary.ContainsKey(id))
{
ContactList contactList = new ContactList();
contactList.ContactListID = id;
contactList.ContactListName = dr["CONTACT_LIST_NAME"].ToString();
//contactList.AggLabels = new ObservableCollection<AggregatedLabel>() { new AggregatedLabel() { Name = dr["LABEL_NAME"].ToString(), Count = Convert.ToInt32(dr["LABEL_COUNT"])}};
contactList.AggLabels = new ObservableCollection<AggregatedLabel>()
{
new AggregatedLabel()
{
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
};
myContactDictionary.Add(id, contactList);
}
else
{
ContactList contactList = myContactDictionary[id];
contactList.AggLabels.Add(
new AggregatedLabel()
{
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
);
}
}
}
There are two possible solutions I can think of:
1) Use a dictionary instead of the collection of aggregated labels the same way you do it for the contact dictionary. When yout use the name as key and the count as value, you can use the ContainsKey-Method to check whether the label already exists.
contactList.AggLabels = new Dictionary<string, int>();
...
else
{
ContactList contactList = myContactDictionary[id];
if (contactList.AggLabels.ContainsKey(dr["LABEL_NAME"].ToString()))
{
contactList.AggLabels[dr["LABEL_NAME"].ToString()] += Convert.ToInt32(dr["LABEL_COUNT"]);
}
else
{
contactList.AggLabels.Add(dr["LABEL_NAME"].ToString(), Convert.ToInt32(dr["LABEL_COUNT"]));
}
}
2) I you need to use the AggreagteLabel object you can use a loop to search throug all labels.
else
{
bool flagAggLabelFound = false;
ContactList contactList = myContactDictionary[id];
foreach(AggregateLabel aggLabel in contactList.AggLabels)
{
if(aggLabel.Name == dr["LABEL_NAME"].ToString())
{
aggLabel.Count += Convert.ToInt32(dr["LABEL_COUNT"]);
flagAggLabelFound = true;
break;
}
}
if (!flagAggLabelFound)
{
contactList.AggLabels.Add(
new AggregatedLabel()
{
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
);
}
}
I hope this helps.
I would try this:
ContactList contactList = myContactDictionary[id];
AggregateLabel existing = contactList.AggLabels.FirstOrDefault(
l => l.Name == dr["LABEL_NAME"].ToString()
);
if (existing == null) { contactList.AggLabels.Add(
new AggregatedLabel() {
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
);
}
else { existing.Count += Convert.ToInt32(dr["LABEL_COUNT"]); }
#extract these Aggregated Labels and put them in a separate Observable collection:
1) If you a Dictionary for storing the labels in the contact list, this should work:
ObservableCollection<AggregateLabel> copyOfAggregateLabels = new ObservableCollection<AggregateLabel>();
foreach (KeyValuePair<string, int> aggLabel in aggregateLabels)
{
copyOfAggregateLabels.Add(
new AggregatedLabel() {
Name = aggLabel.Key,
Count = aggLabel.Value
}
);
}
2) If you use an ObservableCollection of AggregateLabels, you get an AggregateLable instead of a KeyValuePair in the loop. The rest works the same way.
First I thought of something like:
ObservableCollection<AggregateLabel> copyOfAggregateLabels = new ObservableCollection<AggregateLabel>(aggregateLables);
But this way you get a new ObservableCollection, but the labels stored in the new collection are still referring to the same objects as the ones in the collection you copy.

Categories

Resources