Nested Collection Mapping in Automapper - c#

Am trying to map nested collections using automapper and I have done the basic setup and configuration. When I try to do the map it the nested values are coming as null. I have tried to follow few posts and put together something. I want the list to have a hierarchy instead of flattening. Any help around this would be great.
Source Entities:
public class OuterEntity
{
public int ID { get; set; }
public string Name { get; set; }
public List<InnerEntity> InnerEntityList { get; set; }
}
public class InnerEntity
{
public int InnerId { get; set; }
public string InnerName { get; set; }
public List<InnerMostEntity> InnerMostList { get; set; }
}
public class InnerMostEntity
{
public int InnerMostId { get; set; }
public string InnerMostName { get; set; }
public DateTime ModifiedDate { get; set; }
}
Destination Entities:
public class OuterEntityDTO
{
public int ID { get; set; }
public string Name { get; set; }
public List<InnerEntity> InnerEntityList { get; set; }
}
public class InnerEntityDTO
{
public int InnerId { get; set; }
public string InnerName { get; set; }
public List<InnerMostEntity> InnerMostList { get; set; }
}
public class InnerMostEntityDTO
{
public int InnerMostId { get; set; }
public string InnerMostName { get; set; }
public DateTime ModifiedDate { get; set; }
}
Controller Class:
public List<OuterEntityDTO> GetAll()
{
var outerEntityList = myRepo.GetAll(); //Type of List<OuterEntity>
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<OuterEntity, OuterEntityDTO>().ReverseMap();
cfg.CreateMap<InnerEntity, InnerEntityDTO>().ReverseMap();
cfg.CreateMap<InnerMostEntity, InnerMostEntityDTO>().ReveseMap();
});
config.AssertConfigurationIsValid();
var innerMostDTO = Mapper.Map<List<OuterEntity>,List<OuterEntityDTO>>(outerEntityList);
//The inner list at first level itself is null.
return innerMostDTO;
}
Am trying to achieve this in DOT NET Core. Autommaper version is 6.1.1

I think you should have a wrong class hierarchy in DTO classes, as you have
public List<InnerMostEntity> InnerMostList { get; set; }
in public class InnerEntityDTO, you should write it as
public List<InnerMostEntityDTO> InnerMostList { get; set; }

Related

DynamoDB how to use ScanAsync on a nested structure?

Anyone have any idea / example how can I get the list of DynamoDbRepo with all nested structure if in DynamoDbMethodParameter.Name == specific value?
I suppose I should use ScanAsync but with what setting( ScanRequest ) ?
[DynamoDBTable("REPO_TABLE")]
public class DynamoDbRepo
{
[DynamoDBProperty("Id")]
[DynamoDBHashKey]
public int Id { get; set; }
[DynamoDBProperty("Solutions")]
public List<DynamoDbSolution> Solutions { get; set; }
}
public class DynamoDbSolution
{
[DynamoDBProperty("Path")]
public string Path { get; set; }
[DynamoDBProperty("Methods")]
public List<DynamoDbMethod> Methods { get; set; }
}
public class DynamoDbMethod
{
[DynamoDBProperty("Name")]
public string Name { get; set; }
[DynamoDBProperty("MethodParameters")]
public List<DynamoDbMethodParameter> MethodParameters { get; set; }
}
public class DynamoDbMethodParameter
{
[DynamoDBProperty("Type")]
public string Type { get; set; }
[DynamoDBProperty("Name")]
public string Name { get; set; }
}

Querying Repository with inheritance

I am using code first approach with Entity Framework 6. Three of my model classes implements inheritance and each of these model has collection which also implement inheritance. I am using TPH inheritance strategy. Everything works fine and I can insert/update with no problem at all. However, I get when I try to read data from the repo. The I get is shown below.
I have include my models, entity configuration and the line that throws this exception:
The include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the select operator for collection navigation properties
Code:
public abstract class OrderSup
{
public OrderSup()
{
DetailOrderSups = new HashSet<DetailOrderSup>();
}
public int Id { get; set; }
public string Description { get; set; }
public decimal AmountPaid { get; set; }
public DateTime DateEntered { get; set; }
public string CusSupCode { get; set; }
public decimal NetAmount { get; set; }
public decimal TaxAmount { get; set; }
public string DespatchSatus { get; set; }
public string Reference { get; set; }
}
public abstract class DetailOrderSup
{
[Key, Column(Order = 0)]
public virtual int OrderId { get; set; }
[Key, Column(Order = 1)]
public virtual int ProductId { get; set; }
public virtual Product OrderedProducts { get; set; }
public InvoiceType InvoiceType { get; set; }
public virtual OrderSup OrderSup { get; set; }
}
public class Order : OrderSup
{
public int SalesOrderNumber { get; set; }
public InvoiceType InvoiceType { get; set; }
}
public class PurchaseOrder : OrderSup
{
public string OrderStatus { get; set; }
//public string AlocationStatus { get; set; }
public int InvoiceNumber { get; set; }
}
public class PurchaseOrderDetails : DetailOrderSup
{
public bool IsOrderPaid { get; set; }
public decimal Outstanding { get; set; }
public decimal AmountPaid { get; set; }
public bool IsDisputed { get; set; }
}
public class OrderDetails: DetailOrderSup
{
public bool IsOrderPaid { get; set; }
public decimal Outstanding { get; set; }
}
public IEnumerable<PurchaseOrder> GetPurchaseOrders()
{
// THIS IS LINE THAT THROWS EXCEPTION
return this.AppContext.Orders.OfType<PurchaseOrder>()
.Include(o => o.DetailOrderSups.OfType<PurchaseOrderDetails>());
}
class OrderSupConfiguration : EntityTypeConfiguration<OrderSup>
{
public OrderSupConfiguration()
{
HasMany(p => p.DetailOrderSups)
.WithRequired(o => o.OrderSup)
.HasForeignKey(o => o.OrderId);
}
}
Please what am I doing wrong?
Thanks in advance for your assistance

Automapper missing type map configuration

I can't seem to figure out what is going wrong here, I have configured AutoMapper as follows
services.AddAutoMapper(typeof(MetingenView), typeof(Meting));
And in the controller like this:
public MetingenController(IMapper mapper)
{
this._mapper = mapper;
}
After, I use it like this:
var entity = await this.Context.MetingenView.AsNoTracking().FirstOrDefaultAsync(g =>g.IdMeting == key);
if (entity == null)
{
return NotFound();
}
data.Patch(entity);
var meting = await this.Context.Meting.FirstOrDefaultAsync(m => m.IdMeting == key);
this._mapper.Map(entity, meting);
Then the error rolls out:
AutoMapper.AutoMapperMappingException: Missing type map configuration
or unsupported mapping.
EDIT:
Here are the Meting, and MetingenView classes:
public partial class Meting
{
public int IdMeting { get; set; }
public int IdKoeling { get; set; }
public int IdWerknemer { get; set; }
public int IdGebouw { get; set; }
public int Temperatuur { get; set; }
public DateTime AfgenomenTijd { get; set; }
public string ProductNaam { get; set; }
public string Actie { get; set; }
public DateTime? DatumOntstaan { get; set; }
public DateTime? DatumMutatie { get; set; }
public int IndVerwijderd { get; set; }
public DateTime? DatumVerwijderd { get; set; }
public virtual Gebouw IdGebouwNavigation { get; set; }
public virtual Koeling IdKoelingNavigation { get; set; }
public virtual Werknemer IdWerknemerNavigation { get; set; }
}
public partial class MetingenView
{
[Key]
public int IdKlant { get; set; }
public string Locatie { get; set; }
public string SoortKoeling { get; set; }
public int IdMeting { get; set; }
public int IdKoeling { get; set; }
public int IdWerknemer { get; set; }
public int IdGebouw { get; set; }
public int Temperatuur { get; set; }
public string Actie { get; set; }
public string ProductNaam { get; set; }
public DateTime AfgenomenTijd { get; set; }
}
I think the mapping between Meting and MetingenView is not configured in AutoMapper. If you use Asp.Net Core, you could create a profile.
public class MetingProfile : Profile
{
public MetingProfile()
{
CreateMap<MetingenView, Meting>();
}
}
This would create a default mapping that two types have the same property. If you want to config property mapping manually, Function ForMember() would be used.
For example, if you wish that the property MetingenView.IdGebouw maps Meting.IndVerwijderd, you can code this:
CreateMap<MetingenView, Meting>()
.ForMember(dest=>dest.IdGebouw, opt=>opt.MapFrom(src=>src.IndVerwijderd));

How do I deserialize JSON correctly in C#

I am trying to deserialize the Supreme New York JSON but I am getting an error.
I used json2csharp.com to convert the Json into classes.
Then I summarised them all into one called items
namespace SUPBOTTESTING
{
public class items
{
public string name { get; set; }
public int id { get; set; }
public string image_url { get; set; }
public string image_url_hi { get; set; }
public int price { get; set; }
public int sale_price { get; set; }
public bool new_item { get; set; }
public int position { get; set; }
public string category_name { get; set; }
public int price_euro { get; set; }
public int sale_price_euro { get; set; }
}
}
using System;
using System.Net;
using System.Web.Script.Serialization;
namespace SUPBOTTESTING
{
class Program
{
public static void Main()
{
{
string shop_json = new WebClient().DownloadString("https://www.supremenewyork.com/mobile_stock.json");
JavaScriptSerializer shop_object = new JavaScriptSerializer();
items[] shirt_stock = shop_object.Deserialize<items[]>(shop_json);
Console.WriteLine(shirt_stock[1]);
}
}
}
}
I am getting the error:
Default constructor not found for type SUPBOTTESTING.items[]
Ok here is the solution. You have the correct idea but you need to understand the structure of your Json data.
You are deserializing it into an array of Object whereas your Json data returned itself is not an Array or a List. It contains child nodes that are an array so you need to structure your Object accordingly to get a successful breakdown of data.
Here I have used Newtonsoft to deserialise the Json data into an Object.
I have tested the code and it returns a list of Shirts
static void Main(string[] args)
{
var shop_json = new WebClient().DownloadString("https://www.supremenewyork.com/mobile_stock.json");
var shirt_stock = JsonConvert.DeserializeObject<StockObject>(shop_json);
// Picking shirts to demonstrate how to display values for all shirts
var shirts = shirt_stock.products_and_categories.Shirts;
foreach (var shirt in shirts)
{
var shirtBuilder = new StringBuilder();
shirtBuilder.AppendLine($"Name: {shirt.name}");
shirtBuilder.AppendLine($"ID: {shirt.id.ToString()}");
shirtBuilder.AppendLine($"New Item: {shirt.new_item.ToString()}");
shirtBuilder.AppendLine($"Category Name: {shirt.category_name}");
Console.WriteLine(shirtBuilder);
}
}
public class StockObject
{
public ProductsCats Products_and_categories { get; set; }
}
public class ProductsCats
{
public Details[] Shirts { get; set; }
public Details[] Bags { get; set; }
public Details[] Accessories { get; set; }
public Details[] Pants { get; set; }
public Details[] Jackets { get; set; }
public Details[] Skates { get; set; }
public Details[] Hats { get; set;}
public Details[] Sweatshirts { get; set;}
[JsonProperty("Tops/Sweaters")]
public Details[] TopsSweaters { get;set;}
public Details[] New { get; set; }
}
public class Details
{
public string name { get; set; }
public int id { get; set; }
public string image_url { get; set; }
public string image_url_hi { get; set; }
public int price { get; set; }
public int sale_price { get; set; }
public bool new_item { get; set; }
public int position { get; set; }
public string category_name { get; set; }
public int price_euro { get; set; }
public int sale_price_euro { get; set; }
}
You see what I have done here?
So your Json data contains a parent node products_and_categories and its child node contains an array of Shirts which is what you are after?
StockObject class contains the Parent property called Products_and_categories of type object ProductsCats.
ProductsCats Object contains the property Shirts of type Details which is an array and will be used during the deserialising process.
Hope this helps?
Well you do not need to specify a default constructor. What is wrong is, i think you didn't check the json data properly. Because your items class is not in the first level of json. You need to create a couple of classes to be more accurate on deserializing.
First of all you need to know that this json file has a lot of bad-smells and bad-practices on it.
Note that you need to install Newtonsoft.Json before going further. It is much more convenient way to deserialize a json into C# classes.
Yet, i wrote a proper way of deserializing it:
public class BaseItem
{
public string Name { get; set; }
public int Id { get; set; }
public string Image_url { get; set; }
public string Image_url_hi { get; set; }
public int Price { get; set; }
public int Sale_price { get; set; }
public bool New_item { get; set; }
public int Position { get; set; }
public string Category_name { get; set; }
public int Price_euro { get; set; }
public int Sale_price_euro { get; set; }
}
public class Shirt : BaseItem { }
public class Bag : BaseItem { }
public class Accessory : BaseItem { }
public class Pant : BaseItem { }
public class Jacket : BaseItem { }
public class Skate : BaseItem { }
public class Hat : BaseItem { }
public class Sweatshirt : BaseItem { }
public class TopsSweater : BaseItem { }
public class New : BaseItem { }
public class RootObject
{
public List<object> Unique_image_url_prefixes { get; set; }
public ProductsAndCategories Products_and_categories { get; set; }
public string Release_date { get; set; }
public string Release_week { get; set; }
}
public class ProductsAndCategories
{
public List<Shirt> Shirts { get; set; }
public List<Bag> Bags { get; set; }
public List<Accessory> Accessories { get; set; }
public List<Pant> Pants { get; set; }
public List<Jacket> Jackets { get; set; }
public List<Skate> Skate { get; set; }
public List<Hat> Hats { get; set; }
public List<Sweatshirt> Sweatshirts { get; set; }
[JsonProperty("Tops/Sweaters")]
public List<TopsSweater> TopsSweaters { get; set; }
public List<New> New { get; set; }
}
First of all, all of your items are have the same properties on them, yet, they all marked as different properties. So that, i created a BaseItem class and other empty classes which are inherited from that.
Also you need other 2 classes -which are RootObject and ProductsAndCategories- to provide data on them. Note that there is a JsonProperty("blabla") on the TopsSweaters property. Because, in json file it is Tops/Sweaters, and you can not use that name on a C# property. That is the attribute for using that kind of different property names.
Then you can populate your object like this:
static void Main(string[] args)
{
var jsonData = "https://www.supremenewyork.com/mobile_stock.json";
string shopJson = new WebClient().DownloadString(jsonData);
RootObject shirtStock = JsonConvert.DeserializeObject<RootObject>(shopJson); //All json data is in this variable
Console.WriteLine(shirtStock.Products_and_categories.Shirts[1]);
}
Your problem is that youre using a class to load the JSON data in, where you should use a struct, alternatively you can also create a constructor that takes no arguments and sets all variables to default values, which is a lot of work so just replace class with struct:
public struct Items
{
public string Name { get; set; }
public int Id { get; set; }
public string Image_Url { get; set; }
public string Image_Url_Hi { get; set; }
public int Price { get; set; }
public int Sale_Price { get; set; }
public bool New_item { get; set; }
public int Position { get; set; }
public string Category_Name { get; set; }
public int Price_Euro { get; set; }
public int Sale_Price_Euro { get; set; }
}
Also please stick to C# naming conventions, you should be able to do this since most JSON parsers are case insensitive by default.
Some more info: A class doesnt really has a proper default constructor if you dont define one, where as a struct always has a default constructor, so when the JSON parser wants to init your class it cant because a default constructor isnt definded.
static void Main(string[] args)
{
string shop_json = new WebClient().DownloadString("https://www.supremenewyork.com/mobile_stock.json");
JavaScriptSerializer shop_object = new JavaScriptSerializer();
var shirt_stock = shop_object.Deserialize<NewYarkItems>(shop_json);
var v = shirt_stock;
}
public class NewYarkItems
{
public dynamic unique_image_url_prefixes { get; set; }
public products_and_categories products_And_Categories { get; set; }
public string release_date { get; set; }
public string release_week { get; set; }
}
public class products_and_categories
{
public List<items> Jackets { get; set; }
}
public class items
{
public string name { get; set; }
public int id { get; set; }
public string image_url { get; set; }
public string image_url_hi { get; set; }
public int price { get; set; }
public int sale_price { get; set; }
public bool new_item { get; set; }
public int position { get; set; }
public string category_name { get; set; }
public int price_euro { get; set; }
public int sale_price_euro { get; set; }
}

How to access a model through List in MVC

I want to sort the ValidatingCarrier in ascending order so I thought of getting it into a List and sorting it using Orderby in my controller.
I have the following Model Classes:
public class sort
{
public OTAAirLowFareSearchRS OTA_AirLowFareSearchRS { get; set; }
}
public class OTAAirLowFareSearchRS
{
public int PricedItinCount { get; set; }
public int BrandedOneWayItinCount { get; set; }
public int SimpleOneWayItinCount { get; set; }
public int DepartedItinCount { get; set; }
public int SoldOutItinCount { get; set; }
public int AvailableItinCount { get; set; }
public string Version { get; set; }
public Success success { get; set; }
public Warnings Warnings { get; set; }
public PricedItineraries PricedItineraries { get; set; }
public TPAExtensions8 TPA_Extensions { get; set; }
}
public class PricedItinerary
{
public int SequenceNumber { get; set; }
public AirItinerary AirItinerary { get; set; }
public List<AirItineraryPricingInfo> AirItineraryPricingInfo { get; set; }
public TicketingInfo TicketingInfo { get; set; }
public TPAExtensions7 TPA_Extensions { get; set; }
}
public class AirItineraryPricingInfo
{
public string PricingSource { get; set; }
public string PricingSubSource { get; set; }
public ItinTotalFare ItinTotalFare { get; set; }
public PTCFareBreakdowns PTC_FareBreakdowns { get; set; }
public FareInfos2 FareInfos { get; set; }
public TPAExtensions6 TPA_Extensions { get; set; }
public string LastTicketDate { get; set; }
}
public class TPAExtensions6
{
public DivideInParty DivideInParty { get; set; }
public ValidatingCarrier ValidatingCarrier { get; set; }
}
The following is the way I am trying to access it in my controller. I cannot access beyond PriceItinerary cause the reset goes as a List.
sort searchResponse = JsonConvert.DeserializeObject<sort>(tar.ToString());
var sortingname = searchResponse.OTA_AirLowFareSearchRS.PricedItineraries.PricedItinerary;
List<PricedItinerary> lstname = new List<PricedItinerary>();
Any kind of help is appreciated....
You have create the object first
searchResponse.OTA_AirLowFareSearchRS.PricedItineraries.PricedItinerary obj = new searchResponse.OTA_AirLowFareSearchRS.PricedItineraries.PricedItinerary;
var x = obj.SequenceNumber;
Are you trying to access "AirItineraryPricingInfo" with the instance of "PricedItinerary"? If it is so, then this helps, otherwise please ignore.
public class PricedItinerary : AirItineraryPricingInfo
{
public int SequenceNumber { get; set; }
public AirItinerary AirItinerary { get; set; }
public List<AirItineraryPricingInfo> AirItineraryPricingInfo { get; set; }
public TicketingInfo TicketingInfo { get; set; }
public TPAExtensions7 TPA_Extensions { get; set; }
}
In controller if we create instance for "PricedItinerary", we can access inherited class.
You can do it with LINQ SelectMany makes a projection os IEnumerable into one IEnumerable.
With the given model and assuming that you need to get a list of ValidatingCarrier starting on PricedItinerary , let's go do it!
IEnumerable<ValidatingCarrier> IEValidatingCarrier = searchResponse.OTA_AirLowFareSearchRS.PricedItineraries.PricedItinerary
.SelectMany(p => p.AirItineraryPricingInfo.SelectMany(a => a.TPA_Extensions.ValidatingCarrier)); //This would give you an IEnumerable<ValidatingCarrier>
IEnumerable<ValidatingCarrier> LstValidatingCarrier = IEValidatingCarrier.OrderBy(o => o.OrderBySomething).ToList(); //And finally, your ordered list!
You can also do it all at once, something like this:
searchResponse.OTA_AirLowFareSearchRS.PricedItineraries.PricedItinerary
.SelectMany(p => p.AirItineraryPricingInfo.SelectMany(a => a.TPA_Extensions.ValidatingCarrier))
.OrderBy(o => o.OrderBySomething).ToList();
Hope it helps! Plase if I don't understand well your question, please let me know!

Categories

Resources