When I add an object in bCPList after looping, all records become same as the last object inserted. Why's that happening and how could I solve this?
public List<Entity.BCPToolkitWorkplace> Load_work_Place(List<BCPToolkitWorkplace> bCPToolkit)
{
Entity.BCPToolkitWorkplace bCP = new Entity.BCPToolkitWorkplace();
List< Entity.BCPToolkitWorkplace> bCPList = new List<Entity.BCPToolkitWorkplace>();
foreach (var item in bCPToolkit)
{
bCP.txn_type = item.txn_type;
bCP.workplace_id = item.workplace_id;
bCP.workplace_name = item.workplace_name;
bCP.workplace_number = item.workplace_number;
bCPList.Add(bCP);
}
return bCPList;
}
Declare the BCP object inside the loop as follows
public List< Entity.BCPToolkitWorkplace> Load_work_Place(List< BCPToolkitWorkplace> bCPToolkit)
{
List< Entity.BCPToolkitWorkplace> bCPList = new List< Entity.BCPToolkitWorkplace>();
foreach (var item in bCPToolkit)
{
// Declaring the bcp object inside the loop
Entity.BCPToolkitWorkplace bCP = new Entity.BCPToolkitWorkplace();
bCP.txn_type = item.txn_type;
bCP.workplace_id = item.workplace_id;
bCP.workplace_name = item.workplace_name;
bCP.workplace_number = item.workplace_number;
bCPList.Add(bCP);
}
return bCPList;
}
You need to move this line to the inside of the foreach.
Entity.BCPToolkitWorkplace bCP = new Entity.BCPToolkitWorkplace();
The reason this is happening is that Entity.BCPToolkitWorkplace, apparently is defined as a class (reference-type), and you defined only one instance of that class at the top, so you were technically adding the same exact instance to the list over and over.
Take a look at the answers here for more about how reference types work.
Related
I'm exporting some data from database to excel using CLOSEDXML. I need to add the corresponding objects/item to each object in the 'newModelist' IQueryable and add all the object to new List. In my case new row were added in the list using list.add method, however the old record is replaced by the next row/object. I'm not quite what would be the correct way to implement this.
var getData = _db.Database.Where(y => y.identifier == Identifier);
var newModelist = new MainModel();
var listXML= new List<listXML>();
foreach(var item in getData)
{
newModelist.col1 = item.A;
newModelist.col2 = item.B;
newModelist.col2 = item.C;
listXML.Add(newModelist);
}
You need to understand what an instance is.
You are currently modifying the same object instance. And you are adding the same instance to the List on every iteration.
Since List only stores the reference to an instance, your List currently contains multiple references to the same instance. Each index will return the same element.
If you want individual object instances you must create each using the new keyword:
foreach(var item in getData)
{
var newModelist = new MainModel
{
col1 = item.A,
col2 = item.B,
col3 = item.C
};
listXML.Add(newModelist);
}
MainModel is a reference type and modifying the value will reflect in the all the references, so you need to create a new instance while setting the properties in the loop. Moving creation of newModelList to for loop would do
foreach(var item in getData)
{
var newModelist = new MainModel();
newModelist.col1 = item.A;
newModelist.col2 = item.B;
newModelist.col2 = item.C;
listXML.Add(newModelist);
}
I'm using foreach to transfer data from list to another but when adding value updated automatically to last value added. For example:
list1 = [1,2,3]
list2 = new List<Model>()
foreach(var item in list1) {
list2.Add(item)
}
the result in list2 is [ 3, 3, 3]
Actually example is below :
var _sizes = new List<ProductsSize>();
var _size = new ProductsSize();
if (model.Dynamic_ProductsSize.Count > 0)
{
foreach (var item in model.Dynamic_ProductsSize)
{
_size.SizeId = item;
_sizes.Add(_size);
}
}
model.ProductsSize = _sizes.ToList();
I need to know why it only takes the last item and what is the solution for this case
You only have one ProductsSize object:
var _size = new ProductsSize();
And you keep modifying that same object. All references to that object, including any list elements it's been added to, get updated when you modify that one object.
Instead, create your new object in the loop:
foreach (var item in model.Dynamic_ProductsSize)
{
var _size = new ProductsSize();
_size.SizeId = item;
_sizes.Add(_size);
}
That way each element in the list is a new object instead of the same object added multiple times.
Side note, you have a few things in the code which aren't necessary. Checking the length before the loop, for example, as well as converting a list to a list at the end.
In fact, I imagine all of the code shown can be shortened to simply this:
model.ProductsSize = model.Dynamic_ProductsSize.Select(p => new ProductsSize { SizeId = p }).ToList();
In which case you're also just converting one model property to another model property. Why not put this logic in the model itself and skip the whole thing?
public IEnumerable<ProductsSize> ProductsSize
{
get { return this.Dynamic_ProductsSize.Select(p => new ProductsSize { SizeId = p });
}
Unless there's a particular reason you want the same data twice in two different properties that isn't clear from this code, having one set of data and just different views/calculations/etc. of that data is often preferred.
Create a new object before adding it to the list. You can use the object initializer syntax to keep it concise:
if (model.Dynamic_ProductsSize.Count > 0)
{
foreach (var item in model.Dynamic_ProductsSize)
{
_sizes.Add(new ProductsSize(){SizeId = item});
}
}
I have some code that's main purpose is to combine multiple like lists into one master list to return with the View.
ActivityAuditDetails searchParams = new ActivityAuditDetails();
ActivityAuditDetails finalResults = new ActivityAuditDetails();
List<string> finalChangedColumns = new List<string>();
List<string> finalOldValues = new List<string>();
List<string> finalNewValues = new List<string>();
string finalAuditAction = string.Empty;
List<int> auditKeys = AuditIdentityId.Split(',').Select(int.Parse).ToList();
string url = "/Audit/GetActivityAuditDetails";
try
{
foreach (int auditKey in auditKeys)
{
searchParams.AuditIdentityId = auditKey;
ActivityAuditDetails result = // SOME METHOD THAT RETURNS RESULTS AS IT SHOULD;
finalChangedColumns.Concat(result.ChangedColumns);
finalAuditAction = result.AuditAction;
finalOldValues.Concat(result.OldValues);
finalNewValues.Concat(result.NewValues);
}
finalResults.ChangedColumns = finalChangedColumns;
finalResults.AuditAction = finalAuditAction;
finalResults.OldValues = finalOldValues;
finalResults.NewValues = finalNewValues;
}
catch (Exception e)
{
e.ToLog();
}
return View(finalResults);
I can see that the result object is populated as it should be in the debugger. I thought the Concat method would work to combine the lists, but my final values in the foreach loop never get update\incremented ( the list count remains zero ).
Is there another way to accomplish this, or am I having a morning brain fart? My question was not about the differences, as I was aware of them. I just had a momentary lapse of reason.
You likely want to use AddRange rather than Concat.
The former adds the data directly to the List. The latter concatenates data into a new IEnumerable.
But because you are not assigning the result of Concat to anything (i.e. var g = finalChangedColumns.Concat(result.ChangedColumns);) your Concat calls do effectively nothing.
List<T>.AddRange(IEnumerable<T> collection) (link to info) probably does what you're looking for, right?
Adds the elements of the specified collection to the end of the List.
From documentation:
string[] input = { "Brachiosaurus",
"Amargasaurus",
"Mamenchisaurus" };
List<string> dinosaurs = new List<string>();
dinosaurs.AddRange(input);
//The list now contains all dinosaurs from the input string array
I try the following code to serialize my objects into xml file, but when run this code the last item in the list values serialize by the count for the list.
I want to serialize every item in the list? what is the wrong in my code
Can anyone help me ?
//list of class values
List<values> valus = new List<values>();
values value = new values();
foreach (Control control in Controls)
{
value.ctrlname = control.Name.ToString();
value.ctrllocation = control.Location.ToString();
value.ctrltext = control.Text.ToString();
value.ctrltype = control.GetType().ToString();
value.ctrlstatus = control.Enabled.ToString();
valus.Add(value);
}
System.Xml.Serialization.XmlSerializer writer =
new System.Xml.Serialization.XmlSerializer(typeof(values));
var path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "//Serialization.xml";
System.IO.FileStream file = System.IO.File.Create(path);
foreach (values item in valus)
{
writer.Serialize(file, item);
}
file.Close();
First lets validate that your classes are serialzble, like so:
[Serializable()]
public class rootValues
{
public rootValues()
{
valuesArray = new List<values>();
}
[XmlElement("item", typeof(values))]
public List<values> valuesList { get; set; }
}
[Serializable()]
public class values
{
[System.Xml.Serialization.XmlAttribute("ctrlname")]
public string ctrlname { get; set; }
//....
}
Second, your using the same name for the list and object
//list of class values
rootValues valusList = new rootValues();
foreach (Control control in Controls)
{
values value = new values(); // Create new element, in your code it was the same
value.ctrlname = control.Name.ToString();
value.ctrllocation = control.Location.ToString();
value.ctrltext = control.Text.ToString();
value.ctrltype = control.GetType().ToString();
value.ctrlstatus = control.Enabled.ToString();
valuesList.valuesList.Add(value);
}
System.Xml.Serialization.XmlSerializer writer = new System.Xml.Serialization.XmlSerializer(typeof(rootValues));
var path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "//Serialization.xml";
System.IO.FileStream file = System.IO.File.Create(path);
writer.Serialize(file, valusList);
file.Close();
FYI, if you want to add a list of class values you can do it like so:
//...
List<values> SomeListOfvalues = new List<values>();
// Init list
SomeListOfvalues.add(new values()); // Adding first element
SomeListOfvalues.add(new values()); // Adding second element
// Adding the whole list to our class
valuesList.valuesList.addRange(SomeListOfvalues );
write.Serialize is probably overwriting whats in the file each time rather then appending. You could try serializing the values to a string like in this question: Serialize an object to string. And then manually appending to the file with the string values.
Alternatively you could serialize the whole list rather then each value at a time.
Your first foreach loop that fills the list is repeatedly overwriting the same value object and adding new references to same object repeatedly to the List. You're not actually adding a new item to your list when you call valus.Add(value);.
Try moving the line values value = new values(); to the top of the foreach loop or, if you're particularly worried about efficiency of declaring an object multiple times, keep the line values value; outside the loop and add the line value = new values(); inside the foreach loop.
Working on an old application I see this code:, It is using DataTable, DataRow stuff.
foreach (string networkIdToCreate in networkIdsToCreate)
{
HTExtractSchema.HTProviderMedicalGroupContractRow rHTProviderMedicalGroupContract = tblHTProviderMedicalGroupContract.NewHTProviderMedicalGroupContractRow();
rHTProviderMedicalGroupContract.ItemArray = rHTProviderMedicalGroupContractDefaults.ItemArray;
rHTProviderMedicalGroupContract.NetworkId = networkIdToCreate;
rHTProviderMedicalGroupContract.Business = "470";
tblHTProviderMedicalGroupContract.Rows.Add(rHTProviderMedicalGroupContract);
}
So it creates the new row, puts some values in there and adds it to the DataTable.
Now I want to modify it to create two rows instead of one row, all values the same except for "Business" field, it is one line before the last in the code above.
So I did that like this:
foreach (string networkIdToCreate in networkIdsToCreate)
{
HTExtractSchema.HTProviderMedicalGroupContractRow rHTProviderMedicalGroupContract = tblHTProviderMedicalGroupContract.NewHTProviderMedicalGroupContractRow();
rHTProviderMedicalGroupContract.ItemArray = rHTProviderMedicalGroupContractDefaults.ItemArray;
rHTProviderMedicalGroupContract.NetworkId = networkIdToCreate;
rHTProviderMedicalGroupContract.Business = "470";
tblHTProviderMedicalGroupContract.Rows.Add(rHTProviderMedicalGroupContract);
HTExtractSchema.HTProviderMedicalGroupContractRow rHTProviderMedicalGroupContract2 = tblHTProviderMedicalGroupContract.NewHTProviderMedicalGroupContractRow();
rHTProviderMedicalGroupContract2.ItemArray = rHTProviderMedicalGroupContractDefaults.ItemArray;
rHTProviderMedicalGroupContract2.NetworkId = networkIdToCreate;
rHTProviderMedicalGroupContract2.Business = "475";
tblHTProviderMedicalGroupContract.Rows.Add(rHTProviderMedicalGroupContract2);
}
But I was wondering if there is a better way other than this copy paste? so if someone saw the code won't laugh at me :D
Just add this internal loop
foreach(var business in new[] {"470", "475"})
{
...
rHTProviderMedicalGroupContract.Business = business ;
...
}
EDIT
Or you can use a method
private void CreatRow(
string networkIdToCreate,
string business)
{
HTExtractSchema.HTProviderMedicalGroupContractRow rHTProviderMedicalGroupContract =
tblHTProviderMedicalGroupContract.NewHTProviderMedicalGroupContractRow();
rHTProviderMedicalGroupContract.ItemArray =
rHTProviderMedicalGroupContractDefaults.ItemArray;
rHTProviderMedicalGroupContract.NetworkId = networkIdToCreate;
rHTProviderMedicalGroupContract.Business = business;
tblHTProviderMedicalGroupContract.Rows.Add(rHTProviderMedicalGroupContract);
}
and use it like this
foreach (string networkIdToCreate in networkIdsToCreate)
{
CreatRow(networkIdToCreate, "470");
CreatRow(networkIdToCreate, "475");
if(networkIdToCreate == "2" || networkIdToCreate == "6")
{
CreateRow(networkIdToCreate, "474");
}
}
Note you may need to pass in tblHTProviderMedicalGroupContract depending on its scope,