I have a small problem regarding mapping models of a external service.
The external service model:
public class Invoice
{
[...]
public int FeeId {get; set;}
public string FeeName {get; set;}
public int SubFeeId {get; set;}
public string SubFeeName {get; set;}
}
Trying to map to:
public class Invoice
{
[...]
public Fee Fee {get; set;}
public Fee SubFee {get; set;}
}
public class Fee
{
public int Id {get; set;}
public string Name {get; set;}
}
So I have my problem with the profile since I cannot a duplicate config because of different properties:
internal class InvoiceProfile : Profile
{
public InvoiceProfile()
{
CreateMap<data.Invoice, Invoice>()
[...]
.ForMember(dest => dest.Fee, opt => opt.MapFrom(src => src))
.ForMember(dest => dest.SubFee, opt => opt.MapFrom(src => src));
CreateMap<data.Invoice, Fee>()
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.FeeId))
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.FeeName));
CreateMap<data.Invoice, Fee>()
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.SubFeeId))
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.SubFeeName));
}
}
How can i do this type of mapping?
Related
I have a CarDto and Car domain object.
Car has list of Drivers.
public class Car
{
public int Id {get; set; }
public int Name {get; set; }
public ICollection<Driver> Drivers {get; set; }
}
public class CarVM
{
public int Id {get; set; }
public int Name {get; set; }
public string DriverBadge {get; set; }
public string[] Drivers {get; set; }
}
I'm trying to map this objects using AutoMapper
CreateMap<CarVM, Car>()
.ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.Name))
.ForMember(dest => dest.Drivers, opts => {
... how to map here?
})
All you have to do is map from string[] to List<>. Simply use the below
CreateMap<CarVM, Car>()
.ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.Name))
.ForMember(dest => dest.Drivers, opts => opts.MapFrom(s=> s.Drivers.ToList()))
});
More information - Automapper Lists & Arrays
I have a simple objects:
public class Project : Entity
{
public uint ProjectId { get; set; }
public virtual ICollection<Cabin> Cabins { get; set; }
}
public class Cabin : Entity
{
public IPAddress IpAddress { get; set; }
public int Port { get; set; }
public DateTime LastConnection { get; set; }
public byte ConnectionStatus { get; set; }
public byte TechnicalStatus { get; set; }
public Project Project { get; set; }
public int ProjectId { get; set; }
}
So mapping using auto mapper from one to another with some ignores would look like:
var mapperConfig = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Project, Project>()
.ForMember(source => source.Id, opt => opt.Ignore())
.ForMember(source => source.ProjectId, opt => opt.Ignore())
.ForMember(source => source.Cabins, opt => opt.MapFrom(cab => cab.cabins));
});
And it works it maps one project object to another, and ignores id and project id and maps collection.
But on that level, is it possible to set what properties from source.Cabins would be ignored?
For example i want to ignore ConnectionStatus, TechnicalStatus.
You could add a configuration mapping for Cabin entity and AutoMapper would look at these configurations before mapping Cabin entity.
cfg.CreateMap<Cabin, Cabin>()
.ForMember(source => source.ConnectionStatus, opt => opt.Ignore())
.ForMember(source => source.TechnicalStatus, opt => opt.Ignore());
Or you could use AfterMap event to define a default value for these properties.
public class MyProfile : Profile
{
protected override void Configure()
{
base.CreateMap<ViewModel, Domain>()
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
//.ForAllMembers(opt => opt.Ignore()) //returns void
.ReverseMap();
}
}
public class ViewModel
{
public int Id { get; set; }
}
public class Domain
{
public int Id { get; set; }
public string UserName {get; set;}
//public string ... { get; set;} //etc..
//...
}
Suppose I don't want to map UserName, and many other properties.
Can I do .ForAllMembers(...) to the mapping, in order to map any unmapped members?
Don't use that ForAllMembers thing, that looks like a version of this:
https://github.com/AutoMapper/AutoMapper/wiki/5.0-Upgrade-Guide#ignoreallnonexisting-extension
Instead, use the CreateMap overload that takes a MemberList enum:
CreateMap<ViewModel, Domain(MemberList.None)
I am using C# EF code-first. I have the following 2 classes:
public class Om_Currency
{
[Key]
public Int16 CurrencyID { get; set; }
public String CurrencySymbol { get; set; }
public Boolean IsActive { get; set; }
public Int32 CountryID { get; set; }
public virtual Om_Country Country { get; set; }
}
public class Om_Country
{
[Key]
public Int16 CountryID { get; set; }
public String CountryName { get; set; }
public Boolean IsActive { get; set; }
public Int32 CurrencyID { get; set; }
public virtual Om_Currency Currency { get; set; }
}
Now, I am trying to implement an 1-1 relationship between these 2 classes. So that I can get Currency details from Country and Country details can be fetched from Currency.
modelBuilder
.Entity<Om_Country>()
.HasOptional(f => f.Currency)
.WithRequired(s => s.Country);
modelBuilder
.Entity<Om_Currency>()
.HasOptional(f => f.Country)
.WithRequired(s => s.Currency);
But I get this error:
The navigation property 'Country' declared on type
'ObjectModel.Country.Om_Currency' has been configured with conflicting
multiplicities.
Am I doing something wrong?
This is the mapping class for Country:
public class CountryMap : EntityTypeConfiguration<Om_Country>
{
public CountryMap()
{
Property(x => x.CountryID)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(x => x.CountryName)
.IsRequired()
.HasMaxLength(100)
.HasColumnAnnotation
(
IndexAnnotation.AnnotationName,
new IndexAnnotation
(
new IndexAttribute("U_CountryName", 1) { IsUnique = true }
)
);
Property(x => x.IsActive).IsRequired();
Property(x => x.CurrencyID).IsRequired();
ToTable(clsCommon.tblCountry);
}
}
and this is the mapping class for Currency:
public class CurrencyMap : EntityTypeConfiguration<Om_Currency>
{
public CurrencyMap()
{
Property(x => x.CurrencyID)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(x => x.CurrencySymbol)
.IsRequired()
.IsVariableLength()
.HasMaxLength(50)
.HasColumnAnnotation
(
IndexAnnotation.AnnotationName,
new IndexAnnotation
(
new IndexAttribute("U_CurrencySymbol", 1) { IsUnique = true }
)
);
Property(x => x.IsActive).IsRequired();
Property(x => x.CountryID).IsRequired();
ToTable(clsCommon.tblCurrency);
}
}
I figured out the issue. I got the Solution from here
Instead of below
modelBuilder
.Entity<Om_Country>()
.HasOptional(f => f.Currency)
.WithRequired(s => s.Country);
modelBuilder
.Entity<Om_Currency>()
.HasOptional(f => f.Country)
.WithRequired(s => s.Currency);
It should be below
modelBuilder.Entity<Om_Country>()
.HasRequired(x => x.Currency).WithMany()
.HasForeignKey(x => x.CurrencyID).WillCascadeOnDelete(false);
modelBuilder.Entity<Om_Currency>()
.HasRequired(x => x.Country).WithMany()
.HasForeignKey(x => x.CountryID).WillCascadeOnDelete(false);
Apologies if this has been asked before, I'm not sure of the specific terms to ask.
A short example:
public class SignOffDetails
{
public int fUserID {get; set;}
public DateTime SignedAt {get; set;}
}
public class User
{
public int UserID {get; set;}
public string FullName {get; set;}
public Image Signature {get; set;}
}
public class MdlsCombined
{
public int UserID {get; set;}
public string FullName {get; set;}
public Image Signature {get; set;}
}
public void Program
{
Mapper.CreateMap<SignOffDetails, MdlsCombined>()
.ForMember(m => m.UserID, y => y.MapFrom(z => z.fUserID));
// Awesome
}
I know I can just map them individually, but is there a function to do the following that I haven't yet discovered?
Mapper.CreateMap<SignOffDetails, MdlsCombined>()
.Let(z => (User)Users.GetUser(z.fUserID))
.ForMember(m => m.UserID, y => y.MapFrom(z => z.fUserID))
.ForMember(m => m.FullName, y => y.MapFromLet(l => ((User)l).FullName))
.ForMember(m => m.Signature, y => y.MapFromLet(l => ((User)l).Signature));
I realize this is quite silly and kinda removes the whole point of procedural programming in the first place, but it's still a legit use imho.
The actual solution is to have two maps from SignOffDetails > MdlsCombined and User > MdlsCombined, but that ain't fluent ;)