How can I map the following:
public abstract class PersonBase
{
public Address Address { get; set; }
}
public class Address
{
public string AddressHome { get; set; }
public int PostalNumber { get; set; }
}
public class PersonEditVM : PersonBase
{
public int PersonId { get; set; }
}
public PersonEntity
{
public int PersonId { get; set; }
public string AddressHome { get; set; }
public int PostalNumber { get; set; }
}
I would like to map PersonEntity to PersonEditVM.
EDIT: Solved after a cup of coffee but it would be nice if it's a cleaner solution?.
Mapper.CreateMap<PersonEntity, PersonEditVM >()
.ForMember(d=>d.Address, s=>s.MapFrom(p=> new Address{
AddressHome = p.AddressHome,
PostalNumber = p.PostalNumber
}));
Here's one way to do it, which would split your Adress (which is correctly spelled Address by the way) mapping into another CreateMap call:
Mapper.CreateMap<PersonEntity, PersonEditVM>()
.ForMember(dest => dest.Adress, opt => opt.MapFrom(src => src));
Mapper.CreateMap<PersonEntity, Adress>()
.ForMember(dest => dest.AdressHome, opt => opt.MapFrom(src => src.AdressHome))
.ForMember(dest => dest.PostalNumber, opt => opt.MapFrom(src => src.PostalNumber));
Related
I have a model class
public class Brochure
{
[Key]
public int BrochureId { get; set; }
public string Name { get; set; }
public string TypeOfCover { get; set; }
public int NumberOfPages { get; set; }
public LibraryType Type { get; set; }
}
and View model
public class BrochureView
{
public int BrochureId { get; set; }
public string Name { get; set; }
public string TypeOfCover { get; set; }
public int NumberOfPages { get; set; }
}
in Brochure service I'm mapping model and viewmodel
public class BrochureService
{
private BrochureRepository _brochureRepository;
public BrochureService(DbContextOptions<LibraryContext> options)
{
_brochureRepository = new BrochureRepository(options);
}
public void Create(BrochureView brochureView)
{
var brochure = Mapper.Map<BrochureView, Brochure>(brochureView);
brochure.Type = LibraryType.Brochures;
_brochureRepository.Create(brochure);
}
}
Here is my automapper profiler:
public static class AutoMapperProfile
{
public static void RegisterMappings()
{
Mapper.Initialize(cfg =>
{
cfg.CreateMap<Brochure, BrochureView>();
cfg.CreateMap<BrochureView, Brochure>()
.ForMember(src => src.Type, opt => opt.Ignore());
});
}
}
but i have an exception:
Unmapped members were found.
AutoMapper cant map "Type" property. How can I resolve this problem?
To answer question from comments, that's the whole MappingProfile
public static class AutoMapperProfile
{
public static void RegisterMappings()
{
Mapper.Initialize(cfg =>
{
cfg.CreateMap<Book, BookView>();
cfg.CreateMap<BookView, Book>();
cfg.CreateMap<Magazine, MagazineView>();
cfg.CreateMap<MagazineView, Magazine>();
cfg.CreateMap<Brochure, BrochureView>();
cfg.CreateMap<BrochureView, Brochure>()
.ForMember(src => src.Type, opt => opt.Ignore());
cfg.CreateMap<PublicHouse, PublicHouseView>();
cfg.CreateMap<PublicHouseView, PublicHouse>();
cfg.CreateMap<Book, LibraryView>()
.ForMember(dest => dest.Name, opt => opt.ResolveUsing(src => src.Name))
.ForMember(dest => dest.Type, opt => opt.ResolveUsing(src => (LibraryType)src.Type));
cfg.CreateMap<Brochure, LibraryView>()
.ForMember(dest => dest.Name, opt => opt.ResolveUsing(src => src.Name))
.ForMember(dest => dest.Type, opt => opt.ResolveUsing(src => (LibraryType)src.Type));
cfg.CreateMap<Magazine, LibraryView>()
.ForMember(dest => dest.Name, opt => opt.ResolveUsing(src => src.Name))
.ForMember(dest => dest.Type, opt => opt.ResolveUsing(src => (LibraryType)src.Type));
});
}
}
In my MVC5 project I use automapper to map my viewmodels to my models. But it seems that I'm doing something wrong, because not all my properties are mapped.
Here is my View Model
public class PlanboardViewModel
{
public int Id { get; set; }
[Display(Name = "Titel")]
public string Title { get; set; }
[Display(Name = "Omschrijving")]
public string Description { get; set; }
[Display(Name = "Verzoektype")]
public int AbsenceTypeId { get; set; }
public List<PlanboardEventMapViewModel> EventMap { get; set; }
public List<PlanboardEventDetail> EventDetails { get; set; }
public List<PlanboardRequest> PlanboardRequests { get; set; }
}
I use a separate class for my profiles:
public class PlanboardMappingProfile : Profile
{
protected override void Configure()
{
//CreateMap<AbsenceType, AbsenceTypeViewModel>();
//.ForAllMembers(opt => opt.Condition(s => !s.IsSourceValueNull));
CreateMap<PlanboardViewModel, Planboard>()
.ForMember(dest => dest.CSVHPlanboardEventDetail, opt => opt.MapFrom(src => src.EventDetails))
.ForMember(dest => dest.CSVHPlanboardEventMap, opt => opt.MapFrom(src => src.EventMap))
.ForMember(dest => dest.CSVHPlanboardRequest, opt => opt.MapFrom(src => src.PlanboardRequests));
CreateMap<PlanboardEventMapViewModel, PlanboardEventMap>();
}
}
In my repository I have the following code:
public int Create(PlanboardViewModel planboardViewModel)
{
try {
// map the viewmodel to the planboard model
// Map the planboards to the view model
var config = new MapperConfiguration(cfg =>
{
cfg.AddProfile<PlanboardMappingProfile>();
cfg.CreateMap<PlanboardViewModel, Planboard>();
cfg.CreateMap<PlanboardEventMapViewModel, PlanboardEventMap>();
});
IMapper mapper = config.CreateMapper();
Planboard planboard = mapper.Map<Planboard>(planboardViewModel);
// Some more code here
When I submit the page and use the debugger, It shows that planboardViewModel has a list of values for PlanboardEventMapViewModel, PlanboardEventDetail, PlanboardRequest. The system is not telling me that there are any errors. When I check planboard after the mapping, it does not show any values for CSVHPlanboardEventDetail, CSVHPlanboardEventMap and CSVHPlanboardRequest.
EDIT
My PlanboardModel is created DB First EF6:
public partial class Planboard
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Planboard()
{
this.CSVHPlanboardEventDetail = new HashSet<PlanboardEventDetail>();
this.CSVHPlanboardEventMap = new HashSet<PlanboardEventMap>();
this.CSVHPlanboardRequest = new HashSet<PlanboardRequest>();
}
public int ID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public int StatusID { get; set; }
public Nullable<int> AbsenceTypeID { get; set; }
public virtual AbsenceType AbsenceTypes { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<PlanboardEventDetail> CSVHPlanboardEventDetail { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<PlanboardEventMap> CSVHPlanboardEventMap { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<PlanboardRequest> CSVHPlanboardRequest { get; set; }
}
I have 3 classes: Book, Genre, Authors
public class Book {
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string Description { get; set; }
public virtual int MfRaiting { get; set; }
public virtual int PageNumber { get; set; }
public virtual IList<Genre> Genres { get; set; }
public virtual Series Series { get; set; }
public virtual Mind Mind { get; set; }
public virtual IList<Author> Authors { get; set; }
public Book() {
Genres = new List<Genre>();
Authors = new List<Author>();
}
}
public class Genre {
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Book> Books { get; set; }
public Genre() {
Books=new List<Book>();
}
}
public class Author {
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string SurName { get; set; }
public virtual string Biography { get; set; }
public virtual IList<Book> Books { get; set; }
public Author() {
Books=new List<Book>();
}
}
And his classMaps
public class BookMap : ClassMap<Book> {
public BookMap() {
Id(x => x.Id);
Map(x => x.Name);
HasManyToMany(x => x.Genres)
.Cascade.All()
.Table("Book_Genre");
HasManyToMany(x => x.Authors)
.Cascade.All()
.Table("Book_Author");
References(x => x.Series);
HasOne(x => x.Mind).Constrained();
}
}
public class GenreMap : ClassMap<Genre> {
public GenreMap() {
Id(x => x.Id);
Map(x => x.Name);
HasManyToMany(x => x.Books)
.Cascade.All()
.Inverse()
.Table("Book_Genre");
}
}
public class AuthorMap : ClassMap<Author> {
public AuthorMap() {
Id(x => x.Id);
Map(x => x.Name);
Map(x => x.SurName);
Map(x => x.Biography);
HasManyToMany(x => x.Books)
.Cascade.All()
.Inverse()
.Table("Book_Author");
}
}
When i try write in code
var criteria = session.CreateCriteria();
criteria.CreateAlias("Genres", "genre", JoinType.LeftOuterJoin);
it works well, but when i do so
public ActionResult Index()
{
var criteria = session.CreateCriteria<Book>();
criteria.CreateAlias("Genres", "genre", JoinType.LeftOuterJoin);
criteria.CreateAlias("Authors", "author", JoinType.LeftOuterJoin);
criteria.SetResultTransformer(new DistinctRootEntityResultTransformer());
}
i see exception Cannot simultaneously fetch multiple bags. How can I get result of that criteria?
Thank
I resolve this problem! I replace IList on ISet, and replace new List<"Class"> on new HashSet<"Class">
I read this problem here.
http://developer-should-know.tumblr.com/post/118012584847/jpa-fetching-strategies Only one collection that is fetched using JOIN strategy can be of type List, other collection must be of type Set. Otherwise an exception will be thrown:
HibernateException: cannot simultaneously fetch multiple bags
I have an EF 4.1 model, two tables are generated PERSON and ADDRESS from my database.
//This method works
public void Update(IPerson person)
{
var personDb = _dataContext.PERSON.SingleOrDefault(x => x.ID == person.Id);
Mapper.Map<Person, PERSON>((Person)person, personDb);
_dataContext.SaveChanges();
}
But when I remove the .Ignore() in Automapper mapping, I get this exception :
The EntityCollection could not be initialized because the relationship manager for the object to which the EntityCollection belongs is already attached to an ObjectContext. The InitializeRelatedCollection method should only be called to initialize a new EntityCollection during deserialization of an object graph.
I'd like when I added an new address to the existing addresses save the person and address.
Any idea ?
Thanks,
public void AutomapperInit()
{
Mapper.CreateMap<Person, PERSON>()
.ForMember(x => x.ADDRESS, opt => opt.Ignore());
Mapper.CreateMap<PERSON, Person>()
.ForMember(dest => dest.Address, option => option.MapFrom(src => src.ADDRESS.Select(address => Mapper.Map<ADDRESS, Address>(address)).ToList()));
Mapper.CreateMap<Address, ADDRESS>();
Mapper.CreateMap<ADDRESS, Address>()
.ForMember(dest => dest.Rue, option => option.MapFrom(src => src.STREET));
}
public interface IPerson
{
int Id { get; set; }
string FirstName { get; set; }
string LastName { get; set; }
ICollection<IAddress> Address { get; set; }
}
public interface IAddress
{
string Rue { get; set; }
string Number { get; set; }
int PersonId { get; set; }
}
class Person : IPerson
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public ICollection<IAddress> Address { get; set; }
}
class Address : IAddress
{
public string Rue { get; set; }
public string Number { get; set; }
public int PersonId { get; set; }
}
Does
var personDb = Mapper.Map<Person, PERSON>((Person)person, personDb);
_dataContext.Attach(personDb);
_dataContext.SaveChanges();
give the results you expect, or am I misinterpreting your question?
I am trying to map information about the User to several dto's, but I'm getting null exceptions. Basically, the reason why I distributed the information among several classes is because there are common info that I need in several views. So this is what I ended up with:
User entity class
public class User
{
public int Id { get; set; }
public string Nickname { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public float Credits { get; set; }
public float PromotionalCredits { get; set; }
public string Telephone { get; set; }
public string Mobile { get; set; }
public double RatingAverage { get; set; }
public string ProfileImage { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
public virtual ICollection<Role> Roles { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
public virtual ICollection<Item> Items { get; set; }
public virtual ICollection<Bid> Bids { get; set; }
public virtual ICollection<CreditCard> CreditCard { get; set; }
public virtual ICollection<Message> ReceivedMessages { get; set; }
public virtual ICollection<Message> SentMessages { get; set; }
public virtual ICollection<Item> WatchList { get; set; }
public virtual ICollection<Rating> OwnRatings { get; set; }
public virtual ICollection<Rating> RatingsForOthers { get; set; }
}
DTO's and ViewModel calsses
public class UserInfoSummaryViewModel
{
public int Id { get; set; }
public string FullName { get; set; }
public UserDetailedStatus DetailedStatus { get; set; }
}
public class UserDetailedStatus
{
public float TotalCredits { get; set; }
public float Credits { get; set; }
public float PromotionalCredits { get; set; }
public BiddingAndItems BiddingAndItems { get; set; }
public int OngoingListings { get; set; }
public int NewMessages { get; set; }
public float Rating { get; set; }
public int NumberOfRatings { get; set; }
}
public class BiddingAndItems
{
public int TotalBids { get; set; }
public int WinningBids { get; set; }
public int AcquiredItems { get; set; }
public int ItemsAwaitingConfirmation { get; set; }
public List<ItemForUserBids> Items { get; set; }
}
Mappings inside AutoMapperBootStrapper class
Mapper.CreateMap<User, BiddingAndItems>()
.ForMember(m => m.TotalBids, o => o.MapFrom(s => s.TotalActiveBids()))
.ForMember(m=>m.ItemsAwaitingConfirmation, o=>o.MapFrom(s=>s.Items.Count(i=>i.IsAwaitingReceptionConfirmation().Equals(true))))
.ForMember(m=>m.AcquiredItems, o=>o.MapFrom(s=>s.AquiredItems().Count))
.ForMember(m => m.WinningBids,
o => o.MapFrom(s => s.Bids.Where(c => c.Item.CurrentHighestBidderId().Equals(s.Id))));
Mapper.CreateMap<User, UserDetailedStatus>()
.ForMember(m => m.NumberOfRatings, o => o.MapFrom(s => s.OwnRatings.Count()))
.ForMember(m => m.NewMessages, o => o.MapFrom(s => s.TotalUnreadMessages()))
.ForMember(m => m.OngoingListings, o => o.MapFrom(s => s.Items.Where(i => i.IsPublished())))
.ForMember(m => m.Rating, o => o.MapFrom(s => s.RatingAverage))
.ForMember(m => m.TotalCredits, o => o.MapFrom(s => s.TotalCredits()));
Mapper.CreateMap<User, UserInfoSummaryViewModel>();
Call to automapper inside UserController
public ActionResult Summary()
{
var user = _helper.GetUserFromSession();
var viewModel = Mapper.Map<User, UserInfoSummaryViewModel>(user);
return View(viewModel);
}
I thought because I have all the necessary mappings inside the bootstrapper this should, theoretically work, apparently I was wrong... How can I fix that?
UPDATE:
I got my mappings fixed and added a couple of value resolvers. Now I'm not getting a null reference exception but there seems to be something wrong because everytime I run the project it gets stuck and then the local server stops responding... Here's my code:
Mapper.CreateMap<User, BiddingAndItems>()
.ForMember(m => m.TotalBids, o => o.MapFrom(s => s.TotalActiveBids()))
.ForMember(m => m.ItemsAwaitingConfirmation,
o => o.MapFrom(s => s.Items.Count(i => i.IsAwaitingReceptionConfirmation().Equals(true))))
.ForMember(m => m.AcquiredItems, o => o.MapFrom(s => s.AquiredItems().Count))
.ForMember(m => m.WinningBids, o => o.ResolveUsing<WinningBidsResolver>())
.ForMember(m => m.Items, o => o.ResolveUsing<BiddingItemResolver>());
Mapper.CreateMap<User, UserDetailedStatus>()
.ForMember(m => m.NumberOfRatings, o => o.MapFrom(s => s.OwnRatings.Count()))
.ForMember(m => m.NewMessages, o => o.MapFrom(s => s.TotalUnreadMessages()))
.ForMember(m => m.OngoingListings, o => o.MapFrom(s => s.Items.Where(i => i.IsPublished()).Count()))
.ForMember(m => m.Rating, o => o.MapFrom(s => s.RatingAverage))
.ForMember(m=>m.BiddingAndItems, o => o.MapFrom(s=> s))
.ForMember(m => m.TotalCredits, o => o.MapFrom(s => s.TotalCredits()));
Mapper.CreateMap<User, UserInfoSummaryViewModel>()
.ForMember(m => m.DetailedStatus, o => o.MapFrom(s => s));
public class BiddingItemResolver : ValueResolver<User, List<ItemForUserBids>>
{
protected override List<ItemForUserBids> ResolveCore(User source)
{
var items = new List<ItemForUserBids>();
foreach (var bid in source.Bids)
{
var item = bid.Item;
var c = new ItemForUserBids
{
BidValue = bid.Amount,
Description = item.Description,
Id = item.Id,
ItemThumb = item.MainImageLink(),
Status = source.ItemBiddingStatus(item.Id),
TimeLeft = TimeUtility.TimeLeft(item.EndDate),
Title = item.Title
};
items.Add(c);
}
return items;
}
}
public class WinningBidsResolver : ValueResolver<User, int>
{
protected override int ResolveCore(User source)
{
return source.Bids.Where(c => c.Item.CurrentHighestBidderId().Equals(source.Id)).Count();
}
}
The problem is that I'm not getting any exceptions to give me any hints about what's going wrong... It just gets stuck! I suspect that my mappings are going into some sort of an infinite loops or something, but I am not sure what is happening exactly... Is there any way I could debug this problem?
Any help would be appreciated...
Without more information about the exception you receive I can only guess what could go wrong: I guess it's because you're using Linq on uninitialized collections in MapFrom. Try implementing a ValueResolver instead.