How to ignore source object in Automapper - c#

This my Source class
public class Content :IAggregateRoot
{
public Guid Id { get; set; }
public string HeaderImage { get; set; }
public string AboutText { get; set; }
public string Address { get; set; }
public long Phone { get; set; }
public long Mobile { get; set; }
public DateTime CreationTime { get; set; }
}
and this is my Destination class
public class AboutViewModel
{
public string AboutText { get; set; }
public string Address { get; set; }
public long Phone { get; set; }
public long Mobile { get; set; }
}
I just want to ignore extra properties of source and map source to destination with Automapper with this method
public static AboutViewModel ConvertToAboutViewModel(this Content content)
{
// Mapper.CreateMap<Content,AboutViewModel>().ForMember(x=>x.AboutText,)
return Mapper.Map<Content, AboutViewModel>(content);
}
How can I do that??

Automapper would ignore those properties by default as they do not exist in the destination class.
Have you actually tried to run your code? if it is not working could you please post details of the error or exception you are getting.
You also need to define your basic map like this:
Mapper.CreateMap<Content, AboutViewModel>();
Mapper.CreateMap<AboutViewModel, Content>();
Ensure that the above code is ran before you call ConvertToAboutViewModel

Related

How unflattening commands to complex types

I'm not yet dependent to either Mapster or AutoMapper. For now I'm using handwritten mappings because I couldn't find a mapper who could do this with smaller code.
The problem is how do we map flatten structures to complex objects? I think a lot of people could benefit from a good mapping example for such a complex object. I've got even a mapping condition based on CopyOfficeAddressAsInvoiceAddress whether or not the office address needs to be copied as invoice address. I've looked all over the place but couldn't get it to work.
Maybe I should also use a different naming to make it more clear for the mapping algorithm?!
The biggest question could such a map being resolved by a mapper or is this to complex? Al the demo's I've seen were using dto and model objects that are quite similar to each other. I didn't get the point of mapping an object to another object that 99% similar to each other.
I have a Command (I'm using Mediatr) that looks like as follows:
public class Command : IRequest<IActionResult>
{
public string AccountName { get; set; }
public string ContactFirstName { get; set; }
public string ContactLastName { get; set; }
public string ContactEMail { get; set; }
public string ContactPhoneNumber { get; set; }
public string BankAccount { get; set; }
public string Bank { get; set; }
public string OfficeName { get; set; }
public string OfficeAddressStreet { get; set; }
public int OfficeAddressStreetNumber { get; set; }
public string? OfficeAddressStreetNumberAddition { get; set; }
public string OfficeAddressPostalcode { get; set; }
public string OfficeAddressCity { get; set; }
public string OfficeAddressCountry { get; set; }
public string? OfficeInvoiceAddressStreet { get; set; } = null;
public int? OfficeInvoiceAddressStreetNumber { get; set; } = null;
public string? OfficeInvoiceAddressStreetNumberAddition { get; set; } = null;
public string? OfficeInvoiceAddressPostalcode { get; set; } = null;
public string? OfficeInvoiceAddressCity { get; set; } = null;
public string? OfficeInvoiceAddressCountry { get; set; } = null;
//[Ignore]
public bool? CopyOfficeAddressAsInvoiceAddress { get; set; } = false;
public string? AssociationIdentifier { get; set; } = null;
}
And I want it to be mapped to the following models:
public class Account
{
public int Id { get; set; }
public string AccountName { get; set; }
public IList<Contact> Users { get; set; }
public IList<Office> Offices { get; set; }
public string Bank { get; set; }
public string BankAccount { get; set; }
public string? AssociationIdentifier { get; set; }
}
public class Office
{
public int Id { get; set; }
public string Name { get; set; }
public Address ContactAddress { get; set; }
public Address InvoiceAddress { get; set; }
public bool HeadQuarter { get; set; }
}
public class Address
{
public int Id { get; set; }
public string Street { get; set; }
public string Postalcode { get; set; }
public int StreetNumber { get; set; }
public string StreetNumberAddition { get; set; }
public string City { get; set; }
public string Country { get; set; }
}
public class Contact
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EMail { get; set; }
public string PhoneNumber { get; set; }
}
First of all, my experience is mainly using Automapper, and it is definitely possible to map complex types like this.
But your command does not need to be completely flat. There is nothing inherently wrong with DTOs being similar to your domain models. Using Automapper this is fairly easy as properties with the same name are mapped 1:1.
It could be that you are submitting a form with all the properties flattened in one object. In that case you could define either a seperate map for this object and each domain object.
CreateMap<AccountDto, Account>(); // mapping logic omitted
CreateMap<AccountDto, Office>();
...
Or you could map the one object to a range of objects using Tuples.
CreateMap<AccountDto, (Account, Office, ...)>(); // mapping logic omitted
But if you define seperate DTOs and make mapping profiles for them, it will probably ease your whole mapping experience. For copying the address, you can simply do something like this, in that case.
if (copyAddress)
{
office.InvoiceAddress = _mapper.Map<Address>(addressDto);
}

Unable to deserialize JSON in c#

I am getting the below JSON in response from a REST API.
{
"data":{
"id":123,
"zoneid":"mydomain.com",
"parent_id":null,
"name":"jaz",
"content":"172.1 6.15.235",
"ttl":60,
"priority":null,
"type":"A",
"regions":[
"global"
],
"system_record":false,
"created_at":"2017-09-28T12:12:17Z",
"updated_at":"2017-09-28T12:12:17Z"
}
}
and trying to resolve using below code but that doesn't result in a correctly deserialized type.
var model = JsonConvert.DeserializeObject<ResponseModel>(response);
below is a class according the field I received in JSON response.
public class ResponseModel
{
public int id { get; set; }
public string zone_id { get; set; }
public int parent_id { get; set; }
public string name { get; set; }
public string content { get; set; }
public int ttl { get; set; }
public int priority { get; set; }
public string type { get; set; }
public string[] regions { get; set; }
public bool system_record { get; set; }
public DateTime created_at { get; set; }
public DateTime updated_at { get; set; }
}
What is missing?
You're missing a wrapper class.
public class Wrapper
{
public ResponseModel data {get;set}
}
and then do:
var model = JsonConvert.DeserializeObject<Wrapper>(response).data;
to get the instance of your ResponseModel out the data property.
You can deduct this from your json:
{ "data":
{ "id":123, /*rest omitted */ }
}
The type that will receive this JSON needs to have a property named data. The suggested Wrapper class acts as that type.
According to json2csharp website, your model seems to be incorrect. Try this one :
public class ResponseModel
{
public int id { get; set; }
public string zoneid { get; set; }
public object parent_id { get; set; }
public string name { get; set; }
public string content { get; set; }
public int ttl { get; set; }
public object priority { get; set; }
public string type { get; set; }
public List<string> regions { get; set; }
public bool system_record { get; set; }
public DateTime created_at { get; set; }
public DateTime updated_at { get; set; }
}
public class RootObject
{
public ResponseModel data { get; set; }
}
Here a cool trick you can do in Visual Studio 2015-2017 where it generates the the correct class if you just copy the JSON (ctrl + c).
You need to create a new class in visual studio and once inside the class go to Edit menu -> Paste special -> paste JSON As Classes.
Steps to generate json class
This will generate the C# object for that json for you and save you all the hassle :)
Your model does not match your response - it matches the data property. Simply wrap another object round it
public class ResponseData
{
public ResponseModel Data {get; set; {
}
and then
var model = JsonConvert.DeserializeObject<ResponseData>(response);

Expanding classes using AutoMap

I have to import a set of data from one database to another with a somewhat different schema, and I'm considering using AutoMap. I could just write a bunch of SQL scripts, but I already have both databases in EF and I want to learn AutoMap ...
While many of the classes are similar, the problem I'm having is where the structure is really different. The target models were designed with several more layers of classes. Instead of flattening, I need to expand.
The target classes have the following properties:
public class Account
{
public int Id { get; set; }
public string Name { get; set; }
public ContactInfo Location { get; set; }
public List<Policy> Policies { get; set; }
}
public class ContactInfo
{
public int Id { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public State State { get; set; }
public string Zip { get; set; }
public string EMail { get; set; }
public List<Phone> PhoneNumbers { get; set; }
}
public class Phone
{
public int Id { get; set; }
public string Name { get; set; }
public string Number { get; set; }
}
public class Policy
{
public int Id { get; set; }
public PolicyNumber PolicyNumber { get; set; }
public List<Transaction> Transactions { get; set; }
}
The source tables, however, are relatively flattened.
public partial class Account
{
public string AccountId { get; set; }
public string AccountName { get; set; }
public string PolicyNumber { get; set; }
}
public partial class Transaction
{
public int TransactionId { get; set; }
public int AccountId { get; set; }
public Nullable<System.DateTime> EffectiveDate { get; set; }
public string InsuredName { get; set; }
public string InsuredAddress { get; set; }
public string InsuredCity { get; set; }
public string InsuredState { get; set; }
public string InsuredZip { get; set; }
public string InsuredPhone { get; set; }
}
I can create the Map, but I don't know how to tell AutoMapper to handle converting the string Policy to a policy object and then add it to the list of Policies.
Mapper.CreateMap<Source.Account, Destination.Account>();
Even worse, the source data inexplicitly has the name and address info at the transaction level. Before you tell me that AutoMap might not be the best solution, please understand that these two source tables are 2 out of over 40 tables in this database, and that the others are not nearly as troublesome.
Can I configure AutoMap to convert the string property PolicyNumber to a Policy Object and add it to the Policies List of the target class?
Any suggestions on how I can get the name and address information from the Transaction into a ContactInfo class and add it at the Account level?
Thank you.
Thanks to Thomas Weller. Custom Value Resolvers handled exactly what I needed.

Collection Nested within Model is Not Bound by MVC 3 (Always null)

I have a model that represents various information about a university in ASP.NET MVC 3 and Entity Framework 5.0. The model has an ICollection of another model, called TrendModel. This collection seems to never be stored/bound by MVC at any point, no matter what I do.
When I manually set this collection to something at run time (after it is retrieved from the database), the collection is of course no longer null, but whatever I seem to set it to and then store in the database, trends is always null when I retrieve it from the database.
UniversityModel:
public class UniversityModel
{
[Key]
public string univ_id { get; set; }
public string ipeds_id { get; set; }
public string name { get; set; }
public bool religious { get; set; }
#region Location Information
public string city { get; set; }
public string state { get; set; }
public string urbanization { get; set; }
public double latitude { get; set; }
public double longitude { get; set; }
#endregion
public ICollection<TrendModel> trends { get; set; }
}
TrendModel:
public class TrendModel
{
[Key]
public string id { get; set; }
public ushort year { get; set; }
public uint? capacity { get; set; }
public uint? rate { get; set; }
public uint? meals { get; set; }
public bool? forProfit { get; set; }
public bool? control { get; set; }
public string degree { get; set; }
public bool? landgrant { get; set; }
public bool? athletic { get; set; }
public string calendar { get; set; }
public bool? required { get; set; }
}
Not sure if it is relevant, but if I put in a constructor for UniversityModel that sets trends to an empty list, then trends is no longer null and is an empty list.
Is this a model binding issue, or a post issue or something? Sorry if I'm completely off-base, I'm pretty new to MVC and ASP.NET.
you haven't included a foreign key in your trend model.try adding univ_id in your TrendModel class.
public class TrendModel
{
[Key]
public string id { get; set; }
.
.
.
[ForeignKey("univ_id")]
public string univ_id {get;set;}
}
As it turn out, the issue was fixed simply by me enforcing lazy loading on the trends, so the property now reads:
public virtual ICollection<TrendModel> trends { get; set; }

Correct use of Object Properties

Below is a Class I created to track the current Person in my glorified Data Entry and retrieval app. Once they select a person it calls the constrtuctor which then calls the database to fill in all the rest of the info. Also, throughout the program they will be able to change the various fields.
With this in mind do I have the below set up correctly? I am inexpierenced with properties and using Objects to store data across multiple forms and would appreciate any insight.
Thanks!
class CurrentPerson
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string MiddleName { get; set; }
public string SuffixID { get; set; }
public string TitleID { get; set; }
public string SocialSn { get; set; }
public string BirthDate { get; set; }
public string Gender { get; set; }
public string DlNumber { get; set; }
public string DlStateID { get; set; }
public string PrimaryRace { get; set; }
public string SecondaryRace { get; set; }
public string EmailAddress { get; set; }
public string MaritalStatus { get; set; }
public string InsertProgram { get; set; }
public string InsertUserID { get; set; }
public string UpdateProgram { get; set; }
public string UpdateUserID { get; set; }
public string LockID { get; set; }
public int PersonID { get; set; }
public int ClientID { get; set; }
public int ResidencyCountyID { get; set; }
public int ResponsibilityCountyID { get; set; }
public bool HispanicOriginFlag { get; set; }
public bool CitizenFlag { get; set; }
public bool VeteranFlag { get; set; }
public DateTime DeathDate { get; set; }
public DateTime InsertDateTime { get; set; }
public DateTime UpdateDateTime { get; set; }
// Put the default Constructor back in
public CurrentPerson(){}
// Custom Constructor that needs the PersonID
public CurrentPerson(int pID)
{
PersonID = pID;
// Methods to get rest of data here
}
}
yup, looks good.
you can, btw, set access on the get/set as well, to make it read/write only publicly
public DateTime DeathDate
{
get;
private set;
}
This is technically fine. They are all declared perfectly well.
However, often, with DB apps, you'll want to not use automatic properties, since property setters are often a great place to do some validation, as well as potentially marking properties/objects as "dirty" and requiring saving of some sort.
The auto property is always get and set, so that you have no control about properties set (to mark the instance as dirty, or whatever). Therefore, while this is an acceptable class as data entity only, I usually find that auto properties are only rarely really applicable.

Categories