I have a requirement to reflect on a object get all properties that are collections and
1)GetCount for each collection
2)GetTotalCount (allCollectionCount)
3)Call a method with this collection.
Below is what I have done so far with a made up noddy structure for semplicity.
I am stuck in how to call this method and how to get count for collection.
Any suggestions?
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
namespace ConsoleApplication2
{
class Program
{
static void Main()
{
var request = GetDataRequest();
//Get all properties
List<PropertyInfo> propInfoList =
new List<PropertyInfo>(request.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public));
//Get collections only
var myClassCollections=propInfoList.Where(xxx => xxx.PropertyType.GetInterfaces().Any(x => x == typeof (IEnumerable))).ToList();
var totalCountForAllCollections=????
foreach (var col in myClassCollections)
{
//How do I call my Method DoSomething
// DoSomething<?>(col.?????)
}
}
public void DoSomething<T>(List<T> objectCollection)
{
//etc...
}
private static DataRequest GetDataRequest()
{
DataRequest request = new DataRequest();
request.Addresses.Add(new Address
{
Id = 1,
City = "London",
Postcode = "32131",
Street = "London Road"
});
request.Addresses.Add(new Address
{
Id = 2,
City = "NewYork",
Postcode = "3432",
Street = "NewYork Road"
});
request.Customers.Add(new Customer
{
Id = 1,
Name = "Jo",
Surname = "Bloggs",
});
request.Customers.Add(new Customer
{
Id = 1,
Name = "Jon",
Surname = "Bloggs2",
});
request.Customers.Add(new Customer
{
Id = 1,
Name = "Jonny",
Surname = "Bloggs3",
});
return request;
}
}
public class DataRequest
{
public DataRequest()
{
Customers = new List<Customer>();
Orders = new List<Order>();
Addresses = new List<Address>();
}
public List<Customer> Customers { get; set; }
public List<Order> Orders { get; set; }
public List<Address> Addresses { get; set; }
}
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}
public class Order
{
public int Id { get; set; }
public string Name { get; set; }
public string OrderNo { get; set; }
}
public class Address
{
public int Id { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string Postcode { get; set; }
}
}
quick and dirty, here you go...
// ..
static class Program
{
static void Main()
{
var request = GetDataRequest();
//Get propertyValues for properties that are enumerable (i.e. lists,arrays etc)
var collectionProperties = request.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(propertInfo => propertInfo.PropertyType.GetInterfaces().Any(x => x == typeof(IEnumerable)))
.Select(p => p.GetValue(request, null))
.Cast<IEnumerable<object>>().ToList();
var totalCountForAllCollections = 0;
// iterate through the list of propertyValues
foreach (var collectionPropertyValue in collectionProperties)
{
totalCountForAllCollections += collectionPropertyValue.Count();
collectionPropertyValue.DoSomething();
}
System.Console.WriteLine("The total count for all collections is : {0}", totalCountForAllCollections);
System.Console.WriteLine("press any key to exit");
System.Console.ReadLine();
}
public static void DoSomething<T>(this IEnumerable<T> objectCollection)
{
//etc...
// N.B. you will have to use typeof(T) to implement logic specific to the type
// If the logic in this method is non-specific to the typeof(T) then Implement logic accordingly
System.Console.WriteLine("The type of the collection is: {0}", objectCollection.GetType());
System.Console.WriteLine("The count of items in this collection is:{0}", objectCollection.Count());
}
// ..
}
// ..
Related
I have got a method with a single parameter of string class that I need to use to access another class in my project.
The following will be what I want it to do. Note that this syntax gives errors.
public string getId(string name) {
string Id = name.GetId();
return Id;
}
Assuming that the user enters "Joe" as the name, one would go to the class Joe.cs, which looks like this.
public class Joe {
public string Id = 32;
public string GetId() {
return Id;
}
}
What I want to happen here is for the first method to be able to get the GetId method from Joe if Joe is entered as a parameter. How would I do this? Thank you all.
This might point you in a better direction
The idea is to have a class called User that holds user information (funnily enough)
This way you can have a list of users (not a class for each one), as such you can easily look up a user and mess with them as much as you want
public class User
{
public string UserName { get; set; }
public string FavoriteColor { get; set; }
}
public class Program
{
// A List to hold users
private static List<User> _users = new List<User>();
private static void Main(string[] args)
{
// lets add some people
_users.Add(new User() { UserName = "Bob",FavoriteColor = "Red" });
_users.Add(new User() { UserName = "Joe", FavoriteColor = "Green" });
_users.Add(new User() { UserName = "Fred", FavoriteColor = "Blue" });
// use a linq query to find someone
var user = _users.FirstOrDefault(x => x.UserName == "Bob");
// do they exist?
if (user != null)
{
// omg yay, gimme teh color!
Console.WriteLine(user.FavoriteColor);
}
}
}
Output
Red
You can take it a step further and ask the user to look up other users (what a time to be a alive!)
Console.WriteLine("Enter a user (case sensitive)");
var userName = Console.ReadLine();
var user = _users.FirstOrDefault(x => x.UserName == userName);
if (user != null)
{
Console.WriteLine(user.FavoriteColor);
}
else
{
Console.WriteLine("Game over, you failed");
}
Console.ReadLine();
You could build a Class that can contain the details you want to store, then build a Manager class that exposes public methods that can extract informations from the stored objects:
public class Friend : IComparable<Friend>
{
public Friend() { }
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int FriendshipLevel { get; set; }
int IComparable<Friend>.CompareTo(Friend other)
{
if (other.FriendshipLevel > this.FriendshipLevel) return -1;
else return (other.FriendshipLevel == this.FriendshipLevel) ? 0 : 1;
}
}
public class MyFriends : List<Friend>
{
public MyFriends() { }
public int? GetID(string FriendName)
{
return this.Where(f => f.FirstName == FriendName).FirstOrDefault()?.ID;
}
public Friend GetFriendByID(int FriendID)
{
return this.Where(f => f.ID == FriendID).FirstOrDefault();
}
}
Build a sample class:
MyFriends myFriends = new MyFriends()
{
new Friend() { ID = 32, FirstName = "Joe", LastName = "Doe", FriendshipLevel = 100},
new Friend() { ID = 21, FirstName = "Jim", LastName = "Bull", FriendshipLevel = 10},
new Friend() { ID = 10, FirstName = "Jack", LastName = "Smith", FriendshipLevel = 50},
};
Then you can extract informations on single/multiple objects using the public methods of the "Manager" class:
int? ID = myFriends.GetID("Joe");
if (ID.HasValue) // Friend Found
Console.WriteLine(ID);
//Search a friend by ID
Friend aFriend = myFriends.GetFriendByID(32);
if (aFriend != null)
Console.WriteLine($"{aFriend.FirstName} {aFriend.LastName}");
Or you can use LINQ to get/aggregate the required informations directly if there isn't a public method that fits:
// Get your best friends using LINQ directly
List<Friend> goodFriends = myFriends.Where(f => f.FriendshipLevel > 49).ToList();
goodFriends.ForEach((f) => Console.WriteLine($"{f.FirstName} {f.LastName}"));
//Best friend
Friend bestFriend = myFriends.Max();
With respect to your Question : GetId method from Joe if Joe is entered as a
parameter.
You can achieve that in the following ways also:
2. Method Using Named Method.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Problem
{
// Simple Model Class.
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
class Program
{
// Delegate.
public delegate string PersonHandler(Person person);
static void Main(string[] args)
{
List<Person> _persons = new List<Person>()
{
new Person(){Id=1,Name="Joe"},
new Person(){Id=2,Name="James"},
new Person(){Id=3,Name="Nick"},
new Person(){Id=4,Name="Mike"},
new Person(){Id=5,Name="John"},
};
PersonHandler _personHandler = new PersonHandler(GetIdOfPerson);
IEnumerable<string> _personIds = _persons.Select(p => _personHandler.Invoke(p));
foreach (var id in _personIds)
{
Console.WriteLine(string.Format("Id's : {0}", id));
}
}
// This is the GetId Method.
static string GetIdOfPerson(Person person)
{
string Id = person.Id.ToString();
return Id;
}
}
}
2. Method Using Anonymous Moethod.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Problem
{
// Simple Model Class.
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
class Program
{
// Delegate.
public delegate string PersonHandler(Person person);
static void Main(string[] args)
{
List<Person> _persons = new List<Person>()
{
new Person(){Id=1,Name="Joe"},
new Person(){Id=2,Name="James"},
new Person(){Id=3,Name="Nick"},
new Person(){Id=4,Name="Mike"},
new Person(){Id=5,Name="John"},
};
PersonHandler _personHandler = delegate(Person person)
{
string id = person.Id.ToString();
return id;
};
// Retrieving all person Id's.
IEnumerable<string> _personIds = _persons.Select(p => _personHandler.Invoke(p));
foreach (var id in _personIds)
{
Console.WriteLine(string.Format("Id's : {0}", id));
}
}
}
}
2. Method Using a Lambda Expression.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Problem
{
// Simple Model Class.
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
class Program
{
// Delegate.
public delegate string PersonHandler(Person person);
static void Main(string[] args)
{
List<Person> _persons = new List<Person>()
{
new Person(){Id=1,Name="Joe"},
new Person(){Id=2,Name="James"},
new Person(){Id=3,Name="Nick"},
new Person(){Id=4,Name="Mike"},
new Person(){Id=5,Name="John"},
};
PersonHandler _personHandler = (Person person) => person.Id.ToString();
IEnumerable<string> _personIds = _persons.Select(p => _personHandler.Invoke(p));
foreach (var id in _personIds)
{
Console.WriteLine(string.Format("Id's : {0}", id));
}
}
}
}
Output:
I'm trying to output a Paymentplan for a specific customer with a specific order.
I keep getting this error:
info:Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor[1]
Executing ObjectResult, writing value of type 'null'.
There is something I'm doing wrong but I'm not sure what it is. Looked for solutions for a long time with no luck. I'm new to programming and C# so still trying to get hang of this. Really appreciate your help and guidance.
Here is what I have so far:
Models:
using System.Collections.Generic;
namespace Project.Models
{
public class Customer
{
public string CustomerId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string DateOfBirth { get; set; }
}
public class Order
{
public string OrderId { get; set; }
public string Product { get; set; }
public string Status { get; set; }
public double Price { get; set; }
}
public class CustomerOrder
{
public string CustomerId {get; set;}
public string OrderId { get; set; }
}
public class Repayment
{
public int Amount { get; set; }
public string DueDate { get; set; }
public string RepaymentId { get; set; }
}
public class Choice
{
public string ChoiceId { get; set; }
public List<Repayment> Repayments{ get; set; }
}
public class RepaymentPlan
{
public List<Choice> Choices{ get; set; }
}
}
Repositories:
using System.Collections.Generic;
using System.Linq;
using Project.Models;
using System.Net;
using System.Collections.Specialized;
using System.Text;
namespace Project.Repositories
{
public class OrderRepository
{
private static List<Order> _Orders;
private static List<CustomerOrder> _CustomerOrder;
private static List<RepaymentPlan> _RepaymentPlan;
static OrderRepository()
{
_Orders = new List<Order>();
_CustomerOrder= new List<CustomerOrder>();
_PaymentPlan = new List<PaymentPlan>();
_Orders.Add(new Order
{
OrderId = "124",
Product= "Shirts",
Status= "On it's way",
Price= 100.20,
});
_Orders.Add(new Order
{
OrderId= "122",
Product= "Pants",
Status= "Not ready",
Price= 300.30,
});
_Orders.Add(new Order
{
OrderId= "143",
Product= "Deadpool",
Status= "On it's way",
Price= 6.20,
});
_Orders.Add(new Order
{
OrderId= "156",
Product= "Socks",
Status= "Not ready",
Price= 3.30,
});
_CustomerOrder.Add(new CustomerOrder
{
CustomerId = "578",
OrderId = "156",
});
_RepaymentPlan.Add(new RepaymentPlan
{
choices = new List<Choice>
{
new Choice
{
choiceId = "cho1",
Repayments = new List<Repayment>
{
new Repayment
{
amount = 200,
dueDate = "2018-06-01"
},
new Repayment
{
amount = 100,
dueDate = "2018-08-01",
}
}
},
new Choice
{
choiceId = "cho2",
repayments = new List<Repayment>
{
new Repayment
{
repaymentId = "Choice1",
amount = 300,
dueDate = "2018-10-01"
},
new Repayment
{
repaymentId = "Choice2",
amount = 150,
dueDate = "2018-11-01"
},
}
}
},
});
}
public static RepaymentPlan GetRepaymentPlan(string customerId, string orderId)
{
var customerlist =_CustomerOrder.FindAll(c => c.CustomerId==customerId);
var orderlist= _CustomerOrder.FindAll(c => c.orderId==orderId);
var pplist= new RepaymentPlan();
if (customerlist == orderlist)
{
return pplist;
}
return null;
}
Controllers:
OrderController.cs:
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Project.Models;
using Project.Repositories;
namespace Project.Controllers
{
public class OrderController : Controller
{
[HttpGet("customers/{customerid}/orders/{orderId}/paymentPlan")]
public RepaymentPlan FindRepaymentPlan(string customerId, string orderId)
{
return OrderRepository.GetRepaymentPlan(customerId, orderId);
}
}
}
OK, after a closer scan of your code, I see that the problem is in this method
public static RepaymentPlan GetRepaymentPlan(string customerId, string orderId)
You will always return null because your condition will always evaluate to false. This is available for any (probably) programming language.
if (customerlist == orderlist) evaluates if the two objects are identical (they reference the same memory address), it doesn't evaluate the content of the objects. To see if two object have the same data, you can use a loop (for, while). But since you used Linq, it is enough to use multiple conditions in FindAll function.
public static RepaymentPlan GetRepaymentPlan(string customerId, string orderId)
{
var customerlist =_CustomerOrder.FindAll(c => c.CustomerId==customerId && c.orderId==orderId);
var pplist= new RepaymentPlan();
if (customerlist.Any())
{
return pplist;
}
return null;
}
Also, you may want to return customerlist.First() instead of pplist. If you return an empty object of type RepaymentPlan, it might not help you.
I'm approaching to document database and I'm little bit confused how to map documents relationship, in a situation as follow
public class Person
{
public Person()
{
}
public int Id { get; set; }
public string Name { get;set;}
public string Surname { get; set; }
public DateTime? BirthDate { get; set; }
}
public class Car
{
public Car() { }
public int Id { get; set; }
public string Name { get; set; }
public int PersonId { get; set;}
}
A person has one or more cars for example in this way I can query the db as follow
public Car Get(int id)
{
Car car = null;
using (IDocumentSession session = store.OpenSession())
{
car = session.Include<Car, Person>(x => x.PersonId).Load<Car>(id);
bool isLoaded = session.Advanced.IsLoaded("people/" + car.PersonId); // true!
}
return car;
}
and it's everything ok, the client makes just one request, but if I have a person and I want to show all his cars how can I query the db to do just a request?
I think tha I must modify the model putting a List<int> Cars in Person for reference his cars.
Note that I don't want to embed Cars in the Person document because Cars can be referenced from others document.
Thanks.
You can do it like this:
using (IDocumentSession session = store.OpenSession())
{
var carsForOne = session.Query<Car>()
.Include(x=>x.PersonId)
.Where(x=>x.PersonId == "people/1")
.ToList();
var person = session.Load<Person>("people/1");
}
This make just a single db request.
You can index the Cars collection and load all the cars from the index.
The index would look like this:
public class CarIndex : AbstractIndexCreationTask<Car, CarView>
{
public CarIndex()
{
Map = cars => from car in cars
select new
{
car.Id,
car.Name,
car.PersonId,
};
}
}
The CarView class is identical to the Car class, but can be changed to better fit the indexing needs.
public class CarView
{
public int Id { get; set; }
public string Name { get; set; }
public int PersonId { get; set; }
}
You'll need to execute the index before being able to use it:
new CarIndex().Execute(store);
Loading the cars for a certain person would look like this:
using (IDocumentSession session = store.OpenSession())
{
session.Store(new Person { Id = 1, Name = "A", Surname = "A" });
session.Store(new Car { Id = 1, Name = "A", PersonId = 1 });
session.Store(new Car { Id = 2, Name = "B", PersonId = 1 });
session.Store(new Car { Id = 3, Name = "C", PersonId = 2 });
session.SaveChanges();
}
WaitForIndexing(store); // from RavenTestBase
using (IDocumentSession session = store.OpenSession())
{
var resultsForId1 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 1);
Assert.Equal(2, resultsForId1.Count());
var resultsForId2 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 2);
Assert.Equal(1, resultsForId2.Count());
}
If you want to load the person and their cars in a single database request, use lazy loading:
var resultsForId1 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 1).Lazily();
var person = session.Advanced.Lazily.Load<Person>(1);
var personValue = person.Value;
var resultsValue = resultsForId1.Value;
Complete test (needs xunit and RavenDB.Tests.Helpers nugets):
using Raven.Client;
using Raven.Client.Indexes;
using Raven.Tests.Helpers;
using System;
using System.Linq;
using Xunit;
namespace SO41547501Answer
{
public class SO41547501 : RavenTestBase
{
[Fact]
public void SO41547501Test()
{
using (var server = GetNewServer())
using (var store = NewRemoteDocumentStore(ravenDbServer: server))
{
new CarIndex().Execute(store);
using (IDocumentSession session = store.OpenSession())
{
session.Store(new Person { Id = 1, Name = "A", Surname = "A" });
session.Store(new Car { Id = 1, Name = "A", PersonId = 1 });
session.Store(new Car { Id = 2, Name = "B", PersonId = 1 });
session.Store(new Car { Id = 3, Name = "C", PersonId = 2 });
session.SaveChanges();
}
WaitForAllRequestsToComplete(server);
WaitForIndexing(store);
using (IDocumentSession session = store.OpenSession())
{
var resultsForId1 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 1);
Assert.Equal(2, resultsForId1.Count());
var resultsForId2 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 2);
Assert.Equal(1, resultsForId2.Count());
}
using (IDocumentSession session = store.OpenSession())
{
server.Server.ResetNumberOfRequests();
var resultsForId1 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 1).Lazily();
var person = session.Advanced.Lazily.Load<Person>(1);
var personValue = person.Value;
var resultsValue = resultsForId1.Value;
Assert.Equal("A", personValue.Name); // person data loaded
Assert.Equal("A", resultsValue.First().Name); // cars data loaded
Assert.Equal(1, server.Server.NumberOfRequests); // only one request sent to the server
}
}
}
}
public class CarIndex : AbstractIndexCreationTask<Car, CarView>
{
public CarIndex()
{
Map = cars => from car in cars
select new
{
car.Id,
car.Name,
car.PersonId,
};
}
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public DateTime? BirthDate { get; set; }
}
public class Car
{
public int Id { get; set; }
public string Name { get; set; }
public int PersonId { get; set; }
}
public class CarView
{
public int Id { get; set; }
public string Name { get; set; }
public int PersonId { get; set; }
}
}
I have the following model (comments define fields within given object)
public class ServiceModel
{
public List<ShippingRequest> ShippingRequest { get; set; }
public QuotesResult QuotesResult { get; set; }
}
public class ShippingRequest
{
public Address Address { get; private set; } // AddressId
public List<ShippingPackage> ShippingPackages { get; private set; }
}
public class ShippingPackage
{
public Package Package { get; private set; } // PackageId
public List<ShippingItem> ShippingItems { get; private set; } // IsSkipped
}
public class QuotesResult
{
public List<Quote> Quotes { get; set; } // PackageId, Cost
}
Suppose I have the following input, I need to get a list of AddressId's and corresponding Quotes that refer to that address (via PackageId). Quotes are already populated at this point.
Quote.PackageId = Package.PackageId
INPUT:
Suppose I have following input with three ShippingRequests
Address1 = {Package1, Package2, Package3}
Address2 = {Package5, Package8}
Address3 = {Package11, Package12}
To get the all the quotes for a given address I need to Join PackageId of "Package" with PackageId of Quote. That way I will know that this Quote belongs to this Address.
I've tried this but i get an error:
var addrQuotes = ServiceModel.ShippingRequest
.GroupJoin(ServiceModel.QuotesResult.Quotes, c1 => c1.ShippingPackages
.SelectMany(y => y.Package.Id), c2 => c2.PackageId, (c1, c2) =>
new {
c1.Address.Id,
Quotes = c2.Select(e =>
{
e.Price = c1.ShippingPackages.Any(
x => x.ShippingItems.All(y => y.IsSkipped))
? 0
: e.Price + ExtraCost;
e.Provider = GetName(e.Code);
return e;
})
}).OrderBy(q => q.Id);
One caviar to this is that I also need to check ShippingItems(s) that go in a Package. If ALL the ShippingItems within a ShippingPackage have boolean flag "IsSkipped" set to true, the Quote's Price should be set to 0, otherwise add Extra cost to Quote.Price.
OUTPUT:
Address1 = [Quote1, Quote20, Quote21, Quote50, ...]
Address2 = [Quote3, Quote100...]
Address3 = [Quote5, Quote33, Quote12]
Any help greatly appreciated.
I didn't do entire job but got something to compile and run without errors. This should get you pointed in right direction.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
ServiceModel serviceModel = new ServiceModel()
{
ShippingRequest = new List<ShippingRequest>(){
new ShippingRequest() {
Address = "Address 1",
ShippingPackages = new List<ShippingPackage>() {
new ShippingPackage() { Package = "Package1"},
new ShippingPackage() { Package = "Package2"},
new ShippingPackage() { Package = "Package3"}
}
},
new ShippingRequest() {
Address = "Address 2",
ShippingPackages = new List<ShippingPackage>() {
new ShippingPackage() { Package = "Package5"},
new ShippingPackage() { Package = "Package8"},
}
},
new ShippingRequest() {
Address = "Address 3",
ShippingPackages = new List<ShippingPackage>() {
new ShippingPackage() { Package = "Package11"},
new ShippingPackage() { Package = "Package12"},
}
}
},
QuotesResult = new QuotesResult()
{
Quotes = new List<Quote>() {
new Quote() { Cost = 123, Id = "Package1"},
new Quote() { Cost = 123, Id = "Package2"},
new Quote() { Cost = 123, Id = "Package3"},
new Quote() { Cost = 123, Id = "Package11"},
new Quote() { Cost = 123, Id = "Package11"}
}
}
};
var addrQuotes = (from requests in serviceModel.ShippingRequest.Select(x => x.ShippingPackages.Select(y => new { address = x.Address, package = y})).SelectMany(z => z)
join quote in serviceModel.QuotesResult.Quotes
on requests.package.Package equals quote.Id
select new { quote = quote, package = requests }).ToList();
var results = addrQuotes.GroupBy(m => m.package.address)
.Select(n => new {
quotes = n.Select(c => c).Select(c1 => new {
address = c1.package.address,
quote = c1.quote
}).ToList()
}).ToList();
}
}
public class ServiceModel
{
public List<ShippingRequest> ShippingRequest { get; set; }
public QuotesResult QuotesResult { get; set; }
}
public class ShippingRequest
{
public string Address { get; set; } // AddressId
public List<ShippingPackage> ShippingPackages { get; set; }
}
public class ShippingPackage
{
public string Package { get; set; } // PackageId
public List<string> ShippingItems { get; set; } // IsSkipped
}
public class QuotesResult
{
public List<Quote> Quotes { get; set; } // PackageId, Cost
}
public class Quote
{
public string Id { get; set; }
public decimal Cost { get; set; }
}
}
I have below scenario:
This is my class structure :
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public System.Collections.ObjectModel.Collection<Likes> Likes { get; set; }
}
public class Likes
{
public string Sport { get; set; }
public string Music { get; set; }
public string Food { get; set; }
public string Place { get; set; }
}
When I serialize object of User class then it will generate the below json string :
{"FirstName":"Naresh",
"LastName":"Parmar",
"Likes": [{"Sport":"Cricket",
"Music":"Classic",
"Food":"Gujarati",
"Place":"India"}]
}
I want to generate above json string like below:
{"FirstName":"Naresh",
"LastName":"Parmar",
"Sport":"Cricket",
"Music":"Classic",
"Food":"Gujarati",
"Place":"India"
}
I want the nested properties as primary one.
Any help would be appreciated.
Thanks in advance..
EDIT:
{"FirstName":"Naresh",
"LastName":"Parmar",
"Sport":"Cricket,Chess,Football",
"Music":"Classic",
"Food":"Gujarati",
"Place":"India"
}
It's really bad practice, since the code i'll post bellow doesn't have great maintainability, however if that's what you looking for, you can use this. Another class that have the format that you'd like, and have a method that adds a list of likes to the format you've required. That the class you should serialize to JSON:
class NestedUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Sport { get; set; }
public string Music { get; set; }
public string Food { get; set; }
public string Place { get; set; }
public void AddLikes(System.Collections.ObjectModel.Collection<Likes> likes)
{
foreach (Likes like in likes)
{
Sport += like.Sport + ",";
Music += like.Music + ",";
Food += like.Food + ",";
Place += like.Place + ",";
}
if (Sport != string.Empty)
{
Sport = Sport.Substring(0, Sport.Length - 1);
}
if (Music != string.Empty)
{
Music = Music.Substring(0, Music.Length - 1);
}
if (Food != string.Empty)
{
Food = Food.Substring(0, Food.Length - 1);
}
if (Place != string.Empty)
{
Place = Place.Substring(0, Place.Length - 1);
}
}
}
Since it's not only limited to Likes objects I'd suggest using dynamic objects. So the User class I propose is as follows:
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public dynamic Details { get; set; }
public User()
{
Details = new ExpandoObject();
}
public void AddSingleDetail(string key, string value)
{
var dict = this.Details as IDictionary<string, Object>;
if (dict.ContainsKey(key))
{
dict[key] += "," + value;
}
else
{
dict[key] = value;
}
}
public void AddDetails(object detailsObject)
{
var type = detailsObject.GetType();
foreach (var prop in type.GetProperties())
{
AddSingleDetail(prop.Name, prop.GetValue(detailsObject).ToString());
}
}
}
You can use it for adding single proerpties or adding an object as a whole. I used reflection to get all the property name and values and add them to the user details.
Sample usage:
static void Main(string[] args)
{
var user1 = new User() { FirstName = "Homer", LastName = "Simpson" };
user1.AddSingleDetail("Sport", "Bowling");
user1.AddSingleDetail("Sport", "Sleeping");
user1.AddSingleDetail("Food", "Donut");
user1.AddSingleDetail("Music", "Rock");
string flattenedHomer1 = ConvertUserToFlattenedJson(user1);
var user2 = new User() { FirstName = "Homer", LastName = "Simpson" };
var likes1 = new Likes() { Food = "Donut", Music = "Rock", Place = "Springfield", Sport = "Bowling" };
var likes2 = new Likes() { Food = "Steaks", Music = "Metal", Place = "Evergreen Terrace", Sport = "Sleeping" };
var proStuff = new ProfessionalStuff() { Title = "Boss" };
user2.AddDetails(likes1);
user2.AddDetails(likes2);
user2.AddDetails(proStuff);
string flattenedHomer2 = ConvertUserToFlattenedJson(user2);
}
And the method performing the JSON conversion is:
public static string ConvertUserToFlattenedJson(User u)
{
dynamic flatUser = new ExpandoObject();
flatUser.FirstName = u.FirstName;
flatUser.LastName = u.LastName;
var dict = u.Details as IDictionary<string, Object>;
foreach (var like in dict)
{
((IDictionary<string, Object>)flatUser)[like.Key] = like.Value;
}
string json = Newtonsoft.Json.JsonConvert.SerializeObject(flatUser);
return json;
}
In my sample above user2 is converted to the following JSON string which I believe is what you are looking for:
{
"FirstName": "Homer",
"LastName": "Simpson",
"Sport": "Bowling,Sleeping",
"Music": "Rock,Metal",
"Food": "Donut,Steaks",
"Place": "Springfield,Evergreen Terrace",
"Title": "Boss"
}
While concatenating strings you can check for null or duplicate values. I didn't handle that part.
For the sake of completeness, here's the ProfessionalStuff class I made up:
public class ProfessionalStuff
{
public string Title { get; set; }
}
Hope this helps.