AutoMapper complex type objects mapping C# - c#

In my method I got back results that contain several list of strings and list of complex type objects.
var AcctLst = gd.validateGroupMembershipUploadDetails(_input);
Mapper.CreateMap<Data.Entities.Upload.GroupMembershipValidationOutput, Business.Upload.GroupMembershipValidationOutput>();
var result = Mapper.Map<Data.Entities.Upload.GroupMembershipValidationOutput, Business.Upload.GroupMembershipValidationOutput>(AcctLst);
return result;
var AcctLst contains the sample data :
Data.Entities.Upload.GroupMembershipValidationOutput
and
Business.Upload.GroupMembershipValidationOutput
looks like
public class GroupMembershipValidationOutput
{
public List<string> _validMasterIds { get; set; }
public List<ChapterCodeValidationOutput> _validChapterCodes { get; set; }
public List<GroupCodeValidationOutput> _validGroupCodes { get; set; }
public List<string> _invalidMasterIds { get; set; }
public List<string> _invalidChapterCodes { get; set; }
public List<string> _invalidGroupCodes { get; set; }
}
public class ChapterCodeValidationOutput
{
public string chpt_cd { get; set; }
public string appl_src_cd { get; set; }
}
public class GroupCodeValidationOutput
{
public string grp_cd { get; set; }
public string grp_nm { get; set; }
}
I guess _validChapterCodes and _validGroupCodes throw the following exception :
Missing type map configuration or unsupported mapping.
Mapping types:
ChapterCodeValidationOutput -> ChapterCodeValidationOutput
ARC.Donor.Data.Entities.Upload.ChapterCodeValidationOutput -> ARC.Donor.Business.Upload.ChapterCodeValidationOutput
Destination path:
GroupMembershipValidationOutput._validChapterCodes._validChapterCodes._validChapterCodes0[0]
Source value:
ARC.Donor.Data.Entities.Upload.ChapterCodeValidationOutput

Yeah damn. It's relatively simple. You just have to map the inner nested types first.
var AcctLst = gd.validateGroupMembershipUploadDetails(_input);
Mapper.CreateMap<Data.Entities.Upload.ChapterCodeValidationOutput, Business.Upload.ChapterCodeValidationOutput>();
Mapper.CreateMap<Data.Entities.Upload.GroupCodeValidationOutput, Business.Upload.GroupCodeValidationOutput>();
Mapper.CreateMap<Data.Entities.Upload.GroupMembershipValidationOutput, Business.Upload.GroupMembershipValidationOutput>();
var result = Mapper.Map<Data.Entities.Upload.GroupMembershipValidationOutput, Business.Upload.GroupMembershipValidationOutput>(AcctLst);
return result;
Then it works flawlessly.

Related

Automapper executes without error, but no data being copied from source to destination

I have a class like this
public class ListOfBMTTeamMapping
{
public class TeamMapping
{
public List<TeamMappings> results { get; set; }
}
public class TeamMappings
{
public int id { get; set; }
public string areaPath { get; set; }
public string agileReleaseTrainName { get; set; }
public string deliveryTeamName { get; set; }
public string keyedInTeamCode { get; set; }
public string deliveryTeamId { get; set; }
public bool isDeleted { get; set; }
public string modified { get; set; }
public string modifiedBy { get; set; }
}
}
And here is my model class to which I need the above API class to get copied
public class JsonBmtAdoMapping
{
public int? Id { get; set; }
public string AreaPath { get; set; }
public string AgileReleaseTrainName { get; set; }
public string DeliveryTeamName { get; set; }
public string KeyedInTeamCode { get; set; }
public string DeliveryTeamId { get; set; }
public string IsDeleted { get; set; }
public DateTime? Modified { get; set; }
public string ModifiedBy { get; set; }
}
So here is my code I tried
var format = "dd/MM/yyyy";
var dateTimeConverter = new IsoDateTimeConverter { DateTimeFormat = format };
ListOfBMTTeamMapping.TeamMapping Results = new ListOfBMTTeamMapping.TeamMapping();
Results = JsonConvert.DeserializeObject<ListOfBMTTeamMapping.TeamMapping>(responseBody);
List<JsonBmtAdoMapping> jM = new List<JsonBmtAdoMapping>();
jM = _mapper.Map<ListOfBMTTeamMapping.TeamMapping,List<JsonBmtAdoMapping>>(Results);
int n = 10;
And here is my automapper profile
CreateMap<ListOfBMTTeamMapping.TeamMapping, List<JsonBmtAdoMapping>>();
CreateMap<ListOfBMTTeamMapping.TeamMappings, JsonBmtAdoMapping>();
But when the code executes, Ofcourse I am getting the data in results variable without any trouble
But when the mapper code fires, it execute the line without any error, but no data being copied from source to my model class which is the destination
jM.count is always 0 when Results hold 124 rows of data
What I did wrong
Your mapping from TeamMapping to List<JsonBmtAdoMapping> can't be done out of the box by AutoMapper, because your source is an object with a property that contains the list and the destination is a list on itself.
So you have to tell him, how this conversion from a single object to a list can be done. Due to the fact, that you already have a mapping for each individual item, we can use that recursively within our mapping method.
By using this mapping, it should work:
CreateMap<ListOfBMTTeamMapping.TeamMappings, JsonBmtAdoMapping>();
CreateMap<ListOfBMTTeamMapping.TeamMapping, List<JsonBmtAdoMapping>>()
.ConvertUsing((src, _, context) => src.results.Select(context.Mapper.Map<JsonBmtAdoMapping>).ToList());
Update
Cause a mapper is already defined for the individual items and lists are handled automatically by AutoMapper we can even make it shorter (thanks for Lucian for the hint in the comments):
CreateMap<ListOfBMTTeamMapping.TeamMappings, JsonBmtAdoMapping>();
CreateMap<ListOfBMTTeamMapping.TeamMapping, List<JsonBmtAdoMapping>>()
.ConvertUsing((src, _, context) => context.Mapper.Map<List<JsonBmtAdoMapping>>(src.results));

AutoMapper returns NULL when returning a list

Code without AutoMapper:
List<CountryDM> countryDMList = _countryRepo.GetCountry();
List<CountryVM> countryVMList = new List<CountryVM>();
foreach (CountryDM countryDM in countryDMList)
{
countryVMList.Add(CountryVM.ToViewModel(countryDM));
}
return countryVMList;
I used AutoMapper for the above task. But it returns a NULL list. Please refer the below code:
List<CountryDM> countryDMList = _countryRepo.GetCountry();
Mapper.CreateMap<List<CountryDM>, List<CountryVM>>();
List<CountryVM> countryVMList = new List<CountryVM>();
return Mapper.Map<List<CountryVM>>(countryDMList);
public class CountryDM
{
public int ID { get; set; }
public string CountryCode { get; set; }
public string Description { get; set; }
}
public class CountryVM
{
public int ID { get; set; }
public string CountryCode { get; set; }
public string Description { get; set; }
}
You don't need to define a mapping between lists, just between objects, AutoMapper will know how to extrapolate that:
Mapper.CreateMap<CountryDM, CountryVM>();
the rest stays the same

Convert flat to hierarchy list?

I have two tables "CategoryGroup" and "Category" which returns data in one list. Requirement is to convert flat list to hierarchy list like CategoryGroup contains related categories.
Please suggest how to convert into hieararchy list?
public class ProfileConditionGroup
{
public Guid ConditionGroupGUID { get; set; }
public string ConditionGroupName { get; set; }
public List<ProfileConditionList> profileConditions { get; set; }
}
public class ProfileConditionList
{
public string ConditionName { get; set; }
public Nullable<Guid> ConditionGUID { get; set; }
public string[] ThisConditionSelectedByProfileIDs { get; set; }
public Nullable<Guid> ParentConditionGroupGUID { get; set; }
public bool IsDefaultSelected { get; set; }
}
This is actually a little tricky without having an actual concrete return type, but here's the way I'd tackle it if you're just building a tree of Guid values.
Given this query:
var query =
from pcg in pcgs
from pcl in pcg.profileConditions
select new
{
pcg.ConditionGroupName,
pcg.ConditionGroupGUID,
pcl.ConditionName,
pcl.ConditionGUID,
pcl.ThisConditionSelectedByProfileIDs,
pcl.ParentConditionGroupGUID,
pcl.IsDefaultSelected,
};
...I'd do this:
var lookup = query.ToLookup(x => x.ParentConditionGroupGUID);
Func<Guid?, Tree<Guid?>> build = null;
build = g =>
{
var r = new Tree<Guid?>() { Value = g };
r.AddRange(lookup[g].Select(x => build(x.ConditionGroupGUID)));
return r;
};
Now you just call build(null) and you should get a tree of Guid?. If you can create you're own output class you'd change the function to Func<Guid?, Tree<YourOutputClass>>.
You need this class for the tree:
public class Tree<T> : List<Tree<T>>
{
public T Value { get; set; }
}

Server not receiving lists inside of JSON object passed in

These are the data contracts that are being used in the function.
public class ResumeSkillsListDataContract : IResumeSkillsListDataContract
{
public IList<ISkillDataContract> KnownSkillsList { get; set; }
public IList<ISkillDataContract> BadSkillsList { get; set; }
public IList<ISkillDataContract> NewSkillsList { get; set; }
public Int32 PersonId { get; set; }
}
public class SkillDataContract : ISkillDataContract
{
public String Name { get; set; }
public Nullable<Int32> Id { get; set; }
public Nullable<Boolean> IsAssigned { get; set; }
public Nullable<Int32> SkillCategoryId { get; set; }
public Nullable<Int32> SkillCategoryMappingId { get; set; }
}
This is the function in the controller. I am expecting three populated lists and a PersonId to be passed in. However, I am only receiving the PersonId. In my Post, I see the data I am expecting to see in the console but when debugging the controller, item.List is empty every time.
public IList<ISkillDataContract> PostResumePersonSkills(ResumeSkillsListDataContract item)
{
var newList = item.KnownSkillsList;
var ignoreList = item.BadSkillsList;
var existingList = item.NewSkillsList;
var personId = item.PersonId;
return resumePersonSkillsBusinessLibrary.PostSkills(newList, ignoreList, existingList, personId);
}
Here is a quick snapshot of what im sending to the server. Any idea what could be wrong? Thanks.
$scope.doneWithSkills = function () {
var resumeCollection = {
KnownSkillsList: $scope.KnownSkillsList, BadSkillsList: $scope.IgnoredSkillsList,
NewSkillsList: $scope.SaveAsSkillsList, PersonId:$scope.ParsedPerson.Person.PersonId
};
resumeParserService.PostResumeSkills(resumeCollection);
};
Function in the resumeParserService
self.PostResumeSkills = function (skills) {
var url = 'ResumeSkill/PostResumePersonSkills';
console.log(skills);
webApiService.Post(url, skills);
};
Sample JSON being passed.
{"KnownSkillsList":[{"Name":"C++","Id":null,"IsAssigned":null,"SkillCategoryId":3,"SkillCategoryMappingId":154},{"Name":"Unix","Id":null,"IsAssigned":null,"SkillCategoryId":3,"SkillCategoryMappingId":219},{"Name":".Net","Id":null,"IsAssigned":null,"SkillCategoryId":3,"SkillCategoryMappingId":139},{"Name":"Clearcase","Id":null,"IsAssigned":null,"SkillCategoryId":3,"SkillCategoryMappingId":155},{"Name":"Uml","Id":null,"IsAssigned":null,"SkillCategoryId":3,"SkillCategoryMappingId":218},{"Name":"Xml","Id":null,"IsAssigned":null,"SkillCategoryId":3,"SkillCategoryMappingId":239},{"Name":"Java","Id":null,"IsAssigned":null,"SkillCategoryId":3,"SkillCategoryMappingId":173},{"Name":"Python","Id":null,"IsAssigned":null,"SkillCategoryId":3,"SkillCategoryMappingId":199},{"Name":"Visual Basic","Id":null,"IsAssigned":null,"SkillCategoryId":3,"SkillCategoryMappingId":223}],"BadSkillsList":[],"NewSkillsList":[{"Name":"Algorithms","Id":null,"IsAssigned":null,"SkillCategoryId":3,"SkillCategoryMappingId":null}],"PersonId":1203}
I would expect this is caused by your lists ResumeSkillsListDataContract being lists of an interface. The problem is going to be that when the JSON is deserialized the deserializer does not know what concrete type to instantiate.
Try changing to this and see if it resolves the problem
public class ResumeSkillsListDataContract : IResumeSkillsListDataContract
{
public IList<SkillDataContract> KnownSkillsList { get; set; }
public IList<SkillDataContract> BadSkillsList { get; set; }
public IList<SkillDataContract> NewSkillsList { get; set; }
public Int32 PersonId { get; set; }
}

Serialize deserialize anonymous child JSON properties to model

I have an API I am receiving data from. That API is out of my control on how it is structured, and I need to serialize and deserialize the JSON output to map the data to my model.
Everything works well where JSON is nicely formatted with named properties.
What can you do where there is no named value and there is just an array of ints and strings? like under locations
here is a sample of the JSON:
{"id":"2160336","activation_date":"2013-08-01","expiration_date":"2013-08-29","title":"Practice Manager","locations":{"103":"Cambridge","107":"London"}}
I have models that are like:
public class ItemResults
{
public int Id { get; set; }
public DateTime Activation_Date { get; set; }
public DateTime Expiration_Date{ get; set; }
public string Title { get; set; }
public Location Locations { get; set; }
}
public class Location
{
public int Id { get; set; }
public string value { get; set; }
}
and I am mapping using the inbuilt ajax serialization:
protected T MapRawApiResponseTo<T>( string response )
{
if ( string.IsNullOrEmpty( response ) )
{
return default( T );
}
var serialize = new JavaScriptSerializer();
return serialize.Deserialize<T>( response );
}
var results = MapRawApiResponseTo<ItemResults>(rawApiResponse);
So the ID and all other properties are picked up and mapped but what every I do I can not seem to map the locations.
Many thanks
public Dictionary<int,string> Locations { get; set; }
job done; you should find that using Json.NET, at least, i.e.
var result = JsonConvert.DeserializeObject<ItemResults>(json);
you get 2 entries in result.Locations; specifically result[103] = "Cambridge"; and result[107] = "London";
If you don't mind, you can workaround with dictionary:
class Program
{
static void Main(string[] args)
{
string json =
"{'id':'2160336','activation_date':'2013-08-01','expiration_date':'2013-08-29','title':'Practice Manager','locations':{'103':'Cambridge','107':'London'}}";
var deserializeObject = JsonConvert.DeserializeObject<ItemResults>(json);
Console.WriteLine("{0}:{1}", deserializeObject.Locations.First().Key, deserializeObject.Locations.First().Value);
Console.ReadKey();
}
}
public class ItemResults
{
public int Id { get; set; }
public DateTime Activation_Date { get; set; }
public DateTime Expiration_Date { get; set; }
public string Title { get; set; }
public Dictionary<int, string> Locations { get; set; }
}
you can also use manual parsing, like here: Json.NET (Newtonsoft.Json) - Two 'properties' with same name?
This will work:
public Dictionary<string, string> Locations { get; set; }
public IEnumerable<Location> LocationObjects { get { return Locations
.Select(x => new Location { Id = int.Parse(x.Key), value = x.Value }); } }
I propose you the following solution :
public class ItemResults
{
public int Id { get; set; }
public DateTime Activation_Date { get; set; }
public DateTime Expiration_Date { get; set; }
public string Title { get; set; }
[JsonProperty("locations")]
public JObject JsonLocations { get; set; }
[JsonIgnore]
public List<Location> Locations { get; set; }
[OnDeserialized]
public void OnDeserializedMethod(StreamingContext context)
{
this.Locations = new List<Location>();
foreach (KeyValuePair<string, JToken> item in this.JsonLocations)
{
this.Locations.Add(new Location() { Id = int.Parse(item.Key), value = item.Value.ToString() });
}
}
}
public class Location
{
public int Id { get; set; }
public string value { get; set; }
}
After you just have to deserialize your JSON with : JsonConvert.DeserializeObject<ItemResults>(json);

Categories

Resources