AutoMapper how to flatten nested lists - automapper

I am trying to map out some nested lists into a list of flattened structures using automapper.
Currently I am able to map the correct number of credits with names but I can not get the role and role description to map across.
I am trying to get a flattened list like this.
John Smith, Actor, Dr Evil
John Smith, Writer, null
Frank Brown, Director, null
Joe Green, Actor, Henchman
Here is a cutdown version of my domain model, view model and mapping.
What am I doing wrong with the Domain.Credit to ViewModel.Credit mapping?
//Domain Model
public class Talent
{
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual IList<Credit> Credits { get; set; }
}
public class Credit
{
public virtual Role Role { get; set; }
public virtual string Subtitle { get; set; }
}
public class Role
{
public virtual string Title { get; set; }
}
//View Model
public class EpisodeViewModel
{
public IList<Credit> Credits { get; set; }
public class Credit
{
public string Name { get; set; }
public string Role { get; set; }
public string RoleDescription { get; set; }
}
}
//Mappings
Mapper.CreateMap<Episode, EpisodeViewModel>()
.ForMember(destination => destination.Credits, options => options.MapFrom(source => source.Talent));
Mapper.CreateMap<Talent, Credit>()
.ForMember(destination => destination.Name, options => options.MapFrom(source => string.Format("{0} {1}", source.FirstName, source.LastName)));
Mapper.CreateMap<Domain.Credit, Credit>()
.ForMember(destination => destination.Role, options => options.MapFrom(source => source.Role.Title))
.ForMember(destination => destination.RoleDescription, options => options.MapFrom(source => source.Subtitle));

Related

how do i use AutoMapper in ICollation<> Fields

when i use AutoMapper for mapping my ViewModels and get All News, thrown error for me.
Errors...
The following property on Mosque.Core.ViewModels.CategoryViewModel cannot be mapped:
Categories
Add a custom mapping expression, ignore, add a custom resolver, or modify the destination type Mosque.Core.ViewModels.CategoryViewModel.
please help me, thank you
//Models
public class News
{
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public virtual User User { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<News> News { get; set; }
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<News> News { get; set; }
}
//ViewModels
public class NewsViewModel
{
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<CategoryViewModel> Categories { get; set; }
public virtual UserViewModel User { get; set; }
}
public class CategoryViewModel
{
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<NewsViewModel> News { get; set; }
}
public class UserViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<NewsViewModel> News { get; set; }
}
how do i use for select All News?
--Update1--
I used onion architecture in the project and i installed AutoMapper in the Service layer and i want get all news from repository and fill into ViewModels and pass to the UI.
my code in service layer is...
public List<NewsViewModel> GetAll()
{
Mapper.CreateMap<News, NewsViewModel>()
.ForMember(dest => dest.Categories, src => src.MapFrom(p => p.Categories))
.ForMember(dest => dest.User, src => src.MapFrom(p => p.User));
Mapper.AssertConfigurationIsValid();
var viewModels = new List<NewsViewModel>();
foreach (var item in _newsRepository.GetAll())
{
var viewModel = Mapper.Map<News, NewsViewModel>(item);
viewModels.Add(viewModel);
}
return viewModels;
}
You don't seem to have created maps for Catagory and User.
Add the following maps:
Mapper.CreateMap<User, UserViewModel>();
Mapper.CreateMap<Category, CategoryViewModel>();
By the way, why are you creating the maps inside the GetAll method? You can create the maps once, usually at application startup.

Entity Framework - Update complex entities

I'm using EF5.0 (database first) and trying to Update "Company" entity which is a complex type, it contains "Address" entity as navigation property.
I receive a Company DTO object from UI and I map it, using AutoMapper, to Entity object and call objectContext.Save() for saving.
Problem am facing is, "Company" entity values are getting saved but not the "Address" entity. Below are the each object details-
public class CompanyDto
{
public int Id { get; set; }
public string Name { get; set; }
public AddressDto Address { get; set; }
}
with AddressDto as -
public class AddressDto : IDto
{
public int Id { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string PostCode { get; set; }
}
Company Entity (generated by EF - database first)
public partial class tblCompany
{
public tblCompany()
{
this.tblAddresses = new HashSet<tblAddress>();
}
public int ID { get; set; }
public string CompanyName { get; set; }
public virtual ICollection<tblAddress> tblAddresses { get; set; } //navigation property
}
with Address entity is as follows -
public partial class tblAddress
{
public int ID { get; set; }
public int CaseID { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string City { get; set; }
public string County { get; set; }
public string PostCode { get; set; }
public virtual tblCase tblCase { get; set; }
}
AutoMapper mapping configuration for converting from DTO to entity
Mapper.CreateMap<CompanyDto, tblCase>()
.ForMember(x => x.ID, opt => opt.MapFrom(cd => cd.Id))
.ForMember(x => x.CompanyName, opt => opt.MapFrom(cd => cd.Name))
.AfterMap((s, d) => d.tblAddresses.Add(new tblAddress
{
AddressLine1 = s.Address.Street,
CaseID = s.Id,
City = s.Address.City,
PostCode = s.Address.PostCode
}));
public void Update(CompanyDto company)
{
//TO DO: check if AutoMapper could map address as well.
var companyDao = Mapper.Map<CompanyDto, tblCase>(company);
_companyRepository.Update(companyDao);
_unitOfWork.Save();
}
Thanks in advance
Sai

map collection of model to viewmodel with automapper

iwant to map collection of model to viewmodel with automapper
this is my code
public class LanguageViewModel
{
public string Name { get; set; }
public IList<Word> Categories { set; get; }
public IList<string> PictureURL { set; get; }
}
and this my model
public class Word : BaseFieldsTables
{
public string Text { get; set; }
public virtual Category Category { get; set; }
public int CategoryID { get; set; }
public virtual Language Language { get; set; }
public int LanguageID { get; set; }
public virtual ICollection<Picture> Pictures { get; set; }
[InverseProperty("MainWord")]
public virtual ICollection<RelationshipBetweenWords> MainWords { get; set; }
[InverseProperty("RelatedWord")]
public virtual ICollection<RelationshipBetweenWords> RelatedWords { get; set; }
}
Fot his example you start with top domain model and map it with inner collections called Nested mappings.
mapper.CreateMap<Word , LanguageViewModel>()
.ForMember(dest => dest.Name, src => src.MapFrom(s => s.Text));
For inner collections within Word domain model, you need to define separate mappings for Categories and Pictures.
mapper.CreateMap<Picture, PictureModel>()
.ForMember(dest => dest.PictureURL , src => src.MapFrom(x => x.Picture.Urltext));
mapper.CreateMap<Category, CategoryModel>()
.ForMember(dest => dest.CategoryId, src => src.MapFrom(x => x.Category.CategoryInt));
and for all remaining inner collections you need to define mapping to make it work

Entity Framework 4.0 CTP5 Many to Many relation ship with a help table?

i have a question about EF4 again :) sorry i can't find any thing on the net.
The question is i am using CTP5 Code Only to map (many to many), how do i do it???
But i am doing the old fashion way, i mean i have three tables:
Users
Companies.
UsersToCompanies -> (UserId, CompanyId)
How do i map this, it will be really appreciated if you would show me the code example to it,
from POCO's to Mapping.
This is the error i receive...
This is my entities
public class User
{
public int UserId { get; set; }
public int? UserRoleId { get; set; }
public string UserName { get; set; }
public string UserPassword { get; set; }
public DateTime InsertDate { get; set; }
public virtual UserRole UserRole { get; set; }
//this is my many to many prop
public virtual ICollection<Company> Companies { get; set; }
}
public class Company
{
public int CompanyId { get; set; }
public string CompanyNameHe { get; set; }
public string CompanyNameEn { get; set; }
public string CompanyParent { get; set; }
public DateTime InsertDate { get; set; }
//this is my many to many prop
public virtual ICollection<User> Users { get; set; }
}
/*relationship map*/
public class UsersCompanies
{
public int Id { get; set; }
public int UserId { get; set; }
public int CompanyId { get; set; }
}
//mapping
public class CompanyMap : BaseConfig<Company>
{
public CompanyMap()
{
/*Identity*/
HasKey(c => c.CompanyId);
Property(c => c.CompanyId).HasDatabaseGenerationOption(DatabaseGenerationOption.Identity).HasColumnName("COMPANY_ID");
/*Have default values*/
Property(c => c.InsertDate).HasDatabaseGenerationOption(DatabaseGenerationOption.Computed).HasColumnName("INSERT_DATE");
/*simple scalars*/
Property(c => c.CompanyNameHe).HasMaxLength(32).IsRequired().HasColumnName("COMPANY_NAME_HE");
Property(c => c.CompanyNameEn).HasMaxLength(32).IsRequired().HasColumnName("COMPANY_NAME_EN");
Property(c => c.CompanyParent).HasMaxLength(32).IsRequired().HasColumnName("COMPANY_PARENT");
ToTable("CMS_COMPANY", "GMATEST");
}
}
public class UserMap : BaseConfig<User>
{
public UserMap()
{
/*Identity*/
HasKey(c => c.UserId);
Property(c => c.UserId).HasDatabaseGenerationOption(DatabaseGenerationOption.Identity).HasColumnName("USER_ID");
/*Have default values*/
Property(c => c.InsertDate).HasDatabaseGenerationOption(DatabaseGenerationOption.Computed).HasColumnName("INSERT_DATE");
/*simple scalars*/
Property(c => c.UserName).HasMaxLength(25).IsRequired().HasColumnName("USER_NAME");
Property(c => c.UserPassword).HasMaxLength(25).IsRequired().HasColumnName("USER_PASSWORD");
Property(c => c.UserRoleId).IsRequired().HasColumnName("USER_ROLE_ID");
/*relationship*/
HasRequired(u => u.UserRole).WithMany().HasForeignKey(t => t.UserRoleId);
HasMany(p => p.Companies).WithMany(c => c.Users).Map(mc =>
{
mc.ToTable("UsersCompanies");
mc.MapLeftKey(p => p.UserId, "CompanyId");
mc.MapRightKey(c => c.CompanyId, "UserId");
});
ToTable("CMS_USERS", "GMATEST");
}
}
public class UsersCompaniesMap : BaseConfig<UsersCompanies>
{
public UsersCompaniesMap()
{
/*Identity*/
HasKey(k => k.Id);
Property(c => c.Id).HasDatabaseGenerationOption(DatabaseGenerationOption.Identity).HasColumnName("ID");
Property(c => c.UserId).IsRequired().HasColumnName("USER_ID");
Property(c => c.CompanyId).IsRequired().HasColumnName("COMPANY_ID");
ToTable("CMS_USERS_TO_COMPANIES", "GMATEST");
}
}
Here's the error I get:
'((new
System.Linq.SystemCore_EnumerableDebugView(ctx.FindAll())).Items[0]).Companies'
threw an exception of type
'System.Data.EntityCommandExecutionException'
Inner exception: ORA-00942: table or
view does not exist
You do not really need 3 tables to perform the mapping. You could simply do the following:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Company> Companies { get; set; }
}
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<User> Users { get; set; }
}
And this should do it. As long as you have a virtual ICollection referencing the other entity in both POCO's, CTP5's conventions should take care of everything for you. On the other hand, if you prefer doing it manually using the Fluent API, then check this blog by the ADO.NET team (scroll a little down to the many-to-many relationship section)
The answer for my problem, i have to say many thanks to you all, but Andrey from Devart,
have given me the solution, it's simple.
First off all i have to have, three tables Companies, Users, UsersCompanies/
Second off all i have to map the tables to original names of tables example:
my users table called in Db like that: CMS_USERS i have to map it with original name.
this is the example that i use and it's really works.
HasMany(c => c.Companies)
.WithMany(u => u.Users)
.Map(mc =>
{
mc.ToTable("CMS_USERS_TO_COMPANIES", "GMATEST");
mc.MapLeftKey(c => c.UserId, "USER_ID");
mc.MapRightKey(u => u.CompanyId, "COMPANY_ID");
});
Thank you all.

How do I convert a list of objects to a list of integers using AutoMapper?

I have a Student object:
public class Student
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
And a Classroom object:
public class Classroom
{
public List<Student> Students { get; set; }
}
I want to use AutoMapper to convert the list of students to a list of student IDs:
public class ClassroomDTO
{
public List<int> StudentIds { get; set; }
}
How do I configure AutoMapper to do this conversion?
Answer:
To expand on my question and Jimmy's answer, this is what I ended up doing:
Mapper.CreateMap<Student, int>().ConvertUsing(x => x.Id);
Mapper.CreateMap<Classroom, ClassroomDTO>()
.ForMember(x => x.StudentIds, y => y.MapFrom(z => z.Students));
AutoMapper was smart enough to do the rest.
You'll need a custom type converter:
Mapper.CreateMap<Student, int>().ConvertUsing(src => src.Id);

Resources