Issue with list in C# -- MVC - c#

I have issue in the following code. Below is my model code
public class Comments
{
public string displayComments { get; set; }
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}")]
public DateTime? dTime { get; set; }
public int airPortId { get; set; }
}
public class LstComments
{
private List<Comments> _lstcomment = new List<Comments>();
public List<Comments> lstCommet
{
get
{
return _lstcomment;
}
set
{
_lstcomment = value;
}
}
}
and in mycontroller am getting data from EF and adding it to the properties in For loop. Code Below
Comments com = new Comments();
LstComments savedComments = new LstComments();
AirportEntities airPortEntity = new AirportEntities();
var userComments = from c in airPortEntity.AirportComments
select c;
//List<Comments> savedComments = new List<Comments>();
foreach (var item in userComments)
{
com.displayComments = item.Comments;
com.dTime = item.Time;
savedComments.lstCommet.Add(com);
}
My issue is my entire list is getting updated with same records(recently added data)
For eg. foreach 3rd timn updates both 1st and 2nd 3rd item in list with 3rd item data.
What i am doing wrong ?

You instantiate Comments outside of the loop. This means there are a bunch of references to the same comment object on the heap. You need to do
Comments com = new Comments(); inside of the foreach. This will create a separate instance on each iteration, instead of just giving the one instance new values.

you need to instantiate Comments com = new Comments(); each time in foreach. As for now you just rewrite reference to the same object.
Or which is better to rewrite foreach as:
foreach (var item in userComments)
{
savedComments.lstCommet.Add(
new Comments()
{
com.displayComments = item.Comments,
com.dTime = item.Time
});
}

Related

How to clone object with a different Primary Key

I have this class Cart_Record, shown below. I want to update the PrimaryKey. To do that I am trying to clone the object into a new object to copy CartLines and update ID. I haven't found much in the issue queue or the documentation to help me.
public class Cart_Record : RealmObject
{
public Cart_Record() { }
public Cart_Record(IList<Cart_Line> cartLines, int id)
{
ID = id;
foreach (var cartLine in cartLines)
CartLines.Add(App.RealmDB.Find<Cart_Line>(cartLine.ProductId));
}
[PrimaryKey]
public int ID { get; set; }
public IList<Cart_Line> CartLines { get; }
}
I am trying this
var appCart = App.RealmDB.All<Cart_Record>().First();
App.RealmDB.Write(() =>
{
var cartLines = new List<Cart_Line>(appCart.CartLines);
App.RealmDB.Remove(App.RealmDB.Find<Cart_Record>(appCart.ID));
App.RealmDB.Add<Cart_Record>(new Cart_Record(cartLines, serverCart.ID));
});
However I keep getting exceptions, specifically RealmObjectManagedByAnotherRealmException. I don't understand how as I am not readding the Cart_Line objects to Realm, just to the CartLine list in the new object.
What am I doing wrong?
Thanks ahead of time.
Edit: I found something that works but I would like to see if someone else have a better method. This is what works for me.
var appCart = App.RealmDB.All<Cart_Record>().First();
App.RealmDB.Write(() =>
{
var cartLines = new List<Cart_Line>(appCart.CartLines);
App.RealmDB.Remove(App.RealmDB.Find<Cart_Record>(appCart.ID));
var newAppCart = App.RealmDB.Add<Cart_Record>(new Cart_Record() { ID = serverCart.ID });
foreach (var cartLine in cartLines)
newAppCart.CartLines.Add(cartLine);
});
I'm not sure what App.RealmDB does under the hood, but using the out-of-the-box Realm API, what you want to achieve can be done by simply adding the CartLines from the original to the updated object:
// Assume want to change Id from 1 to 2
var realm = Realm.GetInstance();
var original = realm.Find<Cart_Record>(1);
var updated = new Cart_Record { ID = 2 }; // other properties must be copied here
foreach (var cart in original.CartLines)
{
updated.CartLines.Add(cart);
}
realm.Write(() =>
{
realm.Remove(original);
realm.Add(updated);
});
// updated now has all the original's CartLines

Why isn't my object being updated

I'm doing something wrong because after the loop executed myData still contains objects with blank ids. Why isn't the myData object being updated in the following foreach loop, and how do I fix it?
I thought it could be that I wasn't passing the object by reference, but added a ref keyword and also moved to the main method and I'm still showing the object not being updated.
Additional Information
The user object in the foreach loop is being updated, but the myData list does not reflect the updates I see being applied to the user object.
** Solution **
I was not creating a List but an Enumerable which was pulling the json each time I went through myData in a foreach list. Adding a ToList() fixed my issue.
public class MyData
{
public string ID { get; set; }
public Dictionary<string, string> Properties { get; set; }
}
int index = 0;
// Does not allow me to up, creates an IEnumerable
//IEnumerable<MyData> myData = JObject.Parse(json)["Users"]
// .Select(x => new MyData()
// {
// ID = x["id"].ToString(),
// Properties = x.OfType<JProperty>()
// .ToDictionary(y => y.Name, y => y.Value.ToString())
// });
//Works allows me to update the resulting list.
IEnumerable<MyData> myData = JObject.Parse(json)["Users"]
.Select(x => new MyData()
{
ID = x["id"].ToString(),
Properties = x.OfType<JProperty>()
.ToDictionary(y => y.Name, y => y.Value.ToString())
}).ToList();
foreach (var user in myData) // Also tried myData.ToList()
{
if (string.IsNullOrEmpty(user.ID))
{
user.ID = index.ToString();
user.Properties["id"] = index.ToString();
}
index++;
}
public class MyData
{
public MyData()
{
this.Properties = new Dictionary<string,string>();
}
public string ID { get; set; }
public Dictionary<string, string> Properties { get; set; }
}
public static void Main(string[] args)
{
IEnumerable<MyData> myDataList = new List<MyData>();
int index = 0; // Assuming your starting point is 0
foreach (var obj in myDataList)
{
if (obj != null && string.IsNullOrEmpty(obj.ID))
{
obj.ID = index.ToString();
// Checks if the Properties dictionary has the key "id"
if (obj.Properties.ContainsKey("id"))
{
// If it does, then update it
obj.Properties["id"] = obj.ID;
}
else
{
// Else add it to the dictionary
obj.Properties.Add("id", obj.ID);
}
}
index++;
}
I believe the reason why your objects are not updating because it's probably still referring to the memory block before your objects were changed. Perhaps. The easiest way (that I can think of, there are thousands of smarter programmers than me) is to create a new list and have it contain all of your updated objects.
Edit
I updated the code above with the code that I have. I created a method to set a small amount of objects to test:
private static IEnumerable<MyData> GetMyData()
{
return new List<MyData>()
{
new MyData(),
new MyData() {ID = "2"},
new MyData() {ID = "3"},
new MyData()
};
}
I was able to view my changes and then go through a foreach loop to view my changes. If the ID of the object is Null or Empty, then it steps into the if check and adds the current index to the ID as you know.
Now for my question: Which "id" is blank? The "id" in the dictionary or is it the ID of the model? Are all of your (Model).ID blank? As the updated code of yours, if your dictionary doesn't have "id" as a key, it's going to throw an exception saying it doesn't exist so you will need to do a check to make sure it does exist or add it if it doesn't.

how do I combine objects in order to display all at the same time as JSON?

In the code below, check the following line:
//here I need to put the object "nd" into a "bucket" so that I can finish the loop and then return EVERYTHING together.
My question is, how do I combine objects to return as JSON? The reason why I need to "combine" is because of the loop which assigns values to specific properties of this class. Once each class has been done getting property values, I need to return everything as JSON.
namespace X
{
public class NotificationsController : ApiController
{
public List<NotificationTreeNode> getNotifications(int id)
{
var bo = new HomeBO();
var list = bo.GetNotificationsForUser(id);
var notificationTreeNodes = (from GBLNotifications n in list
where n.NotificationCount != 0
select new NotificationTreeNode(n)).ToList();
foreach (var notificationTreeNode in notificationTreeNodes)
{
Node nd = new Node();
nd.notificationType = notificationTreeNode.NotificationNode.NotificationType;
var notificationList = bo.GetNotificationsForUser(id, notificationTreeNode.NotificationNode.NotificationTypeId).Cast<GBLNotifications>().ToList();
List<string> notificationDescriptions = new List<string>();
foreach (var item in notificationList)
{
notificationDescriptions.Add(item.NotificationDescription);
}
nd.notifications = notificationDescriptions;
//here I need to put the object "nd" into a "bucket" so that I can finish the loop and then return EVERYTHING together.
}
return bucket;
}
}
public class Node
{
public string notificationType
{
get;
set;
}
public List<string> notifications
{
get;
set;
}
}
}
You can simply add each item to a list as you're iterating through the source collection:
public List<Node> getNotifications(int id)
{
var bucket = new List<Node>(notificationTreeNodes.Count);
foreach (var notificationTreeNode in notificationTreeNodes)
{
Node nd = new Node();
...
bucket.Add(nd);
}
return bucket;
}

Adding an item to list string[]

I am trying to add a few rows I got from a DataTable to my list using this struct:
protected struct roleProperties
{
public string roleName { get; set; }
public string[] functionTitle { get; set; }
}
As you can see I want more strings inside the method Title string
I have been trying to do it like this:
public void getRoleFuncs(int roleId)
{
List<roleProperties> roles = new List<roleProperties>();
int i = 1;
SqlParameter ro_id = new SqlParameter("#ro_id", roleId);
string q = "SELECT ro_name, fu_title FROM roles INNER JOIN rolefunctions ON roles.ro_id = rolefunctions.fk_role_id INNER JOIN functions ON rolefunctions.fk_func_id = functions.fu_id WHERE ro_id = #ro_id";
SqlDataReader r = gm.returnReader(q, ro_id);
while (r.Read())
{
roleProperties item = new roleProperties();
item.roleName = r["ro_name"].ToString();
foreach (IDataRecord str in r)
{
item.functionTitle[i] = r["fu_title"].ToString();
i++;
}
roles.Add(item);
}
}
But I get a null reference on this line:
item.functionTitle[i] = r["fu_title"].ToString();
Can anyone see what I am doing wrong?
item.functionTitle is null because arrays are reference types and you have not initialized the property anywhere (so it has the default value: null for a reference type).
Even if that was not a problem (let's say functionTitle is an empty array) item.functionTitle[i] would again throw because it tries to access an index that is out of bounds. And finally, you have an off-by-one error: the first element in an array has the index 0, not 1.
You can fix all of the above by changing the code to
while (r.Read())
{
roleProperties item = new roleProperties();
item.roleName = r["ro_name"].ToString();
item.functionTitle = r.Select(o => o["fu_title"].ToString()).ToArray();
roles.Add(item);
}
Your array is not initialized and hence null since you do not know the size of the array you are going to need it seems a more suitable approach to use a list instead
change your struct to
protected class roleProperties
{
public string roleName { get; set; }
public IList<string> functionTitle { get; private set;}
public roleProperties(){
functionTitle = new List<string>();
}
}
and then change
item.functionTitle[i] = r["fu_title"].ToString();
to
item.functionTitle.Add(r["fu_title"].ToString());
I've changed the struct to a class because it's mutable and mutable structs are evil.
Initialize the array first.
item.functionTitle = new string[n]; // where n is an int

How to read the properties of an object inside an arraylist

I'm having some issues reading the properties of an item I have placed into an arraylist and I can't find the answer anywhere.
ArrayList itemsArrayList = new ArrayList();
itemsArrayList.Add(abyssalScepter);
itemsArrayList.Add(aegisOfTheLegion);
itemInBuildAbilityPower = itemsArrayList[0].abilityPower;
I need to be able to read the properties of the objects in the array so I can apply their values elsewhere but this gets me nowhere.
You need to cast object to the expected type (and hope it's really of this type).
itemInBuildAbilityPower = ((Item)itemsArrayList[0]).abilityPower;
The better option (if the infrastructure code is yours) to use generic container, e.g. List<T>.
List<Item> itemsArrayList = new List<Item>
itemsArrayList.Add(abyssalScepter);
itemsArrayList.Add(aegisOfTheLegion);
itemInBuildAbilityPower = itemsArrayList[0].abilityPower;
try
var itemInBuildAbilityPower = itemsArrayList[0].GetType().GetProperty ("abilityPower").GetGetMethod().Invoke (itemsArrayList[0], null);
Building on elder_george's answer, here is an example of what you could do if abyssalScepter and aegisOfTheLegion are not the exact same type:
using System.Collections.Generic;
class Power { }
interface IAbilityPower { Power abilityPower { get; set; } }
class Scepter : IAbilityPower { public Power abilityPower { get; set; } }
class Aegis : IAbilityPower { public Power abilityPower { get; set; } }
class Test
{
public static void Main()
{
var abyssalScepter = new Scepter();
var aegisOfTheLegion = new Aegis();
var itemsList = new List<IAbilityPower>();
itemsList.Add(abyssalScepter);
itemsList.Add(aegisOfTheLegion);
var power = itemsList[0].abilityPower;
}
}

Categories