So I'm creating a new tool in C# and I've created a class called 'Customer' and each 'Customer' has sub-group of employees which is an array of names. How do I set this property in my class for 'Customer'? What I have below for 'Employees' is not correct. I just left it there as a placeholder.
Thank you
public class Customer
{
public String Number { get; set; }
public String Name { get; set; }
public String Street { get; set; }
public String City { get; set; }
public String State { get; set; }
public String Zipcode { get; set; }
public string[] Employees = { get; set; }
}
You could use a List instead of an array as it is easier to manipulate:
public class Customer
{
public String Number { get; set; }
public String Name { get; set; }
public String Street { get; set; }
public String City { get; set; }
public String State { get; set; }
public String Zipcode { get; set; }
public List<string> Employees { get; set; }
}
And then when you instantiate it, you could add new employers as such:
Customer customer = new Cusomter();
customer.Number = "num1";
customer.Name = "ABC";
//...
List<string> lstEmp = new List<string>();
lstEmp.Add("NewEmployee1");
lstEmp.Add("NewEmployee2");
customer.Employees = lstEmp;
And read it like this:
foreach (string name in customer.Employees)
{
Console.WriteLine(name);
}
Simply use this declaration:
public string[] Employees { get; set; }
Related
let's say I have this :
public class University
{
public string Name { get; set; }
public Adress Adress { get; set; }
public Countings Countings { get; set; }
}
public class Adress
{
public string Street { get; set; }
public string City { get; set; }
public string Postalcode { get; set; }
}
public class Countings
{
public int studentCount { get; set; }
public int profCount { get; set; }
}
Now I want to have a new object of University with all properties with their default value:
var university = new University();
How can I make sure that the properties Adress and Countings are also constructed and not just null ?
Regards !
Set them with initializers. You can do this in the default constructor, but it's usually easiest to do it in the property's declaration:
public class University
{
public string Name { get; set; } = "";
public Adress Adress { get; set; } = new Adress();
public Countings Countings { get; set; } = new Countings();
}
public class Adress
{
public string Street { get; set; } = "";
public string City { get; set; } = ""
public string Postalcode { get; set; } = "";
}
Note that Value Types (like int already have a default that cannot be null), so unless the default value for studentCount or profCount is something other than 0, it's not necessary to initialize those properties. They will automatically default to zero.
This should work:
public class University
{
public string Name { get; set; }
public Adress Adress { get; set; } = new Adress();
public Countings Countings { get; set; } = new Countings();
}
You could also init them in a ctor:
public class University
{
public string Name { get; set; }
public Adress Adress { get; set; }
public Countings Countings { get; set; }
public University()
{
this.Adress = new Adress();
this.Countings = new Countings();
}
}
I'm trying to parse some JSON data and ultimatley store it in a database.
I'm having issues when storing a collection of strings / values which are not objects themselves.
For example - The "callingCodes" & "altSpellings"
I want to store these in an SQL table which will have reference to the country they belong to.
This is an example of the JSON:
{
"name":"Puerto Rico",
"topLevelDomain":[
".pr"
],
"alpha2Code":"PR",
"alpha3Code":"PRI",
"callingCodes":[
"1787",
"1939"
],
"capital":"San Juan",
"altSpellings":[
"PR",
"Commonwealth of Puerto Rico",
"Estado Libre Asociado de Puerto Rico"
],
"region":"Americas",
"subregion":"Caribbean",
"population":3474182,
"latlng":[
18.25,
-66.5
]
},
I originally created some C# classes to represent the data using http://json2csharp.com/
This sugguested I store the values as a list of strings, which I did:
public List<string> CallingCodes { get; set; }
I now want to store the data in a table, so I created a class "TopLevelDomain" to store / link the data to the parent country:
public class CallingCode
{
public int ID { get; set; }
public int CountryID { get; set; }
public string Code{ get; set; }
}
So I altered the parent to be as follows:
public ICollection<CallingCode> CallingCodes { get; set; }
Is it possible to direct the string values into the "Code" property of my new class?
Or am I trying to crowbar two pieces of logic into one?
Is the correct way to have models for the JSON, and manually restructure these into my new DB / Entity Framework Models?
This is the auto-generated class you get from such JSON. The tricky bit here is List of primitive types.
public class RootObject
{
public string name { get; set; }
public List<string> topLevelDomain { get; set; }
public string alpha2Code { get; set; }
public string alpha3Code { get; set; }
public List<string> callingCodes { get; set; }
public string capital { get; set; }
public List<string> altSpellings { get; set; }
public string region { get; set; }
public string subregion { get; set; }
public int population { get; set; }
public List<double> latlng { get; set; }
}
Certain databases like PostgreSQL supports array as primitive type. If you are using PostgreSQL then you can perhaps make those properties array of primitive type and store them on server as is.
For other databases which does not support array, you cannot store a list of primitive values into single column of database. The easiest way to deal with it is to introduce serialization and create single string which can be stored to server. So looking at above class, for public List<string> topLevelDomain property, you can rewrite it in following way,
[NotMapped]
public List<string> topLevelDomain
{
get => Deserialize(TopLevelDomainString);
set => TopLevelDomainString = Serialize(value);
}
public string TopLevelDomainString { get; set; }
With NotMapped attribute EF will not map topLevelDomain property. But TopLevelDomainString will be persisted to database and it will get values from topLevelDomain. As for Serialize/Deserialize methods, you can use any serialization method. You can use JsonSerializer directly (since you are already using JSON objects. Or you can just combine strings using , as delimiter and split string from server using it.
Starting with EF Core 2.1 version, you can use Value-Conversion feature directly to provide funcs to do conversion (essentially serialization code like above) to EF and EF will do it while reading/saving data from/to server. This will avoid you having to create additional CLR property.
Here is your auto-generated class:
public class RootObject
{
public string name { get; set; }
public List<string> topLevelDomain { get; set; }
public string alpha2Code { get; set; }
public string alpha3Code { get; set; }
public List<string> callingCodes { get; set; }
public string capital { get; set; }
public List<string> altSpellings { get; set; }
public string region { get; set; }
public string subregion { get; set; }
public int population { get; set; }
public List<double> latlng { get; set; }
}
Let's prepare another simple one:
public class MyRootObject
{
public MyRootObject(RootObject root)
{
Name = root.name;
List<CallingCode> callingCodesConverted = new List<CallingCode>();
foreach (string code in root.callingCodes)
{
CallingCode newCode = new CallingCode() { Code = code };
callingCodesConverted.Add(newCode);
}
CallingCodes = callingCodesConverted;
}
public string Name { get; set; }
public List<CallingCode> CallingCodes { get; set; }
}
Now you could first do encoding from json to class RootObject, and then create MyRootObject based on it:
string path = #"D:\test.txt";
var r = new StreamReader(path);
var myJson = r.ReadToEnd();
RootObject root = Json.Decode<RootObject>(myJson);
MyRootObject myroot = new MyRootObject(root);
Sure MyRootObject is only an example.
Is the correct way to have models for the JSON, and manually
restructure these into my new DB / Entity Framework Models?
Well some might use that in their code and some might do even worse than that. But, I personally like to use models/dtos for the things I could and know about the data.
am I trying to crowbar two pieces of logic into one?
Yes. But, it depends. Either strongly type/define objects and all or just Ser/Deser everytime.
Your data is known (no unkown properties or anything, so why serialize and deserialize it everytime?)
Solution 1 : if you use the JSON as is to create a DB Entry
Entites
public class Country //assuming this is country data
{
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("alpha2Code")]
public string Alpha2Code { get; set; }
[JsonProperty("alpha3Code")]
public string Alpha3Code { get; set; }
[JsonProperty("capital")]
public string Capital { get; set; }
[JsonProperty("region")]
public string Region { get; set; }
[JsonProperty("subregion")]
public string Subregion { get; set; }
[JsonProperty("population")]
public long Population { get; set; }
[JsonProperty("topLevelDomain")]
public virtual List<TopLevelDomain> TopLevelDomains { get; set; }
[JsonProperty("callingCodes")]
public virtual List<CallingCodes> CallingCodes { get; set; }
[JsonProperty("altSpellings")]
public virtual List<AltSpellings> AltSpellings { get; set; }
[JsonProperty("latlng")]
public virtual List<Coordinates> Coordinates { get; set; }
}
public class TopLevelDomain
{
public int Id { get; set; }
[ForeignKey("Country")]
public int CountryId {get; set; }
public virtual Country Country { get; set; }
public string DomainName { get; set; }
}
public class CallingCodes
{
public int Id { get; set; }
[ForeignKey("Country")]
public int CountryId {get; set; }
public virtual Country Country { get; set; }
public string Code { get; set;} // either store it as String
//OR
public long Code { get; set;}
}
public class AltSpellings
{
public int Id { get; set; }
[ForeignKey("Country")]
public int CountryId {get; set; }
public virtual Country Country { get; set; }
public string AltSpelling { get; set; }
}
public class Coordinates
{
public int Id { get; set; }
[ForeignKey("Country")]
public int CountryId {get; set; }
public virtual Country Country { get; set; }
public double Coordinates { get; set; } //again either as string or double, your wish. I would use double
}
Use it like so
//assuming using Newtonsoft
var myJson = ....assuming one Country;
var myJsonList = ...assuming List<Country>;
var country = JsonConvert.DeserializeObject<Country>(myJson);
var countries = JsonConvert.DeserializeObject<List<Country>>(myJson);
Solution 2 : First one can cause too many tables for a little data but First solution is a little more object based and typed, so Here is another one
Entity
public class Country //assuming this is country data
{
public int Id { get; set; }
public string Name { get; set; }
public string Alpha2Code { get; set; }
public string Alpha3Code { get; set; }
public string Capital { get; set; }
public string Region { get; set; }
public string Subregion { get; set; }
public long Population { get; set; }
public string TopLevelDomains { get; set; }
public string CallingCodes { get; set;}
public string AltSpellings { get; set; }
public double Longitude { get; set;}
public double Latitude { get; set; }
}
Model
public class CountryJson
{
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("alpha2Code")]
public string Alpha2Code { get; set; }
[JsonProperty("alpha3Code")]
public string Alpha3Code { get; set; }
[JsonProperty("capital")]
public string Capital { get; set; }
[JsonProperty("region")]
public string Region { get; set; }
[JsonProperty("subregion")]
public string Subregion { get; set; }
[JsonProperty("population")]
public long Population { get; set; }
[JsonProperty("topLevelDomain")]
public List<string> TopLevelDomains { get; set; }
[JsonProperty("callingCodes")]
public List<string> CallingCodes { get; set;}
[JsonProperty("altSpellings")]
public List<string> AltSpellings { get; set; }
[JsonProperty("latlng")]
public List<string> Latlng { get; set; }
}
Use it like so
//assuming using Newtonsoft
var myJson = ....assuming one Country;
var countryJson = JsonConvert.DeserializeObject<CountryJson>(myJson);
//Write a Mapper Or Manual Map like below
var countryEntity = new Country
{
Name = countryJson.Name,
...
TopLevelDomains = JsonConvert.Serialize(countryJson.TopLevelDomains),
CallingCodes = JsonConvert.Serialize(countryJson.CallingCodes),
...//same for all list (NOTE: YOU NEED TO DESERIALIZE IT WHEN YOU FETCH IT FROM DB
Longitude = countryJson.Latlng.ElementAt(0),//assuming 0 is longi, 1 is lat
Latitude = countryJson.Latlng.ElementAt(1)//you can do it like above as well as string if you want
}
I have this code:
public class TABLE01
{
public string FIELD1 { get; set; }
public string FIELD2 { get; set; }
}
...
// fieldlist:
List<string> fieldsTABLE01 = new List<string>();
fieldsTABLE01.Add("FIELD1");
fieldsTABLE01.Add("FIELD2");
//response type List:
lResponseLegacy.Clear();
lResponseLegacy = DataExtract(fieldsTABLE01);
List<ClassDefinitions.TABLE01> listDataTableTABLE01 = new List<ClassDefinitions.TABLE01>();
foreach (string linea in lResponseLegacy)
{
ClassDefinitions.TABLE01 tableTABLE01 = new ClassDefinitions.TABLE01();
tableTABLE01.table01FIELD1 = ClassPackSupport.GetStringBetween(linea, "<FIELD1>", "</FIELD1>");
tableTABLE01.table01FIELD2 = ClassPackSupport.GetStringBetween(linea, "<FIELD2>", "</FIELD2>");
listDataTableTABLE01.Add(tableTABLE01);
}
classRespuestaDataclassModelo.tableTABLE01 = listDataTableTABLE01;
Now, I need to use the same previous code for others tables like fieldsTABLE01 with their own fields. As well, the previous code must create a list from a dynamic definition of a class (ClassDefinitions.TABLE01) and loop through of their own fields on these class.
In other words, I need to use the same code (maybe on a method) for other classes:
public class TABLE02
{
public string FIELD3 { get; set; }
public string FIELD4 { get; set; }
public string FIELD9 { get; set; }
}
public class TABLE03
{
public string FIELD5 { get; set; }
public string FIELD6 { get; set; }
}
public class TABLE04
{
public string FIELD7 { get; set; }
public string FIELD8 { get; set; }
public string FIELD14 { get; set; }
public string FIELD15 { get; set; }
}
Please, do you give me some tip?
Thanks.
You can use reflection like so
//Get a classes properties, you can do this with many classes.
var yourClassProperties = typeof(YourClass).GetProperties();
//And down the line:
fieldsTABLE01 = fieldsTABLE01.Concat(yourClassProperties).ToList();
Followed the steps mentioned in Automapper wiki to configure nested mapping with complex objects. but not working :
public class Student
{
public int ID{get;set;}
public string Name { get; set; }
public string Standard { get; set; }
public List<string> Course { get; set; }
public int Age { get; set; }
public string FatherName { get; set; }
public string MotherName{ get; set; }
public char Gender { get; set; }
public DateTime DOB { get; set; }
public string BloodGroup { get; set; }
public int TestCondition { get; set; }
public Address Address { get; set; }
}
public class Address
{
public int ID { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Zip { get; set; }
}
DTO :
public class StudentDTO
{
public string Name { get; set; }
public string Standard { get; set; }
public char Gender { get; set; }
public DateTime DOB { get; set; }
public string BG { get; set; }
public int TestCondition { get; set; }
public AddressDTO AddressDTO { get; set; }
}
public class AddressDTO
{
public int ID { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Zip { get; set; }
}
Configuration :
public class AutoMapperProfileConfig : Profile
{
public AutoMapperProfileConfig()
{
CreateMap<Student, StudentDTO>().ForMember(dest => dest.DOB, opt=>opt.Ignore())
.ForMember(x=>x.BG,opt=>opt.MapFrom(y=>y.BloodGroup))/*.AfterMap((src, dest) => dest.Name = "After MAP")*/
.ForMember(x=>x.TestCondition, opt=>opt.Condition(src => (src.TestCondition >= 100))
);
CreateMap<Address, AddressDTO>();
Execution :
Student student = new Student();
Address add = new Address();
add.Line1 = "abcd";
student.Address = add;
var studentLite = Mapper.Map<StudentDTO>(student);
Although studentDTO is getting mapped properly the AddressDTO is null.
You're mapping Student.Address to StudentDTO.AddressDTO. As the name of your target property has changed, AutoMapper doesn't know what to do with it. If you changed your propertyname in StudentDTO from AddressDTO into Address, Automapper should be able pick it up and map it.
An alternative solution would of course be to instruct AutoMapper explicitly to map Student.Address to StudentDTO.AddressDTO.
I had a similar problem with a dictionary - now I'm trying to populate a viewmodel, to return a JSON object to a GET request.
My viewmodel is:
public class HotelInventoryta
{
public int api_version { get; set; }
public string lang { get; set; }
public List<Hotel_List_ta> hotels { get; set; }
}
public class Hotel_List_ta
{
public int ta_id { get; set; }
public string partner_id { get; set; }
public string name { get; set; }
public string street { get; set; }
public string city { get; set; }
public string postal_code { get; set; }
public string state { get; set; }
public string country { get; set; }
public double latitude { get; set; }
public double longitude { get; set; }
public string desc { get; set; }
public string url { get; set; }
public string email { get; set; }
public string phone { get; set; }
public string fax { get; set; }
}
My DataBase model is:
[Table("tblHotel")]
public class Hotelta
{
[Key()]
[Column("hotel_id")]
public long hotel_id { get; set; }
public string hotel_name { get; set; }
public string hotel_add1 { get; set; }
public string hotel_towncity { get; set; }
public string hotel_pc { get; set; }
public string hotel_country { get; set; }
public string hotel_pass { get; set; }
public string hotel_email { get; set; }
public string hotel_tel { get; set; }
public string hotel_fax { get; set; }
}
My controller code to populate the viewmodel is:
private HoteltaContext dbh = new HoteltaContext();
//
// GET: /ta/hotel_inventory
[HttpGet]
public HotelInventoryta hotel_inventory(int api_version, string lang)
{
{
HotelInventoryta hotelinventory = new HotelInventoryta();
hotelinventory.api_version = api_version;
hotelinventory.lang = lang;
// Get data from database
var h = dbh.Hotelta.Where(x => x.hotel_id != 0).ToList();
// loop through each result, and add it to the hotelinventory.hotels model
foreach (var ht in h)
{
// I get the exception on the next line
hotelinventory.hotels.Add(new Hotel_List_ta
{
ta_id = 0,
partner_id = ht.hotel_id.ToString(),
name = ht.hotel_name,
street = ht.hotel_add1,
city = ht.hotel_towncity,
postal_code = ht.hotel_pc,
country = ht.hotel_country,
url = "http://www.me.com",
email = ht.hotel_email,
phone = ht.hotel_tel,
fax = ht.hotel_fax
});
}
return hotelinventory;
}
}
The error is:
Object reference not set to an instance of an object
Firstly, can you help me resolve the error - and if possible, confirm if the way I am reading from the database and populating the viewmodel, is the best way to do it?
Thank you, Mark
This is because the hotels property is never initialized. You could do this in the constructor of HotelInventoryta:
public class HotelInventoryta
{
public HotelInventoryta()
{
hotels = new List<Hotel_List_ta>();
}
// ...
}
Now you initialzed the property with an empty collection, so you can add items to it, rather than hotels being null which causes your exception.