changing data of class list - c#

I try to add new record to my list and change data of it, but it's change all record of array, here is my class and code:
The class:
public class TransportDto
{
public int type { get; set; }
public string url { get; set; }
public int Relationship { get; set; }
}
loading data to my list:
IQueryable<TransportDto> list = _entities.Database.SqlQuery<TransportDto>(filterExpression).AsQueryable();
List<TransportDto> lst = list.ToList();
TransportDto help =lst[1];// adding record like one of my result
lst.Add(help);
Now I try to change value of lst[lst.Count-1] but when I change it , lst[1] change too
lst[lst.Count-1].type=3;
on result both lst[lst.Count-1] and lst[1] changes to 3, but I just try to change one record of array

When you write TransportDto help =lst[1];, you are getting the object at the index of 1. When you add this object to the list, you are adding the same object to the list not a copy of it.
Which means in the list, the indices of 1 and lst.Count-1 point to the same object. When you access the object as lst[lst.Count-1] you are accessing this object and .type=3 makes changes to the object the two indices are pointing to.
If you want a copy of the object in lst[1], consider cloning the object. This could make a copy of the object. You can refer here: How to Clone Objects
To simplify, in your case you can create a clone function like this:
public class TransportDto
{
public int type { get; set; }
public string url { get; set; }
public int Relationship { get; set; }
public TransportDto Clone(){
return new TransportDto{
type = type,
url = url,
Relationship = Relationship
};
}
}
This clone function creates a new object of TransportDto and passes the same values thus creating a copy. Now in your list you can do this:
TransportDto help =lst[1].Clone();
Now help stores a copy of lst[1].

Related

LINQ navigation property multiple sources

I have a database which stores different locations. Based on the type of the location, the unique details are stored in a different table than the common properties (i.e. Name, Coordinates, Description are stored in the Locations table, while Population is stored in the CityDetails table).
The tables are connected via FK in the "specific details" table.
Since there are more than one "specific details" table I'm scratching my head how to query those multiple tables.
My Location object looks like this:
[Table("Locations")]
public class LocationData
{
public Guid Id { get; set; }
// multiple different properties here.
public string Type { get; set; }
public DetailsData { get; set; }
}
based on the Type property I can see which details table I have to query. A details table looks at least like this:
public abstract class DetailsData
{
[Key, ForeignKey("Location")]
public Guid { get; set; }
public LocationData Location { get; set; }
}
Every table that represents a location type then inherits from the DetailsData class and is configured to use the "Table-per-concrete-class" inheritance hierarchy.
Here is an example of what a "specific details" table might look like:
[Table("CityDetails")]
public class CityDetailsData : DetailsData
{
public string Planet { get; set; }
public int Population { get; set; }
}
How can I populate the DetailsData property in the Location class. Here is my current LINQ query:
from l in Locations
select new
{
Id = l.Id,
Name = l.Name,
Description = l.Description,
Coordinates = l.Coordinates,
Type = l.Type,
DetailsData = CityDetails // Here lies the problem. How can I populate this property properly?
}
Okay, I'm working on the assumption that your details tables all have different sets of columns, that you want to be able to use IEnumerable<LocationData> instances, and that you want to be able to directly access the properties of the instances of whatever details table object you return.
That's a toughie. There are basically three ways you can write code for an object of unknown type:
Give it a type of Object.
Make all "details" tables inherit from a common interface, and make CityDetails an object that implements that interface.
Use a generic type, which means you do ultimately specify the type, but you can push that decision up the chain to a declarer of your implemented type.
Using System.Object means that you either need to cast all your DetailsData objects to the required type (or use Reflection to access their properties), whereas using an interface means you can access some properties directly, but probably not everything you want.
I think a generic type might be your best, hybrid, solution.
I would do something like this:
Accept that there isn't a perfect solution.
Instead of creating an anonymous type, as you are doing in your example code, define a class like this (akin to a ViewModel, if you're using ASP.NET MVC):
public class LocationViewModel<TDetailsData>
{
public Guid Id { get; set; }
// multiple different properties here.
public string Type { get; set; }
public TDetailsData DetailsData { get; set; }
}
Define a helper method that takes a type parameter and returns a value of type TDetailsData. Use that to populate your DetailsData property on LocationViewModel.
TDetailsData GetLocationDetails<TDetailsData>(string type, Guid ID)
{
// get the appropriate data based on the type.
}
If you need to keep an IEnumerable of these objects, define an interface ILocationDataViewModel and another of ILocationDataViewModel<TDetailsData>, make LocationViewModel implement both of them, and use IEnumerable<ILocationDataViewModel> or IEnumerable<ILocationDataViewModel<CityDetailsData>>, etc., as called for by the situation.
If I understood correctly, you would like to dynamically determine the type and deal with it on the fly. In that case, you can go with dynamic. I have not tested this code, but you can think in that line
public DetailsData GetDetailsData(Type t)
{
dynamic typVal = new ExpandoObject();
if(t == typeof(CityDetails))
{
typVal = new CityDetails();
}
// add other types
return (DetailsData)PopulateDetailsData(typVal);
}
public DetailsData PopulateDetailsData(CityDetails cd)
{
cd.Planet = new CityDetails().Planet;
return cd;
}
// Add other type related methods with same
// signature with input parameter differentiated by types
// for example
public DetailsData PopulateDetailsData(TownDetails td)
{
td.Income = new TownDetails().Income;
return td;
}
in query, you can have something like below
from l in Locations
select new
{
Id = l.Id,
Name = l.Name,
Description = l.Description,
Coordinates = l.Coordinates,
Type = l.Type,
DetailsData = GetDetailsData(l.Type)
}

Populate List with Json file

I have a List of Items. Item is an object with multiple constructors, thus an item can be created in several forms.
Example of class Item with two constructors.
public class Item
{
public string name = "";
public int age= 0;
public int anotherNumber = 0;
public Item(string iName, int iAge)
{
name = iName;
age= iAge;
}
public Item(string iName, int iAge, int iAnotherNumber)
{
name = iName;
age= iAge;
}
}
I have then a Json file in the form of:-
[{"name":"Joseph","age":25},{"name":"Peter","age":50}]
I'm using the below method to read file and populate list using Newtonsoft.Json API.
public List<Item> ReadJsonString()
{
List<Item> data = new List<Item>();
string json = File.ReadAllText("\\path");
data = JsonConvert.DeserializeObject<List<Item>>(json);
return data;
}
If I have only one constuctor in the Item class (example the constructor that takes 2 arguments) this method works fine and I am able to populate the list. However when I add the second constructor in class Items(since I want to be able also to read Json files with the third attribute..
Example:-
[{"name":"Joseph","age":25, "anotherNumber": 12},{"name":"Peter","age":50, "anotherNumber": 12}]
The ReadJsonObj method fails with error "Unable to find a constructor to use for type Item". I can fix this issue by creating multiple class Item (e.g. ItemA, ItemB),one that takes three variables and the other that takes two variables. However I would like to have only one Item class.
I cannot find out why this is happening and how to fix such an issue.
You can use properties instead of regular fields and constructor initialization.
public class Item
{
public string name {get;set;}
public int age {get;set;}
public int anotherNumber {get;set;}
}
Thus you will cover both deserialization cases.

How to solve "Expected element name to be '_t', not 'number'."

I have a mongo model like this:
class ObjectA {
[BsonId(IdGenerator = typeof(BsonObjectIdGenerator))]
public BsonObjectId Id;
[BsonElement("number")]
public int Number { get; set; }
[BsonElement("b")]
public List<ObjectB> objectB { get; set; }
}
class ObjectB {
[BsonElement("someProperty")]
public string SomeProperty { get; set; }
}
My problem is when I aggregate the collection with {$unwind:objectB}. The result documencts have a unique object on the property objectB (not a list).
So the cast failes with the exception:
An error occurred while deserializing the ObjectB property of class
ObjectA: Expected element name to be '_t', not
'number'.
Do I have to create a new model for this or is there a easier way to solve it?
You could also choose to work with BsonDocument directly (but that is not strongly typed and more cumbersome to work with), e.g. (I'm using the simple Posts/Tags example here)
var aggregationResults = db.GetCollection("Posts").Aggregate().ResultDocuments;
foreach (var document in aggregationResults)
{
var tag = document.GetValue("Tags").AsString;
}
Unlike the normal query and projection operators, the aggregation framework may change the structure of your document. As you already pointed out, $unwind transforms a document that contains an array into a number of documents that each have a single value of the same name.
Another approach this is to indeed create a new type for this, so
class Post {
public List<string> Tags { get; set; }
...
would become
class PostAggregationResult {
public string Tags { get; set; }
...
That is very easy to work with, but if you have very various aggregation queries, you need a large number of classes which can be annoying.

How to add data items to a List<Struct>

I have the following struct defined in a user control:
public struct ColumnData
{
public string ColumnName { get; set; }
public string ColumnDataItem { get; set; }
public bool ColumnIsHyperLink { get; set; }
public string ColumnHyperLinkURL { get; set; }
public string ColumnHyperLinkPK { get; set; }
}
I create a new instance of List<ColumnData> (In a different code behind that creates an instance of the user control) and want to pass in values to it, but how do I assign them to specific attributes within the struct object?
I create an instance of the struct using the following code:
List<ColumnData> DataItems = new List<ColumnData>();
This:
List<ColumnData> DataItems = new List<ColumnData>();
creates a new list.
This:
List<ColumnData> DataItems = new List<ColumnData>();
var cd = new ColumnData();
cd.ColumnName = "Taco";
DataItems.Add(cd);
creates a new list, a new struct, and adds an item to the list.
Change that to a class; all your woes relating to modifying struct properties (etc) will go away.
Alternatively, make it an immutable struct, and initialize it with the correct values at the point of creation - then the issue is moot, no matter how many times it is subsequently copied.
IMO the first is the right approach here.
so you need to do this:
public void AddToList(ColumnData columnData)
{
DataItems.Add(columnData);
}
and call this method from your other class passing an already created and initialized columnData object.
List<ColumnData> DataItems = new List<ColumnData>();
Is creating the list that holds your structs not your structs itself.
You could use structs here for performance reasons (faster then classes).
ColumnData data = new ColumnData
{
ColumnName = "Blaa"
};
DataItems.Add(data);

Linq extracting objects

I have a JSON "multi-level" response that I need to deserialize and from the deserialized classes structure I need to extract all the objects of a certain class.
Below the code I'm using, at the end I find that my result is empty, not populated.
// given these two classes:
[DataContract]
public class ThingsList
{
[DataMember(Name = "status")]
public string Status { get; set; }
[DataMember(Name = "since")]
public double Since { get; set; }
[DataMember(Name = "list")]
public Dictionary<string, ThingsListItem> Items { get; set; }
public DateTime SinceDate { get { return UnixTime.ToDateTime(Since); } }
}
[DataContract]
public class ThingsListItem
{
[DataMember(Name = "url")]
public string Url { get; set; }
[DataMember(Name = "title")]
public string Title { get; set; }
}
// I can deserialize my json to this structure with:
ThingsList results = JsonConvert.DeserializeObject<ThingsList>(e.Result);
// now I need to "extract" only the ThingsListItem objects, and I'm trying this:
var theList = from item in results.Items.OfType<ThingsListItem>()
select new
{
Title = item.Title,
Url = item.Url
};
// but "theList" is not populated.
The points here are (I believe):
- I try to use results.Items.OfType() in order to extract only the ThingsListItem objects, that in the "upper" class are declared in the
public Dictionary Items { get; set; }
row.
Any idea? Tell if it's not clear...
Thanks
Andrea
EDIT: updated my response for clarity.
Since your Dictionary values are of type ThingsListItem you can access them directly by using the Dictionary's Values property. There is no need to use OfType to check their type and extract them. Simply use:
var items = results.Items.Values;
The Values property would return an ICollection<ThingsListItem>. You can then iterate over the results with a foreach. LINQ does not have to be used.
While the Values property described above should be sufficient, I will point out a few issues with your original LINQ query attempt.
1) The following query is probably what you were after. Again, the Dictionary's Values property is key (no pun intended) to accessing the items:
var theList = from item in results.Items.Values
select new
{
Title = item.Title,
Url = item.Url
};
2) Why are you using new? That will return an IEnumerable of anonymous types. You already have a defined class, so why project into a new anonymous type? You should retain the underlying ThingsListItem items by selecting the item directly to get an IEnumerable<ThingsListItem>:
var theList = from item in results.Items.Values
select item;
foreach (var item in theList)
{
Console.WriteLine("Title: {0}, Url: {1}", item.Title, item.Url);
}
You would usually project into a new anonymous type to define a type with data properties you are interested in. Generally you would use them immediately after the query, whereas a selection into an existing class could be used immediately or passed around to other methods that are expecting that type.
Hopefully this has cleared up some questions for you and you have a better idea of using LINQ and when to use the new keyword. To reiterate, for your purposes it seems the Values property should suffice. Using LINQ to select the item is redundant when there are other immediate means to do so.

Categories