I'm mapping a list to another list with Automapper, but it seems that my items are not copied.
Here is my code:
var roles = userRepo.GetRoles(null).ToList();
Mapper.CreateMap < List<Domain.Role>, List<Role>>();
var mappedRole = Mapper.Map<List<Domain.Role>, List<Role>>(roles); //the count is 0, list empty :(
Mapper.AssertConfigurationIsValid();
No exceptions were thrown.
All properties has the same names.
Domain.Role
public class Role
{
public int RoleId { get; set; }
public string RoleName { get; set; }
public List<User> Users { get; set; }
}
Role
public class Role
{
public int RoleId { get; set; }
public string RoleName { get; set; }
}
Don't create maps between lists and array, only between the types:
Mapper.CreateMap<Domain.Role, Role>();
and then:
var mappedRole = Mapper.Map<List<Domain.Role>, List<Role>>(roles);
AutoMapper handles lists and arrays automatically.
In my case, I had the (parent) type mapping configured correctly but I didn't add the mappings for the child records, so for this:
class FieldGroup
{
string GroupName { get; set; }
...
List<Field> fields { get; set; }
}
I had to add the second mapping:
cfg.CreateMap<FieldGroup, FieldGroupDTO>();
cfg.CreateMap<Field, FieldDTO>(); << was missing
Avoid adding Collections in your mapper configuration. Make sure you add all the types(classes). I had errors when collections were not in the config, but that was because all types were not included. Bit misleading but that's where the problem lies. Point is, remove all collections from mapper config and add all classes only. Add collections when doing the actual transformation ie. call to mapper.Map.
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Infrastructure.Entities.Pet, Domain.Model.Pet>();
cfg.CreateMap<Infrastructure.Entities.Owner, Domain.Model.Owner>().ReverseMap();
});
var mapper = config.CreateMapper();
var domainPetOwners = mapper.Map<List<Domain.Model.Owner>>(repoPetOwners);
Related
I use Asp.Net MVC, Entity Framework. I have a form it looks like below.
Here, dropdownlist is filled from a table(types). Checkboxes is filled from another table(test). Tables are like below:
public class Types
{
public int TypesID{get;set;}
public string TestName { get; set; }
public string TestExplanation { get; set; }
public int TestTime { get; set; }
}
public class Tests
{
public int TestID{get;set;
public string Name { get; set; }
public string Code { get; set; }
}
public class Types_Tests
{
public int Types_TestsID{ get; set; }
public int TypesID { get; set; }
public int TestsID { get; set; }
public virtual Types Types { get; set; }
public virtual Tests Tests { get; set; }
}
Types_test table is relation table between Types and Tests. When I click Kaydet button, it shuld save type and checked tests. I made this operation using ViewBag, javascript and hdnvalue.I added checked checkboz values to a hdntext. I made saving process like below:
[HttpPost]
public ActionResult Index(string drpType, string hdntesttypes)
{
var TypeList = Types.GetAll();
ViewBag.TypesList = new SelectList(TypeList, "Id", "Name");
var testypeList = testTypes.GetAll();
ViewBag.TestTypesList = new SelectList(testypeList, "Id", "TestName");
GenericRepository<TestDisabledTypes> testDisabledRepository = new GenericRepository<TestDisabledTypes>(_context);
if (!string.IsNullOrEmpty(hdntesttypes))
{
string[] disabletypesArray = hdntesttypes.Split(',');
using (TransactionScope trns = new TransactionScope())
{
for (int i = 0; i < disabletypesArray.Length; i++)
{
Test_Types types = new Test_Types ();
types.TestTypesID = Convert.ToInt32(disabletypesArray[i]);
types.TypesID = Convert.ToInt32(drpType);
testDisabledRepository.Insert(types);
}
trns.Complete();
}
}
return View();
}
It wokrs. But I search better solution for this process. Can someone give me any idea?
Thanks.
If you don't need additional attributes for your entity class, you don't need create link table.
Just define the following class, and EF will generate the link table for you automatically.
public class Type
{
public int TypesID{get;set;}
public string TestName { get; set; }
public string TestExplanation { get; set; }
public int TestTime { get; set; }
public ICollection<Test> Tests { get; set; }
}
public class Test
{
public int TestID{get;set;
public string Name { get; set; }
public string Code { get; set; }
public ICollection<Type> Types {get;set;}
}
Well, in EntityFramework if you want to create a many to many relation object you need to create new object of "linking" entity. Unfortunately, it is not possible to add first object, add second object and say "Guys, you are in many to many relationships. Are you happy then?" :) You need to create relation object, set appropriate fields in it (I think these are ids of two objects itself) and add it to relation collection (entity) in your model. But before doing so you need to be sure that objects with data you are linking with are already exists in database. Otherwise you'll get an error
Also it's not necessary to create manually transaction because EF does it for you automatically each time you get/save your data
I have a ViewModel with a number of different properties (ie string, int, etc) that I need to iterate through in the controller. What is the best way to do this? Here is the ViewModel's defintion:
public class BankListViewModel
{
public int ID { get; set; }
public string BankName { get; set; }
public string EPURL { get; set; }
public string AssociatedTPMBD { get; set; }
public string Tier { get; set; }
public List<BankListAgentId> BankListAgentId { get; set; }
public List<BankListStateCode> BankListStateCode { get; set; }
}
I need to omit the two lists, however. Any ideas?
EDIT
The purpose of this process is to pass specific items of the view model into three separate objects. The view model was created to combine properties of three separate SQL tables/Models. I am now trying to divide them up appropriately and add the information to the relevant tables. Right now I'm simply going one by one like so:
BankListMaster banklistmaster = new BankListMaster();
banklistmaster.AssociatedTPMBD = viewmodel.AssociatedTPMBD;
banklistmaster.BankName = viewmodel.BankName;
Although it's not clear why you would need to iterate over the properties instead of just reading their vaules, you could accomplish this using reflection
var model = new BankListViewModel();
PropertyInfo[] properties = model.GetType().GetProperties();
foreach (var property in properties)
{
if (property.GetType() != typeof(List<BankListAgentId>))
{
//do your thing here
}
}
This statement returns a list of people and their addresses and phone numbers.
var listOfPeople = db.People.AsQueryable();
Now, I'd like to use AutoMapper to map the results of the above LINQ statement to a view model. The view model was created mainly to prevent some properties from being returned to the client / user.
How do I get AutoMapper to map the results, listOfPeople, to a view model composed of the base object, Person, and ICollections of Addresses and PhoneNunmbers? I don't have a problem mapping a single person to a single vm. I think I'm getting hung up on mapping a collection, listOfPeople, that contains a couple of collections within.
I'm using ASP.NET Web API 4, not MVC 4.
Here is the view model
public class BasicApiViewModel
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
public virtual ICollection<Phone> Phones { get; set; }
}
If I understood your question, there is no need to separately configure collection mappings, you just need to define mapping between classes (as you've already done), and collections will be handled automatically
AutoMapper only requires configuration of element types, not of any
array or list type that might be used. For example, we might have a
simple source and destination type:
public class Source
{
public int Value { get; set; }
}
public class Destination
{
public int Value { get; set; }
}
All the basic generic collection types are supported:
Mapper.CreateMap<Source, Destination>();
var sources = new[]
{
new Source { Value = 5 },
new Source { Value = 6 },
new Source { Value = 7 }
};
IEnumerable<Destination> ienumerableDest = Mapper.Map<Source[], IEnumerable<Destination>>(sources);
ICollection<Destination> icollectionDest = Mapper.Map<Source[], ICollection<Destination>>(sources);
IList<Destination> ilistDest = Mapper.Map<Source[], IList<Destination>>(sources);
List<Destination> listDest = Mapper.Map<Source[], List<Destination>>(sources);
Destination[] arrayDest = Mapper.Map<Source[], Destination[]>(sources);
Lists and arrays
I'm getting started with the concept of mapping domain models to view models in ASP.NET MVC after watching a recommendation to do this to pass specific viewModels to the views.
I've been able to manage a basic mapping of one domain model to a simpler viewmodel with less properties but now need to produce a more complex viewmodel and can't figure it out. I have the following domain models
public class Club
{
public int ClubID { get; set; }
public string FullName { get; set; }
public string Description { get; set; }
public string Telephone { get; set; }
public string URL { get; set; }
public DateTime CreatedDate { get; set; }
public virtual ICollection<Member> Members{ get; set; }
}
public class Member
{
public int MemberID{ get; set; }
public string Name { get; set; }
public MemberType Membership{ get; set; }
public virtual Club Club { get; set; }
public virtual int ClubID { get; set; }
}
public enum MemberType
{
Standard,
Special,
Limited
}
I want to map to a view model such as this (note: I've split it like this because I think it makes sense but I'm not sure)...
public class ClubDetailsViewModel
{
public int ClubID { get; set; }
public string FullName { get; set; }
public string Description { get; set; }
public IList<ClubDetailsMemberSummaryViewModel> Members { get; set; }
}
public class ClubDetailsMemberSummaryViewModel
{
public MemberType Membership { get; set; }
public int MemberCount { get; set; }
}
What I'm trying to end up with is a page which displays some of the club details plus a summary report of the member types at the club with a count of the members. Such as:
Some Club Name
Description of the club.....
CLUB MEMBERS
Limited - 15
Standard - 100
So I think the viewmodel makes sense for this (although might be a better way to do it). Where I'm struggling is how to map the elements. I can get the Club to map the main fields to the club viewmodel but really can't work out how to map the result of the list of clubs onto their view model and then add that to the main view model as a list.
I'm getting the clubs from my repository using this
var clubs = _clubRepository.GetClubByID(ID);
Then I can transform the Courts which are returned using an include in the data access layer from entity framework using this
var grpCourts = from c in clubs.Members
group c by c.Membership into grp
select new { st = grp.Key, count = grp.Distinct().Count() };
How would I loop through the resulting records and map those to the ClubDetailsMemberSummaryViewModel and then add the list of those to the main ClubDetailsViewModel?
Your mapping from Club to ClubDetailsViewModel will be trivial with the exception of Members. For that property, you could write a quick resolver inline or write your own custom resolver. An inline resolver would look something like this:
Mapper.CreateMap<Club, ClubDetailsViewModel>()
.ForMember(dest => dest.Members, opt => opt.ResolveUsing(src =>
{
return src.Members
.GroupBy(m => m.Membership)
.Select(grp => new ClubDetailsMemberSummaryViewModel
{
Membership = grp.Key,
MemberCount = grp.Distinct().Count()
});
}));
I think it's good practice to refactor more complex resolvers like this out to their own classes:
public class MembershipClubDetailsResolver : ValueResolver<Club, IList<ClubDetailsMemberSummaryViewModel>>
{
protected override IList<ClubDetailsMemberSummaryViewModel> ResolveCore (Club source)
{
return source.Members
.GroupBy (m => m.Membership)
.Select(grp => new ClubDetailsMemberSummaryViewModel
{
Membership = grp.Key,
MemberCount = grp.Distinct().Count()
})
.ToList();
}
}
And then use that resolver in your mapping:
Mapper.CreateMap<Club, ClubDetailsViewModel>()
.ForMember(dest => dest.Members, opt => opt.ResolveUsing<MembershipClubDetailsResolver>());
Your mapping appears to be rather complex, I think I would use the .ConvertUsing method of automapper
Mapper.CreateMap<List<Club>,List<ClubDetailsViewModel>>()
.ConvertUsing<ClubToClubDetailsViewModel>();
The conversion class has the following inheritance
public class ClubToClubDetailsViewModel: TypeConverter<List<Club>,List<ClubDetailsViewModel>>
{
....
}
Alternatively you can tinker with creating two "simple" mappings
Mapper.CreateMap<Club,ClubDetailsViewModel>()
That will map everything except the property called Members
Then you need to create a mapping for the members to ClubDetailsMemberSummaryViewModel, you can do that mapping manually or you can configure this in automapper aswell.
For more specific details on automapper you can visit https://github.com/AutoMapper/AutoMapper/wiki
I am trying to figure out how to generically map a domain model to a presentation model. For example, given the following simple objects and interfaces ...
// Product
public class Product : IProduct
{
public int ProductID { get; set; }
public string ProductName { get; set; }
}
public interface IProduct
{
int ProductID { get; set; }
string ProductName { get; set; }
}
// ProductPresentationModel
public class ProductPresentationModel : IProductPresentationModel
{
public int ProductID { get; set; }
public string ProductName { get; set; }
public bool DisplayOrHide { get; set; }
}
public interface IProductPresentationModel
{
int ProductID { get; set; }
string ProductName { get; set; }
bool DisplayOrHide { get; set; }
}
I would like to be able to write code like this ...
MapperObject mapper = new MapperObject();
ProductService service = new ProductService();
ProductPresentationModel model = mapper.Map(service.GetProductByID(productID));
... in which the "MapperObject" could automatically figure out which properties map across the two objects and what sort of objects it is mapping using something like reflection, convention-based mapping, etc. So, I could then just as easily try to map objects like UserPresentationModel and User with the same MapperObject.
Is this possible? If so, how?
EDIT: Just for clarity, here is an example of a non-generic MapperObject that I am currently using:
public class ProductMapper
{
public ProductPresentationModel Map(Product product)
{
var presentationModel = new ProductPresentationModel(new ProductModel())
{
ProductID = product.ProductID,
ProductName = product.ProductName,
ProductDescription = product.ProductDescription,
PricePerMonth = product.PricePerMonth,
ProductCategory = product.ProductCategory,
ProductImagePath = product.ProductImagePath,
ProductActive = product.ProductActive
};
return presentationModel;
}
}
I am still trying to work out how to get this to work with List, instead of just a single Product, but that's a different topic :)
I see want you want. You want to map your domain entities (Product) to aome kind of DTO object (ProductPresentationModel) for communication with your clients (GUI, external services etc).
I you have all this functionality you're looking for packed into AutoMapper framework.
You can write like this with AutoMapper:
Mapper.CreateMap();
look at this wiki https://github.com/AutoMapper/AutoMapper/wiki/Flattening
Good luck.
/Best Regards Magnus