I have three lists which contains three same properties in each collection. I want to combine a result into one collection. Ex classes structure is as below
publ
There seems to be a number of questions here combined, I'll try to work through them:
With respect to generating a single structure from your API response, I would recommend using the Newtonsoft.Json libraries, available on NuGet Json.NET. They will allow you to deserialize the response from your API, into a single object, which given the sample you provided, should contain a collection of each of your models, Order
, PaymentDetail
, CouponUsageDetail
:
public class APIResponceContainer
{
[JsonProperty("Orders")]
public List<Order> Orders { get; set; }
[JsonProperty("PaymentDetails")]
public List<PaymentDetail> PaymentDetails { get; set; }
[JsonProperty("CouponUsageDetails")]
public List<CouponUsageDetail> CouponUsageDetails { get; set; }
public APIResponceContainer()
{
Orders = new List<Order>();
PaymentDetails = new List<PaymentDetail>();
CouponUsageDetails = new List<CouponUsageDetail>();
}
}
Be aware to add the required attributes to each of your models as so:
public class Order
{
[JsonProperty("ProductId")]
public int ProductId { get; set; }
[JsonProperty("CustomerId")]
public int CustomerId { get; set; }
[JsonProperty("OrderId")]
public int OrderId { get; set; }
}
Deserialization then happens from your JSON string, as such:
StringReader stringReader = new StringReader(myJSONString);
JsonSerializer js = JsonSerializer.Create();
APIResponceContainer APIResponce = (APIResponceContainer)js.Deserialize(stringReader, typeof(APIResponceContainer));
As discussed in the comments, your data is unfortunately in terrible need of normalization. However, what I have inferred is that you would like to produce a flat structure, maintaining the "Few other Properties" and "key properties", for a combination of Order
, PaymentDetail
and CouponUsageDetail
. You can use Linq
for this, importantly I would recommend you choose yourself a "Primary Key". In other words, one property that can independently tie all the others together. In the example below, I have choose OrderID
since it should be unique (?):
var flatSequence =
from order in APIResponce.Orders
join coupon in APIResponce.CouponUsageDetails on order.OrderId equals coupon.OrderId
join payment in APIResponce.PaymentDetails on order.OrderId equals payment.OrderId
select new
{
// Here extract all the properties you care about
OrderID = order.OrderId,
Customer = order.CustomerId,
Product = order.ProductId,
// All the "other Properties" ?
BankDetail = payment.PaymentOnlyProperty
};
Here I have extracted to var
, however if you know the final flat structure you would like, of course determine a class of your own to receive the result.
Please comment if there is any questions.
What are you describing sounds like two standard multi-key LINQ group joins. They are quite efficient (LINQ to Objects implementation uses prepared fast hash based lookups), so no further optimizations are needed:
var orderDetails = (
from o in data.Orders
join p in data.PaymentDetails
on new { o.ProductId, o.CustomerId, o.OrderId }
equals new { p.ProductId, p.CustomerId, p.OrderId }
into orderPaymentDetails
join c in data.CouponUsageDetails
on new { o.ProductId, o.CustomerId, o.OrderId }
equals new { c.ProductId, c.CustomerId, c.OrderId }
into orderCouponUsageDetails
select new OrderDetails
{
ProductId = o.ProductId,
CustomerId = o.CustomerId,
OrderId = o.OrderId,
// Few other Properties of OrderDetail
PaymentDetail = orderPaymentDetails.ToList(),
CouponUsageDetail = orderCouponUsageDetails.ToList(),
})
.ToList();
You can use inheritance.
public class ResultCollection : Collection1
{
List<Collection2> Collection2s { get; set; }
List<Collection3> Collection3s { get; set; }
}
and then
var result = new ResultCollection {
PropId1 = Collection1.PropId1,
PropId2 = Collection1.PropId2,
...
Collection2s = Collection2,
Collection3s = Collection3
}
An automapper can be helpful here.
https://docs.automapper.org/en/stable/
I have solution, but i am not sure if it's ok for you. It depends on data format that you have on the begining.
solution:
class Program
{
static void Main(string[] args)
{
var collection1 = new Collection1() { PropId1 = 1, PropId2 = 2, PropId3 = 3 };
var list2 = new List<Collection2>()
{
new Collection2
{
PropId1 = 11,
PropId2 = 22,
PropId3 = 33
},
new Collection2
{
PropId1 = 22,
PropId2 = 33,
PropId3 = 44
}
};
var list3 = new List<Collection3>()
{
new Collection3
{
PropId1 = 111,
PropId2 = 222,
PropId3 = 333
},
new Collection3
{
PropId1 = 222,
PropId2 = 333,
PropId3 = 444
}
};
var result = new ResultCollection(collection1, list2, list3);
//or
var result2 = new ResultCollection(collection1) //but in this case you have to change your constructor
{
Collection2s = list2,
Collection3s = list3
};
Console.ReadLine();
}
}
public class Collection1
{
public int? PropId1 { get; set; }
public int? PropId2 { get; set; }
public int? PropId3 { get; set; }
}
public class Collection2
{
public int? PropId1 { get; set; }
public int? PropId2 { get; set; }
public int? PropId3 { get; set; }
}
public class Collection3
{
public int? PropId1 { get; set; }
public int? PropId2 { get; set; }
public int? PropId3 { get; set; }
}
public class ResultCollection : Collection1
{
public ResultCollection() { }
public ResultCollection(Collection1 collection, List<Collection2> list2, List<Collection3> list3)
{
foreach (PropertyInfo prop in collection.GetType().GetProperties())
{
PropertyInfo prop2 = collection.GetType().GetProperty(prop.Name);
if (prop2.CanWrite)
prop2.SetValue(this, prop.GetValue(collection, null), null);
}
Collection2s = list2;
Collection3s = list3;
}
public List<Collection2> Collection2s { get; set; }
public List<Collection3> Collection3s { get; set; }
}
But can you give an example of input data?