AutoMapper Nested Mapping not working. Here is the config and code : - c#

Followed the steps mentioned in Automapper wiki to configure nested mapping with complex objects. but not working :
public class Student
{
public int ID{get;set;}
public string Name { get; set; }
public string Standard { get; set; }
public List<string> Course { get; set; }
public int Age { get; set; }
public string FatherName { get; set; }
public string MotherName{ get; set; }
public char Gender { get; set; }
public DateTime DOB { get; set; }
public string BloodGroup { get; set; }
public int TestCondition { get; set; }
public Address Address { get; set; }
}
public class Address
{
public int ID { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Zip { get; set; }
}
DTO :
public class StudentDTO
{
public string Name { get; set; }
public string Standard { get; set; }
public char Gender { get; set; }
public DateTime DOB { get; set; }
public string BG { get; set; }
public int TestCondition { get; set; }
public AddressDTO AddressDTO { get; set; }
}
public class AddressDTO
{
public int ID { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Zip { get; set; }
}
Configuration :
public class AutoMapperProfileConfig : Profile
{
public AutoMapperProfileConfig()
{
CreateMap<Student, StudentDTO>().ForMember(dest => dest.DOB, opt=>opt.Ignore())
.ForMember(x=>x.BG,opt=>opt.MapFrom(y=>y.BloodGroup))/*.AfterMap((src, dest) => dest.Name = "After MAP")*/
.ForMember(x=>x.TestCondition, opt=>opt.Condition(src => (src.TestCondition >= 100))
);
CreateMap<Address, AddressDTO>();
Execution :
Student student = new Student();
Address add = new Address();
add.Line1 = "abcd";
student.Address = add;
var studentLite = Mapper.Map<StudentDTO>(student);
Although studentDTO is getting mapped properly the AddressDTO is null.

You're mapping Student.Address to StudentDTO.AddressDTO. As the name of your target property has changed, AutoMapper doesn't know what to do with it. If you changed your propertyname in StudentDTO from AddressDTO into Address, Automapper should be able pick it up and map it.
An alternative solution would of course be to instruct AutoMapper explicitly to map Student.Address to StudentDTO.AddressDTO.

Related

Get All data from two tables in .net 5 web api?

Patient.cs //This is Patient Model Class
namespace HMS.Models
{
public class Patient
{
[Key]
public string Id { get; set; }
public string Name { get; set; }
public int age { get; set; }
public int Weight { get; set; }
public string Gender { get; set; }
public string Address { get; set; }
public string PhoneNo { get; set; }
public string Disease { get; set; }
[JsonIgnore]
public IList<DoctorPatient> DoctorPatients { get; set; }
public InPatient InPatients { get; set; }
public OutPatient OutPatients { get; set; }
}
}
InPatient.cs //This InPatient Model Class
namespace HMS.Models
{
public class InPatient
{
[ForeignKey("Patient")]
public string InPatientId { get; set; }
public string RoomNo { get; set; }
public DateTime DateOfAddmission { get; set; }
public DateTime DateOfDischarge { get; set; }
public int Advance { get; set; }
public string LabNo { get; set; }
public Patient Patient { get; set; }
}
}
Here Patient and InPatient Attribute have one-to-one relationship
ViewInPatient.cs
namespace HMS.Models
{
public class ViewInPatient
{
public string Name { get; set; }
public int age { get; set; }
public int Weight { get; set; }
public string Gender { get; set; }
public string Address { get; set; }
public string PhoneNo { get; set; }
public string Disease { get; set; }
public string RoomNo { get; set; }
public DateTime DateOfAddmission { get; set; }
public DateTime DateOfDischarge { get; set; }
public int Advance { get; set; }
public string LabNo { get; set; }
}
}
Here is my DbContext class
public class ApplicationDbContext:DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options):base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<DoctorPatient>()
.HasOne(x => x.Doctor)
.WithMany(dp => dp.DoctorPatients)
.HasForeignKey(di => di.DoctorId);
modelBuilder.Entity<DoctorPatient>()
.HasOne(y => y.Patient)
.WithMany(dp => dp.DoctorPatients)
.HasForeignKey(pi => pi.PatientId);
}
public DbSet<Patient> Patients { get; set; }
public DbSet<Doctor> Doctors { get; set; }
public DbSet<DoctorPatient> DoctorPatients { get; set; }
public DbSet<InPatient> InPatients { get; set; }
//public DbQuery<ViewInPatient> ViewInPatients { get; set; }
}
How to get all data of both Patients and InPatients Table like in ViewInPatient class? (I tried to create a view in sql server but in add table window it shows InPatient instead of InPatients and it return null value)
You can join both models in a Linq expression and return ViewInPatient list:
var ViewInPatient_set =
YourContext
.InPatients
.Select(i=> new ViewInPatient()
{
Name = i.Patient.Name,
// ...
RoomNo = i.RoomNo,
// ...
}
)
.ToList(); // <-- transform to list is optional

JSON DeserializeObject to Model without Key Name

I currently have JSON coming in as follows:
{"36879":[{"min_qty":1,"discount_type":"%","csp_price":10}],"57950":[{"min_qty":1,"discount_type":"flat","csp_price":650}]}
This contains a list of the following records
ProductId
MinQty
DiscountType
Price
I need to deserialize this into the following model:
public class CustomerSpecificPricing
{
string productId { get; set; }
public virtual List<CustomerSpecificPricingDetail> CustomerSpecificPricingDetails { get; set; }
}
public class CustomerSpecificPricingDetail
{
public string min_qty { get; set; }
public string discount_type { get; set; }
public string csp_price { get; set; }
}
The problem is that the "productId" of each record is missing the key name.
If I run my JSON through J2C, I get the following:
public class 36879 {
public int min_qty { get; set; }
public string discount_type { get; set; }
public int csp_price { get; set; }
}
public class 57950 {
public int min_qty { get; set; }
public string discount_type { get; set; }
public int csp_price { get; set; }
}
public class Root {
public List<_36879> _36879 { get; set; }
public List<_57950> _57950 { get; set; }
}
Which is obviously incorrect.
How would I deserialize my object correctly?
You would need to deserialize it into a dictionary first and then map it into the format you require after. Something like this should work:
var dict = JsonConvert.DeserializeObject<Dictionary<string, IEnumerable<CustomerSpecificPricingDetail>>>();
var result = dict.Select(kvp => new CustomerSpecificPricing { ProductId = Int32.Parse(kvp.Key), CustomerSpecificPricingDetails = kvp.Value });
Id also recommend you follow the conventional standards of naming. In this case properties in classes should be PascalCase,
e.g. your classes now become:
public class CustomerSpecificPricing
{
[JsonProperty("productId ")]
public string ProductId { get; set; }
public virtual List<CustomerSpecificPricingDetail> CustomerSpecificPricingDetails { get; set; }
}
and
public class CustomerSpecificPricingDetail
{
[JsonProperty("min_qty")]
public string MinQty { get; set; }
[JsonProperty("discount_type ")]
public string DiscountType { get; set; }
[JsonProperty("csp_price ")]
public string CspPrice { get; set; }
}

EF core 2.0, OwnsOne in TPH model classes

I have problem when I try to migrate my model in EF Core 2.0.
public class Profile
{
[Key]
public Guid Id { get; set; }
public Guid UserId { get; set; }
public ExternalUser User { get; set; }
}
public class OrganizationCustomerProfile : Profile
{
public string CompanyName { get; set; }
public Address LegalAddress { get; set; }
public Address ActualAddress { get; set; }
public BusinessRequisites Requisites { get; set; }
public string President { get; set; }
public IEnumerable<ContactPerson> ContactPerson { get; set; }
}
public class PersonCustomerProfile : Profile
{
public FullName Person { get; set; }
public Address Address { get; set; }
public string PhoneNumber { get; set; }
}
public class ContactPerson
{
[Key]
public Guid Id { get; set; }
public FullName Person { get; set; }
public string Rank { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public Guid ProfileId { get; set; }
public Profile Profile { get; set; }
}
Here I want to add complex datatypes Address and BusinessRequisites, which are:
public class BusinessRequisites
{
public string OGRN { get; set; }
public string INN { get; set; }
public string KPPCode { get; set; }
public string SettlementAccount { get; set; }
public string RCBIC { get; set; }
public string CorrespondentAccount { get; set; }
public string BankName { get; set; }
}
public class Address
{
public string FullAddress { get; set; }
public float Latitude { get; set; }
public float Longtitude { get; set; }
}
Code which I use for TPH binding:
public DbSet<Profile> UserProfiles { get; set; }
public DbSet<ContactPerson> ContactPerson { get; set; }
public DbSet<OrganizationCustomerProfile> OrganizationCustomerProfile { get; set; }
...
modelBuilder.Entity<Profile>().HasKey(u => u.Id);
modelBuilder.Entity<OrganizationCustomerProfile>().OwnsOne(e => e.ActualAddress);
modelBuilder.Entity<OrganizationCustomerProfile>().OwnsOne(e => e.LegalAddress);
modelBuilder.Entity<OrganizationCustomerProfile>().OwnsOne(e => e.Requisites);
But when I try to make a migration, I get an error:
"Cannot use table 'UserProfiles' for entity type
'OrganizationCustomerProfile.ActualAddress#Address' since it has a
relationship to a derived entity type 'OrganizationCustomerProfile'.
Either point the relationship to the base type 'Profile' or map
'OrganizationCustomerProfile.ActualAddress#Address' to a different
table."
So, what the reason of this error? Is it not possible to create hierarchy inheritance in EF Core 2.0?
Thank you!
It seems like this isn't supported at the moment:
https://github.com/aspnet/EntityFrameworkCore/issues/9888

Automapper many to many mapping confusion

I have many to many relationship tables such as "User & Notification & UserNotification" and their entities, view models also.
There is only a difference between ViewModel and Entity classes. HasRead property is inside NotificationViewModel. How Can I map this entities to view models? I could not achieve this for HasRead property.
What I did so far is,
Mapping Configuration:
CreateMap<Notification, NotificationViewModel>();
CreateMap<User, UserViewModel>().ForMember(dest => dest.Notifications, map => map.MapFrom(src => src.UserNotification.Select(x => x.Notification)));
Notification class:
public class Notification : IEntityBase
{
public Notification()
{
this.UserNotification = new HashSet<UserNotification>();
}
public int Id { get; set; }
public string Header { get; set; }
public string Content { get; set; }
public System.DateTime CreateTime { get; set; }
public bool Status { get; set; }
public virtual ICollection<UserNotification> UserNotification { get; set; }
}
User Class
public class User : IEntityBase
{
public User()
{
this.UserNotification = new HashSet<UserNotification>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public bool Status { get; set; }
public virtual ICollection<UserNotification> UserNotification { get; set; }
}
UserNotification class:
public class UserNotification : IEntityBase
{
public int Id { get; set; }
public int UserId { get; set; }
public int NotificationId { get; set; }
public bool HasRead { get; set; }
public virtual Notification Notification { get; set; }
public virtual User User { get; set; }
}
UserViewModel class
public class UserViewModel : IValidatableObject
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public bool Status { get; set; }
public IList<NotificationViewModel> Notifications { get; set; }
}
NotificationViewModel class
public class NotificationViewModel
{
public int Id { get; set; }
public string Header { get; set; }
public string Content { get; set; }
public System.DateTime CreateTime { get; set; }
public bool Status { get; set; }
public bool HasRead { get; set; } // this is the difference
}
In order to fix up the HasRead, maybe you can utilize the AfterMap(Action<TSource, TDestination> afterFunction) function. It's not as elegant as the rest of automapper, but it might work.
CreateMap<User, UserViewModel>()
.ForMember(dest => dest.Notifications, map => map.MapFrom(src => src.UserNotification.Select(x => x.Notification)))
.AfterMap((src, dest) =>
{
foreach (var notificationVM in dest.Notifications)
{
notificationVM.HasRead = src.UserNotification.Where(x => x.NotificationId == notificationVM.Id).Select(x => x.HasRead).FirstOrDefault();
}
});

AutoMapper Not Mapping... No Errors Thrown

Here's that I have in my WPF application:
public static class MappingCreator
{
public static void CreateMaps()
{
Mapper.CreateMap<SO.Services.Data.ServiceModel.Types.Customer, Customer>();
Mapper.CreateMap<List<SO.Services.Data.ServiceModel.Types.CustomerSearchResult>, List<CustomerSearchResult>>();
Mapper.AssertConfigurationIsValid();
}
}
CreateMaps() is called once on application start.
DTO:
namespace SO.Services.Data.ServiceModel.Types
{
[DataContract]
public class CustomerSearchResult
{
[DataMember]
public int CustomerId { get; set; }
[DataMember]
public string AccountType { get; set; }
[DataMember]
public string ShortName { get; set; }
[DataMember]
public string LegacyName { get; set; }
[DataMember]
public string LegacyContactName { get; set; }
[DataMember]
public string City { get; set; }
[DataMember]
public string StateAbbreviation { get; set; }
[DataMember]
public string Country { get; set; }
[DataMember]
public string PostalCode { get; set; }
}
}
Model:
namespace SO.Models
{
public class CustomerSearchResult : BindableBase
{
public int CustomerId { get; set; }
public string AccountType { get; set; }
public string ShortName { get; set; }
public string LegacyName { get; set; }
public string LegacyContactName { get; set; }
public string City { get; set; }
public string StateAbbreviation { get; set; }
public string Country { get; set; }
public string PostalCode { get; set; }
}
}
Extension method:
public static class DtoMappingExtensions
{
public static List<CustomerSearchResult> ToModels(this List<SO.Services.Data.ServiceModel.Types.CustomerSearchResult> customerSearchList)
{
return Mapper.Map<List<SO.Services.Data.ServiceModel.Types.CustomerSearchResult>, List<CustomerSearchResult>>(customerSearchList);
}
}
I call a servicestack service which returns a List<SO.Services.Data.ServiceModel.Types.CustomerSearchResult> ... when I use the ToModels extension method against it, it returns a List with 0 records, even though the source list had 25k or so records.
I'm stumped.
In your CreateMaps() you would specify the object mappings, not the list mapping.
Mapper.CreateMap<SO.Services.Data.ServiceModel.Types.CustomerSearchResult, CustomerSearchResult>().ReverseMap();
And then in your ToModels() you do
Mapper.Map<List<CustomerSearchResult>, List<SO.Services.Data.ServiceModel.Types.CustomerSearchResult>>(customerSearchList);
I think the problem is here in this line.
Mapper.CreateMap<List<SO.Services.Data.ServiceModel.Types.CustomerSearchResult>, List<CustomerSearchResult>>();
this statement has no need because the AutoMapper will handle the Mapping of the list automatically when you Map the Classes.
I think you should replace the previous statement with this one
Mapper.CreateMap<SO.Services.Data.ServiceModel.Types.CustomerSearchResult, CustomerSearchResult>();

Categories