I am using Automapper to transfer data from objectA to objectB
classe ObjectA
{
string Title;
string Summary;
}
classe ObjectB
{
string Title;
string Summary;
IAddress Address;
}
I created this kind of mapping between the two objects
AutoMapper.Mapper.CreateMap<IObectA, IObjectB>()
.ForMember(dest => dest.Title, src => src.MapFrom(s => s.Title))
.ForMember(dest => dest.Summary, src => src.MapFrom(s => s.Summary))
.ForMember(dest => dest.Address, src => src.Ignore())
I create my ObjectB and fill all its properties including Address
When I call the mapper, I was expecting it to override Title and Summary and ignore Address
ObjectB = Mapper.Map<IObjectA, IObjectB>(objectA);
Actually, it is throwing and exception for Address.
What am I doing wrong?
[UPDATE]
To express it differently, I have my objectB and I want to update part of it with data coming from ObjectA. When I say Ignore, I mean leave the data the way they already are
I found the solution.
I just discovered that Map method has an overloaded version that excepts a pre-instantiated destination object.
Thanks to this article
Mapper.Map<IObjectA, IObjectB>(objectA, ObjectB );
#JoDG, Thank you for your help
Related
For some reason AutoMapper gives me a list of the type I need, where all properties are 0 or null. When I debug on data I see my list with all object and properties containing data. But .Map() gives me a list with no data in the properties (but the correct amount of objects). I'm new to AutoMapper, but this does seem very weird. Any suggestions?
public static IMapper Initialize()
{
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<PlantSelectResult, IPlant>()
.ForMember(
dest => dest.description,
opt => opt.MapFrom(src => src.description));
});
return new Mapper(config);
}
And my DataProvider:
public IEnumerable<IPlant> GetPlants()
{
using (var dbCtx = new DataClasses1DataContext(_connectionString.String))
{
var data = dbCtx.PlantSelect().ToList();
return automapper.Map<List<PlantSelectResult>, IPlant[]>(data);
}
}
I didn't realize I had removed set; on the properties. Fixing the interfaces so they were settable fixed the problem.
I have a scenario that i have to pass source class as dynamic. I tried it with generic type class but its not working.
public virtual void MapAttributeFact<T>()
{
Mapper.CreateMap<T, DTO.TabRender.Attribute>()
.ForMember(dest => dest.IsMultiSelect, src => src.MapFrom(opt => opt.MultiSelect))
}
Please help me how to pass it as dynamic.
Thanks in advance
I have question about Automapper. This is my usecase:
I have these classes:
Bussiness:
public class Item
{
public NestedItem NestedItem{get;set;}
}
public class NestedItem
{
public string Name{get;set;}
}
ViewModel:
public class ItemViewModel
{
public string NestedItemName{get;set;}
}
When I want to map Item to ItemViewModel. Automapper map property NestedItem.Name to NestedItemName correctly.
But in the opposite way it doesn´t work. Mapping doesn´t change value of NestedItem.Name.
I've got a slightly contradictory answer to the link stated above, maybe I just go about my things the awkward way but I believe you can do it within one map. For example:
Mapper.CreateMap<ItemViewModel, Item>()
.ForMember(dest => dest.NestedItem, opt =>
opt.MapFrom(src => new NestedItem(src.NestedItemName));
Now of course this would require you to create a new constructor or add a blank constructor and use curly brackets.
I can't comment on performance as AutoMapper is a seriously complicated monster. However this should do the trick.
What does UseDestinationValue do?
I am asking because I have a base and inherited class, and for the base class, I would love to have AutoMapper take existing values for me.
Will it do that? (I have looked and the only examples I can see for UseDestinationValue involve lists. Is it only for lists?
could I do this:
PersonContract personContract = new PersonContract {Name = 'Dan'};
Person person = new Person {Name = "Bob"};
Mapper.CreateMap<PersonContract, Person>()
.ForMember(x=>x.Name, opt=>opt.UseDestinationValue());
person = Mapper.Map<PersonContract, Person>(personContract);
Console.WriteLine(person.Name);
and have the output be bob?
I wrote this whole question up and then thought, DUH! just run it and see.
It works as I had hoped.
This is the code I ended up with:
class Program
{
static void Main(string[] args)
{
PersonContract personContract = new PersonContract {NickName = "Dan"};
Person person = new Person {Name = "Robert", NickName = "Bob"};
Mapper.CreateMap<PersonContract, Person>()
.ForMember(x => x.Name, opt =>
{
opt.UseDestinationValue();
opt.Ignore();
});
Mapper.AssertConfigurationIsValid();
var personOut =
Mapper.Map<PersonContract, Person>(personContract, person);
Console.WriteLine(person.Name);
Console.WriteLine(person.NickName);
Console.WriteLine(personOut.Name);
Console.WriteLine(personOut.NickName);
Console.ReadLine();
}
}
internal class Person
{
public string Name { get; set; }
public string NickName { get; set; }
}
internal class PersonContract
{
public string NickName { get; set; }
}
The output was:
Robert
Dan
Robert
Dan
I was brought here having a similar question, but in regards to nested classes and keeping the destination value. I tried above in any way I could, but it did not work for me, it turns out you have to use UseDestinationValue on parent object as well. I am leaving this here in case anyone else has the same issue I did. It took me some time to get it working. I kept thinking the issue lies within AddressViewModel => Address mapping.
In BidderViewModel class, BidderAddress is of type AddressViewModel. I needed the Address ID to be preserved in situations where it is not null.
Mapper.CreateMap<BidderViewModel, Bidder>()
.ForMember(dest => dest.BidderAddress, opt=> opt.UseDestinationValue())
.ForMember(dest => dest.ID, opt => opt.UseDestinationValue());
Mapper.CreateMap<AddressViewModel, Address>()
.ForMember(dest => dest.ID, opt => { opt.UseDestinationValue(); opt.Ignore(); });
Use (where viewModel is of type BidderViewModel as returned by the View in MVC):
Bidder bidder = Mapper.Map<BidderViewModel, Bidder>(viewModel, currentBid.Bidder)
I got the following problem:
I got a Entity (from EF Code First) that looks like this.
public class Movie {
public ICollection<AudioQuality> AudioQualities {get;set;}
}
public class AudioQuality {
public Guid Id{get;set;}
public int Channels{get;set;}
}
//Automapper Init:
Mapper.CreateMap<Movie, MovieDto>();
Mapper.CreateMap<MovieDto, Movie>().ForMember(dest => dest.AudioQualities,opt => opt.UseDestinationValue());
Mapper.CreateMap<VideoQuality, VideoQualityDto>();
Mapper.CreateMap<AudioQuality, AudioQaulityDto>();
Mapper.CreateMap<VideoQualityDto, VideoQuality>();
Mapper.CreateMap<AudioQaulityDto, AudioQuality>()
.ForMember(dest => dest.Movies, opt => opt.Ignore());
And I also got a DTO that looks similar!
I map from the DTO to the Entity like so:
//Get Movie from DB and than update it with the dto values
Movie movieFromDb = GetMoviesWithAllChilds().Single(mov => mov.Id == movieDto.Id);
//use update the entity from db with dto
Mapper.Map(movieDto, movieFromDb);
Now the problem is, that Automapper creates a new AudioQuality-Object for each item in AudioQualities.
But I want that he just copies the values from the AudioQuality-Objects from the DTO to the Entities instead of creating new Objects with the values from the DTO.
Is there a way to do that??
FYI: UseDestinationValue works on the collection (so the collection is not copied).
br rene_r
Get your entity from the context and pass it in to the Mapper function as the second parameter. The updates will eb applied from the source to the destination.
mapper.Map<SourceType, DestType>(source, dest);