The project I am working on use NHibernate, AutoMapper and Fluent. All I need to do is read the XML file and enter the data into database. But there is a problem I am facing. when I try to map the Source and Destination I get the error which I have mentioned in the title.
Below is my code:
public partial class Language
{
public string languageIdField;
public string languageNameField;
}
public partial class Person
{
public int personIdField;
public string firstNameField;
public string lastNameField;
public int stateField;
public int enableEmailField;
public int attestPersonLockedField;
public string emailAddressField;
public string languageId;
}
I am creating above classes with xsd2code tool.But I have simplified it here.
Model classes are:
public class Person
{
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual string EmailAddress {get; set;}
.....
public int state {get; set;}
public virtual User User { get; set; }
public virtual Language language { get; set; }
}
public class Language
{
public virtual string LanguageId { get; set; }
public virtual string LanguageName { get; set; }
public virtual IList<Person> Persons { get; set; }
}
And this is how I map them with AutoMapper:
AutoMapper.Mapper.CreateMap<Language, Models.Language>();
AutoMapper.Mapper.CreateMap<Person, Models.Person>();
And that's how I am reading and trying to save the data:
object id = null;
foreach (var item in templateData.Languages)
{
id = save<Dicom.Expense.Models.Language>(item); // this will return the language id
}
Person person = new Person();
person.Emailaddress = templatedata.Person.EmailAddress;
....
person.languageId = id.ToString();
save<Dicom.Expense.Models.Person>(person);
private void save<TModel>(object templateObject)
{
var dbModel = AutoMapper.Mapper.Map<TModel>(templateObject);
repository.Save<object>(dbModel);
}
When I try to save the Person information I get the error:
could not execute batch command.[SQL: SQL not available]
Cannot insert the value NULL into column 'fkLanguageID
And this is because the Person table have the language ID as a foreign key in it. Now I do not know what changes I need to do so that Person source and destination map properly and save the data into database.
EDIT:
I have realized that I need to change the Person.languageId value into PersonModel.Language object so that NHibernate can read it and map it. Is it possible to use Customer Resolver or Type Converter to achieve this?
This is what I am trying to do:
AutoMapper.Mapper.CreateMap<Person, Models.Person>().ForMember(dest => dest.Language, opt => opt.ResolveUsing<CustomResolver>());
public class CustomResolver : ValueResolver<Person, Models.Language>
{
public Dicom.Expense.Models.Language ResolveCore(Person source)
{
?????
}
}
I solved the problem by creating a Resolver which AutoMapper provide for complex mapping. While creating a mapping I told the mapper to resolve the Destination Language with Source Language ID by resolving it into an object of type Language.
Below is my code;
AutoMapper.Mapper.CreateMap<Person, Models.Person>()
.ForMember(x => x.Language, opt => opt.ResolveUsing(new LanguageCodeResolver(loadRepository)).FromMember(x => x.LanguageId));
public class LanguageCodeResolver : ValueResolver<string, Dicom.Expense.Models.Language>
{
private IDatabaseLoadRepository loadRepository;
public LanguageCodeResolver(IDatabaseLoadRepository loadRepository)
{
this.loadRepository = loadRepository;
}
protected override Models.Language ResolveCore(string languageCode)
{
return loadRepository.FindOne<Models.Language>(x => x.LanguageId == languageCode);
}
}
Related
I am using the official C# MongoDb strongly typed driver version 2.8.0 to interact with MongoDB.
Consider the following classes:
public class Author {
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string BirthDate { get; set; }
public string ScientificDegree { get; set; }
}
public class Book
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
public string AuthorId {get; set;}
public string Title { get; set; }
public int PublishYear { get; set; }
public string Content { get; set; }
public bool IsVerified { get; set; }
public int DownloadCount {get; set; }
}
How to join (one to one) the two collections by the Id field in the author document and the AuthorId field in the Book document without using Linq and by using the lookup operator and the aggregation framwork.
If you use the peek definition of Visual Studio, it will show what Lookup to expect, as shown in the image below, surrounded with red.
The first Lookup is an extension of the IMongoCollection. It executes in the context of the collection and requires a foreign key collection as the first parameter, then the local field on which relation is established, the foreign field that composes the relation, and finally the result type. Unfortunately, the result type cannot be an anonymous type (or I did not discover how to be anonymous?). As always is expected that from the foreign collection will be returned more than one element, so, the operator always expects an array to be returned.
In your case, the result will be as shown in the snippet below. You should create 'LookedUpBooks' class as well.
var result = await collBooks.Aggregate()
.Lookup<Books, Authors, LookedUpBooks>(collAuthors,
x => x.AuthorId,
y => y.Id,
y => y.LastName
).ToListAsync();
public class LookedUpBooks
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
public string Title { get; set; }
// Add more properties as you need
public IEnumerable<Authors> InnerAuthors { get; set; }
}
See more on How to Program with MongoDB Using the .NET Driver
you can do one-to-one, one-to-many, many-to-many relationships quite easily with the MongoDB.Entities wrapper library. the following is how you do one-to-one relationships with two different collections.
using System.Linq;
using MongoDB.Entities;
namespace Library
{
public class Author : Entity
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Book : Entity
{
public string Title { get; set; }
public One<Author> MainAuthor { get; set; } // one-to-one relationship
}
class Program
{
static void Main(string[] args)
{
new DB("library");
var author1 = new Author
{
FirstName = "Eckhart",
LastName = "Tolle"
};
author1.Save();
var book1 = new Book
{
Title = "The Power Of Now",
MainAuthor = author1.ToReference()
};
book1.Save();
var powerOfNow = DB.Collection<Book>()
.Where(b => b.Title.Contains("Now"))
.FirstOrDefault();
var eckhartTolle = powerOfNow.MainAuthor.ToEntity();
}
}
}
I am working with Entity Framework 6.
I am working with 2 classes:
public partial class StateProvince
{
public StateProvince()
{
Addresses = new HashSet<Address>();
}
public int StateProvinceID { get; set; }
public string StateProvinceCode { get; set; }
public string CountryRegionCode { get; set; }
public bool IsOnlyStateProvinceFlag { get; set; }
public string Name { get; set; }
public int TerritoryID { get; set; }
public Guid rowguid { get; set; }
public DateTime ModifiedDate { get; set; }
public ICollection<Address> Addresses { get; set; }
public CountryRegion CountryRegion { get; set; }
}
public partial class CountryRegion
{
public CountryRegion()
{
StateProvinces = new HashSet<StateProvinceTlb>();
}
public string CountryRegionCode { get; set; }
public string Name { get; set; }
public DateTime ModifiedDate { get; set; }
public virtual ICollection<StateProvince> StateProvinces { get; set;}
}
I would like to be able to run a query that would return a list of StateProvince, but also include the name from CountryRegion. The idea is that on an edit screen, the user will select, or edit the CountryRegionCode, but the Name will display beside it in a none editable field just for reference.
I tried adding property as a none mapped field to StateProvince and referencing the property on CountryRegion, like below:
[NotMapped]
public string CountryName
{
get{ return CountryRegion.Name;}
}
but the problem with this is the CountryRegion has to be loaded in order for that to work, and my goal is to not have to load the entire CountryRegion object.
I've also tried to set it in my query like this:
List<StateProvince> statP = context.StateProvinces.Select(s => new StateProvince() {s, CountryName = context.CountryRegions.Where(x => x.CountryRegionCode == s.CountryRegionCode).Select(x => x.Name).FirstOrDefault() }).ToList();
but this doesn't work because the object returned is comprised of a StateProvince object and a separate CountryName property.
I've even tried setting each of the fields individually like:
List<StateProvince> statP = context.StateProvinces.Select(s => new StateProvince() { Name = s.Name, TerritoryID = s.TerritoryID, rowguid = s.rowguid, ModifiedDate = s.ModifiedDate, Addresses=s.Addresses, CountryRegion=s.CountryRegion, CountryName = context.CountryRegions.Where(x => x.CountryRegionCode == s.CountryRegionCode).Select(x => x.Name).FirstOrDefault() }).ToList();
But this again causes the entire CountryRegion object to load, and if I leave those properties out, an exception is thrown. Also, for larger entities this will be hard to maintain.
The TLDR; version of this: Is there a way in Entity Frameworks to have a class mapped to one table, but have a property on that class that references a property on another table without having to retrieve everything on the child table?
I've searched and searched and can't really find much covering this specific kinda of scenario. I'm fairly new to Entity Framework, and I feel like I'm missing something obvious. Any help would be greatly appreciated!!
SOLUTION
This is what I've come up with to solve the issue.
First, I split the CountryRegion table into two separate classes
public partial class CountryRegionHeader
{
public CountryRegionHeader()
{
StateProvinces = new HashSet<StateProvinceTlb>();
}
public string CountryRegionCode { get; set; }
public string Name { get; set; }
}
public partial class CountryRegionDetail
{
public CountryRegionDetail()
{
StateProvinces = new HashSet<StateProvinceTlb>();
}
public string CountryRegionCode { get; set; }
public DateTime ModifiedDate { get; set; }
public virtual ICollection<StateProvince> StateProvinces { get; set;}
public virtual CountryRegion CountryRegion {get;set;}
}
I then add the properties for the new classes to my StateProvince class
[ForeignKey("CountryRegionCode)]
public CountryRegionHeader CountryRegionHeader {get;set;}
[ForeignKey("CountryRegionCode)]
public CountryRegionDetail CountryRegionDetail {get;set;}
I then add the DBSets to my model context for CountryRegionHeader and CountryRegionDetail and tie them together using the fluent API in the OnModelCreating method
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<CountryRegionHeader>()
.HasRequired(e => e.CountryRegionDetail)
.WithRequiredPrincipal();
}
In addition to this, I've created another class just called CountryRegion which has all of the properties from both the Header and Detail as well as the Header and Detail object themselves. The properties actually point back to the header and detail. This really isn't necessary, but it makes the code cleaner and easier to use. Also, when sending the data down to a web client I can just serialize the CountryRegion object and exclude the Header and Detail object. So basically my CountryRegion class looks like this:
public Class CountryRegion
{
public CountryRegionHeader Header;
public CountryRegionDetail Detail;
public CountryRegionCode
{
//need some special logic here for the key since both Header or
//Detail share the primary key and both may not be loaded
get
{
if (Header != null)
return Header.CountryRegionCode;
else
return Detail.CountryRegionCode;
}
set
{
if (Header != null) Header.CountryRegionCode = value;
if (Detail != null) Detail.CountryRegionCode = value;
}
}
public string Name
{
get
{
return Header.Name;
}
set
{
Header.Name = value;
}
}
public DateTime ModifiedDate
{
get
{
return Detail.ModifiedDate ;
}
set
{
Detail.ModifiedDate = value;
}
}
public virtual ICollection<StateProvince> StateProvinces
{
get
{
return Detail.StateProvinces ;
}
set
{
Detail.StateProvinces = value;
}
}
}
So, Now When I query I can do something like:
List<StateProvince> query = db.StateProvince.Include(o=>o.CountryRegionHeader).ToList();
And I only retrieve the data I need without retrieving the entire CountryRegion record
Also, If I'm working with just the CountryRegion, I can query like this:
List<CountryRegion> query = (from a in db.CountryRegionHeader join b in db.CountryRegionDetail on a.CountryRegionCode equals b.CountryRegionCode select new Employee(){Header = a, Detail = b}).ToList();
SOLUTION
This is what I've come up with to solve the issue.
First, I split the CountryRegion table into two separate classes
public partial class CountryRegionHeader
{
public CountryRegionHeader()
{
StateProvinces = new HashSet<StateProvinceTlb>();
}
public string CountryRegionCode { get; set; }
public string Name { get; set; }
}
public partial class CountryRegionDetail
{
public CountryRegionDetail()
{
StateProvinces = new HashSet<StateProvinceTlb>();
}
public string CountryRegionCode { get; set; }
public DateTime ModifiedDate { get; set; }
public virtual ICollection<StateProvince> StateProvinces { get; set;}
pubic virtual CountryRegion CountryRegion {get;set;}
}
I then add the properties for the new classes to my StateProvince class
[ForeignKey("CountryRegionCode)]
public CountryRegionHeader CountryRegionHeader {get;set;}
[ForeignKey("CountryRegionCode)]
public CountryRegionDetail CountryRegionDetail {get;set;}
I then add the DBSets to my model context for CountryRegionHeader and CountryRegionDetail and tie them together using the fluent API in the OnModelCreating method
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<CountryRegionHeader>()
.HasRequired(e => e.CountryRegionDetail)
.WithRequiredPrincipal();
}
In addition to this, I've created another class just called CountryRegion which has all of the properties from both the Header and Detail as well as the Header and Detail object themselves. The properties actually point back to the header and detail. This really isn't necessary, but it makes the code cleaner and easier to use. Also, when sending the data down to a web client I can just serialize the CountryRegion object and exclude the Header and Detail object. So basically my CountryRegion class looks like this:
public Class CountryRegion
{
public CountryRegionHeader Header;
public CountryRegionDetail Detail;
public CountryRegionCode
{
//need some special logic here for the key since both Header or
//Detail share the primary key and both may not be loaded
get
{
if (Header != null)
return Header.CountryRegionCode;
else
return Detail.CountryRegionCode;
}
set
{
if (Header != null) Header.CountryRegionCode = value;
if (Detail != null) Detail.CountryRegionCode = value;
}
}
public string Name
{
get
{
return Header.Name;
}
set
{
Header.Name = value;
}
}
public DateTime ModifiedDate
{
get
{
return Detail.ModifiedDate ;
}
set
{
Detail.ModifiedDate = value;
}
}
public virtual ICollection<StateProvince> StateProvinces
{
get
{
return Detail.StateProvinces ;
}
set
{
Detail.StateProvinces = value;
}
}
}
So, Now When I query I can do something like:
List<StateProvince> query = db.StateProvince.Include(o=>o.CountryRegionHeader).ToList();
And I only retrieve the data I need without retrieving the entire CountryRegion record
Also, If I'm working with just the CountryRegion, I can query like this:
List<CountryRegion> query = (from a in db.CountryRegionHeader join b in db.CountryRegionDetail on a.CountryRegionCode equals b.CountryRegionCode select new Employee(){Header = a, Detail = b}).ToList();
One way to achieve this is to add a computed column on your database that gives you the CountryRegion name on your StateProvince.
With this all you have to do is to request the StateProvince table and your database server will give you the relevant associated CountryRegion name.
Edit
After your comment I had another idea.
Create a class for your usage :
public class StateProvinceEdition : StateProvince
{
public string CountryRegionName { get; set; }
public StateProvinceEdition(StateProvince stateProvince, string countryRegionName)
{
this.StateProvinceID = stateProvince.StateProvinceID;
// And so on ...
// Adding country region name
this.CountryRegionName = countryRegionName;
}
}
Then you need to project your query result into your object using Linq :
List<StateProvinceEdition> statP = context.StateProvinces.Select(s => new StateProvince(s, s.CountryRegion.Name)).ToList();
I do not have a database to test it upon so if EF throws an exception regarding the constructor, try to switch the Select and ToList statements to first load objects from the database and then project the result in the custom class.
Second edit
Similar to the first idea, you can create a view in your database for your purpose and then use Entity Framework to query this view. With this solution you do not need to change your database other than adding a view.
I've got a source model defined as
public class SourceRoot
{
...
public Organisation Organisation { get; set; }
...
}
public class Organisation
{
public long? Id { get; set; }
public string Name { get; set; }
public string Currency { get; set; }
public double SupplementaryAmount { get; set; }
public decimal BaseConversionRate { get; set; }
}
and a destination defined as:
public class DestinationRoot
{
...
public Organisation Organisation { get; set; }
public ContributesTo ContributesTo { get; set; }
}
public class Organisation
{
public long? Id { get; set; }
public string Name { get; set; }
}
public class ContributesTo
{
public string Currency { get; set; }
public double SupplementaryAmount { get; set; }
public decimal BaseConversionRate { get; set; }
}
I want to map from the SourceRoot to the DestinationRoot add copy from the source Organisation to the destination Organisation AND ContributesTo.
I have the following configuration for AutoMapper:
public static class AutoMapperConfig
{
public static MapperConfiguration RegisterMappings()
{
var config = new MapperConfiguration(cfg =>
{
cfg.AddProfile<MyProfile>();
});
return config;
}
}
public class MyProfile : Profile
{
protected override void Configure()
{
this.CreateMap<SourceRoot, DestinationRoot>();
this.CreateMap<Source.Organisation, Destination.Organisation>();
this.CreateMap<Source.Organisation, Destination.ContributesTo>();
}
}
Using this current profile the Organisation gets mapped but the ContributesTo comes out as null.
Note that I'm using version 4.2 of AutoMapper where the static methods have been deprecated so trying to steer away from that. Normally I would do:
Mapper.CreateMap<SourceRoot, DestinationRoot>()
.ForMember(d => d.ContributesTo, opt => opt.MapFrom( s=> Mapper.Map<ContributesTo>(s.Organisation)));
But this is not advised anymore (referencing the static methods). Is there an alternative way of doing this?
Thanks
Just add mapping for ContributesTo destination member:
protected override void Configure ()
{
CreateMap<Source.SourceRoot, Destination.DestinationRoot>()
.ForMember(d => d.ContributesTo, opt => opt.MapFrom(s => s.Organisation));
CreateMap<Source.Organisation, Destination.Organisation>();
CreateMap<Source.Organisation, Destination.ContributesTo>();
}
Otherwise Automapper finds that both source and destinaton roots have property Organisation and it maps only this property. Automapper cannot understand that it should use one property of source to map several properties of destination (which do not match by name). Note that you don't need to specify mapping for Organisation member, because it matches property name in destination object.
I am using Automapper to map my Model objects to DTO. In DTO the primary key should be replaced with the corresponding object. For this purpose I used the code below:
// Model class
public class SubDepartment
{
public long Id { get; set; }
public string Name { get; set; }
public long? DepartmentId { get; set; }
public DateTime LastUpdated { get; set; }
}
// DTO class
public class SubDepartmentDTO
{
public long Id { get; set; }
public string Name { get; set; }
public Department Department { get; set; }
public long EventCount { get; set; }
}
// Mapping code
Mapper.CreateMap<Models.Event.SubDepartment, DTO.SubDepartment>().ForMember(dto => dto.Department,
map => map.MapFrom(sd => Mapper.Map<Department, DTO.Department>(_departmentRepository.GetById(sd.DepartmentId.Value))));
But when I map from SubDepartment to SubDepartmentDTO in my controller, the 'Department' object is always null. I tried replacing the _departmentRepository.GetById(sd.DepartmentId.Value) code with a hardcoded Department object and it is working good. I also verified there is a corresponding Department exist in the database for the primary key. Can anyone point out what I am doing wrong ?
Try it with this code
Mapper.CreateMap<Models.Event.SubDepartment, DTO.SubDepartment>().ForMember(dto => dto.Department,map => map.MapFrom(sd => _departmentRepository.GetById(sd.DepartmentId.Value)));
if it doesn't work you could try Custom value resolver
Models.Event.SubDepartment, DTO.SubDepartment>().ForMember(dto => dto.Department, map => map.ResolveUsing<DepartmentResolver>());
public class DepartmentResolver: ValueResolver<Models.Event.SubDepartment,DTO.SubDepartment>
{
Reporsitory _departmentRepository;
protected override DTO.SubDepartment ResolveCore(Models.Event.SubDepartment source)
{
return _departmentRepository.GetById(source.DepartmentId.Value);
}
}
I was wondering if it is possible to map multiple DTO objects to a single ViewModel object using Automapper?
Essentially, I have multiple DTO objects and would like to display information from each on a single screen in ASP.NET MVC 2.0. To do so I would like to flatten the DTO objects (or parts of them...) into the Viewmodel and pass said viewmodel to the view. If I had one DTO this would be easy, but I've never seen it being done with multiple. Obviously there are a number of roundabout ways to do this (outside of automapper), but this is the approach that I would like to take if possible.
Check for following link regarding your query
http://consultingblogs.emc.com/owainwragg/archive/2010/12/22/automapper-mapping-from-multiple-objects.aspx
You could create a composite DTO that holds two or more DTO objects and map the composite DTO to the output view model.
If you have 2 DTO classes and 1 flattened view model:
public class Dto1
{
public string Property1 { get; set; }
}
public class Dto2
{
public string Property2 { get; set; }
}
public class FlattenedViewModel
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
And you create mappings for both DTOs to view model:
CreateMap<Dto1, FlattenedViewModel>();
CreateMap<Dto2, FlattenedViewModel>();
You can map 1st DTO to the model and then just "append" 2nd DTO:
var dto1 = new Dto1 { Property1 = "Value1"; }
var dto2 = new Dto2 { Property2 = "Value2"; }
var model = Mapper.Map<FlattenedViewModel>(dto1); // map dto1 properties
Mapper.Map(dto2, model); // append dto2 properties
You can add a Map override extension method off IMappingEngine that takes a params array. Something like:
public static class AutoMapperExtensions
{
public static T Map<T>(this IMappingEngine engine, params object[] sources) where T : class
{
if (sources == null || sources.Length == 0)
return default(T);
var destinationType = typeof (T);
var result = engine.Map(sources[0], sources[0].GetType(), destinationType) as T;
for (int i = 1; i < sources.Length; i++)
{
engine.Map(sources[i], result, sources[i].GetType(), destinationType);
}
return result;
}
}
You could then call it like this:
var result = Mapper.Engine.Map<MyViewModel>(dto1, dto2, dto3);
This is the information from the expired link in this answer: https://stackoverflow.com/a/8923063/2005596
When using AutoMapper (http://automapper.codeplex.com ) I often have a scenario where I need to map several entities into one entity. Commonly this occurs when mapping from a number domain entities into a single view model (ASP.NET MVC). Unfortunately the AutoMapper API does not expose functionality to map several entities into one entity; however it is relatively simple to create some helper method to do this. Below I will illustrate the approach that I have taken.
In this example I have the following entities in my domain model
public class Person
{
public int Id { get; set; }
public string Firstname { get; set; }
public string Surname { get; set; }
}
public class Address
{
public int Id { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string Country { get; set; }
}
public class Comment
{
public string Text { get; set; }
public DateTime Created { get; set; }
}
In addition to this I have a requirement to render the person details the person’s address and any related comment on a single page (using ASP.NET MVC). To implement this I have created the view model shown below, which includes data from all three of the domain entities shown above
public class PersonViewModel
{
public int Id { get; set; }
[DisplayName("Firstname")]
public string Firstname { get; set; }
[DisplayName("Surname")]
public string Surname { get; set; }
[DisplayName("Address Line 1")]
public string AddressLine1 { get; set; }
[DisplayName("Address Line 2")]
public string AddressLine2 { get; set; }
[DisplayName("Country Of Residence")]
public string Country { get; set; }
[DisplayName("Admin Comment")]
public string Comment { get; set; }
}
In the controller action method I make three separate calls into the domain layer to retrieve the required entities but this still leaves the issue that I need to map several source entities onto a single destination entity. To perform this mapping I created a helper class which encapsulates AutoMapper and exposes functionality which enables the mapping of several source objects onto one destination object. This class is shown below
public static class EntityMapper
{
public static T Map<T>(params object[] sources) where T : class
{
if (!sources.Any())
{
return default(T);
}
var initialSource = sources[0];
var mappingResult = Map<T>(initialSource);
// Now map the remaining source objects
if (sources.Count() > 1)
{
Map(mappingResult, sources.Skip(1).ToArray());
}
return mappingResult;
}
private static void Map(object destination, params object[] sources)
{
if (!sources.Any())
{
return;
}
var destinationType = destination.GetType();
foreach (var source in sources)
{
var sourceType = source.GetType();
Mapper.Map(source, destination, sourceType, destinationType);
}
}
private static T Map<T>(object source) where T : class
{
var destinationType = typeof(T);
var sourceType = source.GetType();
var mappingResult = Mapper.Map(source, sourceType, destinationType);
return mappingResult as T;
}
}
To map several source objects onto one destination I have made use of the functionality provided by AutoMapper which allows you to perform a mapping between a source object and a destination object that already exists.
Finally below is the code from the controller that retrieves the three entities and performs the mapping onto a single view model
public ActionResult Index()
{
// Retrieve the person, address and comment entities and
// map them on to a person view model entity
var personId = 23;
var person = _personTasks.GetPerson(personId);
var address = _personTasks.GetAddress(personId);
var comment = _personTasks.GetComment(personId);
var personViewModel = EntityMapper.Map<PersonViewModel>(person, address, comment);
return this.View(personViewModel);
}
I just worked this out myself and have a great solution. It is most likely that your two views are actually related somehow in your system (especially if you are using Entity Framework). Check your models and you should see something which displays the relationship, if you don't then just add it. (The virtual)
Your models
public class Dto1
{
public int id { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
public string Property4 { get; set; }
public string Property5 { get; set; }
public virtual Dto2 dto2{ get; set; }
}
public class Dto2
{
public int id { get; set; }
public string PropertyB { get; set; }
public string PropertyC { get; set; }
public string PropertyD { get; set; }
public string PropertyE { get; set; }
}
Your ViewModels
public class Dto1ViewModel
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public virtual Dto2VMForDto1 dto2{ get; set; }
}
//Special ViewModel just for sliding into the above
public class Dto2VMForDto1
{
public int id { get; set; }
public string PropertyB { get; set; }
public string PropertyC { get; set; }
}
Automapper looks like this:
cfg.CreateMap< Dto1, Dto1ViewModel>();
cfg.CreateMap< Dto2, Dto2VMForDto1 >();
I'm assuming you are getting your data with LinQ:
Dto1ViewModel thePageVM = (from entry in context.Dto1 where...).ProjectTo<Dto1ViewModel>();
Viola, everything will work. In your view just access by using model.dto2.PropertyB