I am trying to create a class for serializing and deserializing arrays. The class I have created, appears to be working for deserializing, but when I try to serialize the array, I am having issues. I am a fairly new C# developer and I am sure I have left an important piece out of my code, I just am not sure what.
Below is a copy of the class I created:
namespace PinnacleCartFormAPI
{
class clsGetCustomersResponse
{
public Customer Customer = new Customer();//{ get; set; }
}
public class Customer
{
public Int32 UserId;
public string UserName;
public CustBilling Billing = new CustBilling();
public AddressBook[] AddressBook;// AddressBook = new AddressBook();
}
public class CustBilling
{
public string FullName, FirstName, LastName, Email, Company, Phone;
public CustAddress Address = new CustAddress();
}
public class CustAddress
{
public string Name, Street1, Street2, City, State, Zip, Country;
}
public class AddressBook
{
public string Name, Street1, Street2, City, State, Zip, Country;
}
}
As you can see, the AddressBook class needs to be an Array. I believe my issue is related to the fact that I am not initiating the AddressBook class properly as an array.
Below, is a copy of the calling code that adds values to the different elements of the class:
clsGetCustomersResponse GetCustomersResp = new clsGetCustomersResponse();
GetCustomersResp.Customer.UserId = 123456;
GetCustomersResp.Customer.UserName = "Username";
GetCustomersResp.Customer.Billing.FullName = "Full Name";
GetCustomersResp.Customer.Billing.FirstName = "First Name";
GetCustomersResp.Customer.Billing.LastName = "Last Name";
GetCustomersResp.Customer.Billing.Email = "email#domain.com";
GetCustomersResp.Customer.Billing.Phone = "7778889999";
GetCustomersResp.Customer.Billing.Address.Name = "Address Name";
GetCustomersResp.Customer.Billing.Address.Street1 = "Address Street 1";
GetCustomersResp.Customer.Billing.Address.Street2 = "";
GetCustomersResp.Customer.Billing.Address.City = "Address City";
GetCustomersResp.Customer.Billing.Address.State = "Address State";
GetCustomersResp.Customer.Billing.Address.Zip = "Address Zip";
GetCustomersResp.Customer.Billing.Address.Country = "Address Country";
GetCustomersResp.Customer.AddressBook[0].Name = "Address Name";
GetCustomersResp.Customer.AddressBook[0].Street1 = "Address Street 1";
GetCustomersResp.Customer.AddressBook[0].Street2 = "";
GetCustomersResp.Customer.AddressBook[0].City = "Address City";
GetCustomersResp.Customer.AddressBook[0].State = "Address State";
GetCustomersResp.Customer.AddressBook[0].Zip = "Address Zip";
GetCustomersResp.Customer.AddressBook[0].Country = "Address Country";
As soon as I hit the bolded lines, I receive the following error:
"Object reference not set to an instance of an object"
Again, I believe this is a result of me not properly initializing the AddressBook portion of the code. However, I am not certain how to do that with the array.
Can you please provide me with some direction on this?
Thanks,
Zach
(Just to be clear, this doesn't really have anything to do with JSON.)
Yes, you have to initialize an array before you start putting values in it. Unfortunately arrays are of a fixed size - you can't change the size (e.g. by adding an element) after they've been created. I would suggest using a List<AddressBook> instead of an array. Then you can use:
// This initialization could be in the type itself
GetCustomersResp.Customer.AddressBook = new List<AddressBook>();
AddressBook address = new AddressBook();
address.Name = "Address Name";
address.Street1 = "Address Street 1";
// etc
GetCustomersResp.Customer.AddressBook.Add(address);
I'd also be tempted to rename the AddressBook type - it's just a single address, not a whole address book. The property within Customer could still be called AddressBook, as an address book is a collection of addresses.
Try this (for 10 address books):
GetCustomersResp.Customer.AddressBook = new AddressBook[10];
You need to instantiate your array before you try to assign elements in it
Agreed with Jon's answer - I didn't spend a ton of time on it, but maybe you'll find this refactored set of classes useful:
namespace Pinnacle.Cart.Customers
{
public class RetrieveResponse
{
public RetrieveResponse() { }
public RetrieveResponse(Customer customer) {
Customer = customer;
}
public Customer Customer { get; set; }
}
public class Customer
{
public Customer() {
Billing = new BillingInfo();
AddressBook = new List<AddressBookEntry>();
}
public Int UserId { get; set; }
public String UserName { get; set; }
public BillingInfo Billing { get; set; }
public List<AddressBookEntry> AddressBook { get; set; }
public class BillingInfo
{
public BillingInfo() { Address = new Address(); }
public String FullName { get; set; }
public String FirstName { get; set; }
public String LastName { get; set; }
public String Email { get; set; }
public String Company { get; set; }
public String Phone { get; set; }
public Address Address { get; set; }
}
}
public class Address
{
public String Street1 { get; set; }
public String Street2 { get; set; }
public String City { get; set; }
public String State { get; set; }
public String Zip { get; set; }
public String Country { get; set; }
}
public class AddressBookEntry : Address
{
public string Name { get; set; }
}
}
Related
I have a DBContext that is initializing through DropCreateDatabaseAlways class.
In the Seed method I have this code:
base.Seed(context);
var c1 = new Company { Name = "Samsung"};
var c2 = new Company { Name = "Microsoft"};
context.Companies.AddRange(new List<Company>{c1,c2 });
var phones = new List<Phone>
{
new Phone("Samsung Galaxy S5", 20000, c1),
new Phone("Nokia S1243", 200000, c1),
new Phone("Nokia 930", 10000, c2),
new Phone("Nokia 890", 8900, c2)
};
context.Phones.AddRange(phones);
context.SaveChanges();
And if iterate through phones now, I see that phone.Company is not null.
But when I do this in any other piece of code, phone.Company IS null.
What do I do wrong?
A simple piece of code with null phone.Company:
using (var db = new MyDataModel())
{
var phonesList = db.Phones.ToList();
foreach (var p in phones)
{
System.Console.WriteLine($"Name: {p.Name}
Company: {p.Company}"); // Company is null.
}
}
I can access Company using Join with Companies on phone.companyId, so Companies table exists in DB.
My DataModel class:
public class MyDataModel : DbContext
{
public MyDataModel()
: base("name=MyDataModel")
{
}
static MyDataModel()
{
Database.SetInitializer(new MyContextInializer());
}
public DbSet<Company> Companies { get; set; }
public DbSet<Phone> Phones { get; set; }
}
My Phone class:
namespace DataContext
{
public class Phone
{
public Phone()
{
}
public Phone(string name, int price, Company company)
{
Name = name;
Price = price;
Company = company;
}
public int Id { get; set; }
public string Name { get; set; }
public int Price { get; set; }
public int CompanyId { get; set; }
public Company Company { get; set; }
}
}
If you want to automagically load the companies when you load a phone, you need to add the virtual keyword before the Company property.
public class Phone {
public Phone() {
}
public Phone(string name, int price, Company company)
{
Name = name;
Price = price;
Company = company;
}
public int Id { get; set; }
public string Name { get; set; }
public int Price { get; set; }
public int CompanyId { get; set; }
public virtual Company Company { get; set; }
}
This tells entity framework to automatically load the linked company whenever you retrieve a phone from the database.
Alternatively you can use eager loading when performing a query on phones.
var phones = MyDataModel.Phones.Include(x => x.Company).ToList();
In addition to the cool answer from Immorality, I'll place here these links:
Virtual properties
MSDN - Loading related data strategies
I have a model that contain variables and a list of another class instance..
here models:
public class patient
{
[XmlElement("firstname")]
public string name { get; set; }
[XmlElement("lastname")]
public string surname { get; set; }
[XmlElement("age")]
public int age { get; set; }
[XmlElement("gender")]
public string gender { get; set; }
[XmlArray("exams"), XmlArrayItem(typeof(exam), ElementName = "exam")]
public List<exam> exam { get; set; }
}
public class exam
{
[XmlElement("id")]
public string id { get; set; }
[XmlElement(ElementName = "date", DataType = "DateTime")]
public DateTime date { get; set; }
[XmlElement("comment")]
public string comment { get; set; }
}
List<exam> examsLocal = new List<exam>(){
new exam{ id = "id of patient 1", date = DateTime.Now, comment = "coomment exam1" },
};
List<patient> overview = new List<patient>();
try
{
var b = new List<patient>()
{
new patient{ name = "name of patient 1", surname = "surname of patient 1", gender = "Female", age = 31, exam=examsLocal },
};
var writer = new System.Xml.Serialization.XmlSerializer(typeof(List<patient>));//throw exception
the line throws exceptions works fine if I delete 'exam=examsLocal' varible from List..
What is the correct way of serialize nested List items
Update your class definition of exam to be looks like:
remove the DataType of Date Property because the System.DateTime not allowed in Xml Serialization:
public class exam
{
[XmlElement("id")]
public string id { get; set; }
[XmlElement(ElementName = "date")]
public DateTime date { get; set; }
[XmlElement("comment")]
public string comment { get; set; }
}
And update the Property declaration in patiant class:
[XmlArray("exams"), XmlArrayItem(typeof(exam), ElementName = "exams")]
public List<exam> exams { get; set; }
Actually I have a query which returns result containing column(for ex.Address) of type varchar but the domain model for that table containing property of type object(for ex. Address Address).Because of which it trows error which says could not cast string to Comment.I cant figure out how to resolve this issue with dapper .net.
Code snippet:
IEnumerable<Account> resultList = conn.Query<Account>(#"
SELECT *
FROM Account
WHERE shopId = #ShopId",
new { ShopId = shopId });
The Account object is for example.
public class Account {
public int? Id {get;set;}
public string Name {get;set;}
public Address Address {get;set;}
public string Country {get;set;}
public int ShopId {get; set;}
}
As there is type mismatch between database table column(Address) and domain model property(Address) dapper throws exception.So is there is any way to map that properties though dapper..
Another option is to use Dapper's Multi-Mapping feature.
public class TheAccount
{
public int? Id { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
public string Country { get; set; }
public int ShopId { get; set; }
}
public class Address
{
public string Street { get; set; }
public string City { get; set; }
}
public class Class1
{
[Test]
public void MultiMappingTest()
{
var conn =
new SqlConnection(
#"Data Source=.\SQLEXPRESS; Integrated Security=true; Initial Catalog=MyDb");
conn.Open();
const string sql = "select Id = 1, Name = 'John Doe', Country = 'USA', ShopId = 99, " +
" Street = '123 Elm Street', City = 'Gotham'";
var result = conn.Query<TheAccount, Address, TheAccount>(sql,
(account, address) =>
{
account.Address = address;
return account;
}, splitOn: "Street").First();
Assert.That(result.Address.Street, Is.Not.Null);
Assert.That(result.Country, Is.Not.Null);
Assert.That(result.Name, Is.Not.Null);
}
}
The only issue I see with this is that you'll have to list all of the Account fields, followed by the Address fields in your select statement, to allow splitOn to work.
Since there is a type mismatch between your POCO and your database, you'll need to provide a mapping between the two.
public class Account {
public int? Id {get;set;}
public string Name {get;set;}
public string DBAddress {get;set;}
public Address Address
{
// Propbably optimize here to only create it once.
get { return new Address(this.DBAddress); }
}
public string Country {get;set;}
public int ShopId {get; set;}
}
Something like that - you match the db column to the property DBAddress (You need to provide an alias like SELECT Address as DBAddress instead of *) and provide a get method on your Address object which creates / reuses a type of Address with the contents of the db value.
in my Winform Application, I have Suppliers, Customers, Transport Companies. They are similar as they are basically some kind of Contacts, however they do different slightly in term of available fields.
For example Suppliers need have StartDate and EndDate fields. And currently even though Suppliers and Customers could have more than one contact person\entity, but we are not going do that in these release, but the Transport companies will have more than one contact person\entity and addresses. At the same time, the Supplier and Customer do require PO Address and Delivery Address, and two phone numbers just in case.
Currently in my Code First Entities, I have Suppliers, Customers and Transport Companies each contains a PrimaryContact which is a Contact Type, and for each Contact type, I have a ICollection of Address and Phone which in turn store one or more than one address and phone information. The difference is that Transport Companies will have a collection of Contact in addition of PrimaryContact.
As my understanding, even I have the freedom of design the DB/Entity by myself, there is not always the case that Objects in BLL is exactly mapping of the DB structure underneath.
So the idea is in my BLL layer, I will translate the data from Supplier to BOSupplier to Presentation Layer, and will doing translation to Supplier when get data back from Presentation Layer to DAL. Because in my Presentation Layer, the Supplier will looks like:
public class BOSupplier
{
// Primery key
public int ID { get; set; }
public string Name { get; set; }
public string TaxNumber { get; set; }
public bool InActive { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public string BankAccountNumber { get; set; }
public string BankAccountName { get; set; }
// Property related to Contact Table
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public string SkypeName { get; set; }
// Proterty related to Address Table
// PO address Info
public string POAddressLine { get; set; }
public string POCity { get; set; }
public string PORegion { get; set; }
public string POCountry { get; set; }
public string POPostCode { get; set; }
// Delivery AddressLine
public string DelAddressLine { get; set; }
public string DelCity { get; set; }
public string DelRegion { get; set; }
public string DelCountry { get; set; }
public string DelPostCode { get; set; }
// Proterties related to Phone table
public string PhoneNumber1 { get; set; }
public string PhoneNumber2 { get; set; }
}
}
But in my DAL Layer, my Supplier will looks like this:
public class Supplier
{
// Primery key
public int ID { get; set; }
public string Name { get; set; }
public virtual Contact PrimaryContact { get; set; }
public string TaxNumber { get; set; }
public bool InActive { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public string BankAccountNumber { get; set; }
public string BankAccountName { get; set; }
}
Then when I am actually writing code for BLL classes to manage my intermediate BOSupplier object and List which didn't actually mapping back an Entity to DB side. It seems a lots low level code just to transfer/map fields from two slightly different BOSupplier and Supplier, like this:
public static IEnumerable<BOSupplier> GetBOSuppliers()
{
var suppliers = dbContext.Suppliers;
BOSupplier currentSupplier;
foreach (Supplier supplier in suppliers)
{
currentSupplier = new BOSupplier()
{
ID = supplier.ID,
Name = supplier.Name,
Code = supplier.Code,
FirstName = supplier.PrimaryContact.FirstName,
TaxNumber = supplier.TaxNumber
};
// PO Address
Address poAddress = supplier.PrimaryContact.Addresses
.FirstOrDefault<Address>(a => a.AddressTypeValue == (int)AddressTypes.Postal);
if (poAddress != null)
{
currentSupplier.POAddressLine = poAddress.AddressLine1;
currentSupplier.POCity = poAddress.City;
currentSupplier.POCountry = poAddress.Country;
}
// Delivery Address
Address delAddress = supplier.PrimaryContact.Addresses
.FirstOrDefault<Address>(a => a.AddressTypeValue == (int)AddressTypes.Delivery);
if (delAddress != null)
{
currentSupplier.DelAddressLine = delAddress.AddressLine1;
currentSupplier.DelCity = delAddress.City;
currentSupplier.DelCountry = delAddress.Country;
}
// ToDo:
// There is probably more to think about how we want map multi phone numbers into limited two phone numbers
if (supplier.PrimaryContact.Phones.Count > 0)
{
foreach (Phone phone in supplier.PrimaryContact.Phones)
{
if (phone.PhoneType == PhoneTypes.Default)
{
currentSupplier.PhoneNumber1 = phone.PhoneNumber;
}
else
{
currentSupplier.PhoneNumber2 = phone.PhoneNumber;
}
}
}
this.boSupplierList.Add(currentSupplier);
}
return boSupplierList;
}
I am keep thinking: "Maybe my Entity Model should be simpler, or there is some better way of doing what I am trying to?". So please, from your experience, tell me that my Entity model are on over-complex side, or I just need some better way of mapping from BOSuppier to Supplier or some other thoughts.
Your entity model is not complex according to your description of the domain. You can use AutoMapper to map your Supplier to BOSupplier. Here is an example of flattening object graph using AutoMapper.
I see a problem in your GetBOSuppliers(). It uses lazy loading when you access PrimaryContact and Addresses. To avoid the multiple round trips to database you can eager load them as follows.
var suppliers = dbContext.Suppliers.Include(s => s.PrimaryContact.Addresses);
i have a lot of some WPF windows. On them i write some code, which binds UI controls and data, something like this:
public class AddressWindow
{
public string AddressID { get; set; }
public string Addr1 { get; set; }
public string Addr2 { get; set; }
public string ZIP { get; set; }
public string City { get; set; }
public string Mobile { get; set; }
public string FAX { get; set; }
public string Country { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public bool IsSystem { get; set; }
public bool Enabled { get; set; }
}
private void BindInCode()
{
var address = new AddressWindow
{
// AddressID = "110",
// Addr1 = "Kaunas",
// Addr2 = "Jonavos",
// ZIP = "8987",
// City = "miestas",
// Mobile = "869985868",
// FAX = "87998",
// Country = "Lithuania",
// Email = "emailas#ree.lt",
// Phone = "37598288",
// IsSystem = true,
// Enabled = false
};
Binding binding = new Binding();
binding.Source = address;
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.Path = new PropertyPath("AddressID");
this.db_AddressID.SetBinding(TextEdit.TextProperty, binding);
binding = new Binding();
binding.Source = address;
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.Path = new PropertyPath("Addr1");
this.db_Addr1.SetBinding(TextEdit.TextProperty, binding);
...............
}
Now I want to create some universal simple engine, to fill Data values(assign values from DataTable to my class properties). Does anyone knows some way how to do that..? In example is there some way to assign values by names of properties. Lets say my property names equals to names of Columns from dataRow. Is its possible in wpf to do something like that, or not, should i assign values in every window manually?
Personally I've recourse to code generation to do the job, but you can use to Jimmy Bogard's AutoMapper, which does pretty much what you're talking about. It is on CodePlex and GoogleCode.