I am trying to map an IDictionary<string,object> to another IDictionary<string,object>. The source dictionary contains int, int[], string[] and strongly-typed lists of domain objects. I wanted to map that dictionary to a dictionary where my domain objects get mapped to DTOs.
I created mappings for the domain objects which maps them to the equivalent DTOs. However, when trying to map the dictionary, it results in an empty IDictionary<string,object>.
Any help on this will be very much appreciated.
Never mind, I was doing something dumb. The dictionary was being initialized in the constructor of the parent object, tough overwriting Automapper generated dictionary.
Sigh.
Related
I have a ton of domain entity to dto maps, that are basically one to one maps like this:
CreateMap<Package, PackageForm>();
I have to call CreateMap for each map, this seems like it could be handled by a convention or something. Is it possible to have AutoMapper (try to) create a mapping on the fly when Map() is called for a non-existing map?
Well I just discovered Mapper.DynamicMap(), seems to be what I was after.
I've used Automapper before to map DataTable objects to a DTO object like this:
AutoMapper.CreateMap<IDataReader, MyDTO>();
Now I've run into a case where I have three DataTable objects that map to one DTO object. I can't use the simple case above because I have three sources with the same type.
Is there a way to specify some additional information, like the table name, to determine the correct mapping?
I am having trouble posting a form that contains a Dictionary that contains an int as a key and a list of objects as a value.
Originally this was just a List of Objects and that worked fine and the type was:
List<MyObject> Fields
the working markup was
Fields_{0}__Property1
where {0} is the index of the object. To get it to post back the List of Objects I rendered the object with hidden fields like this:
#Html.HiddenFor(m => m.Property1, new { Name = string.Format("Fields[{0}].Property1", Model.Index), #id = string.Format("Fields_{0}__Property1", Model.Index) })
This worked well. Now however, we have a dictionary instead of a list and the list is inside the dictionary.
Now the type is:
Dictionary<int, List<MyObject>>.
I tested the format expected when we render the dictionary using Html.HiddenFor and so I've added hidden fields with the required format which now is:
#Html.HiddenFor(m => m.Property1, new { Name = string.Format("Fields[{0}][{1}].Property1", Model.Index, Model.Position), #id = string.Format("Fields_{0}__{1}__Property1", Model.Index, Model.Position) })
now the field id is
Fields_{0}__{1}__Property1
where {0} is the key of the dictionary and {1} is the index of the object in the list.
However on postback I now get
[InvalidCastException: Specified cast is not valid.]
System.Web.Mvc.CollectionHelpers.ReplaceDictionaryImpl(IDictionary`2 dictionary, IEnumerable`1 newContents) +131
I am guessing MVC is smart enough to render the fields of this complex object on the view but not smart enough to collect them back into the viewmodel when we post back.
I found this other guy who had a similar problem here and he solved it by not using a dictionary but instead creating a complex object. I'm wondering, however, if there's a quicker way that won't require me to rewrite the entire system.
Any ideas?
Update
I solved it by taking the source code of DefaultModelBinder and adjusting it.
I found the source here. I didn't create my own Binder because I want all the advanced functionality and validation rules to apply to all other elements.
Once I got the DefaultModelBinder compiling and working I found the part where the dictionary was failing to cast the complex items and wrote a custom Dictionary update method that solved the problem
You can always create a custom Model Binder to bind objects from request values exactly as you want. Simply create a class that implements the System.Web.Mvc.IModelBinder interface and implement the BindModel() method.
AutoMapper Beginner Question:
I was hoping AutoMapper would let me merge properties from a DTO back into an existing business object. I don't see anything like that. AutoMapper.Map() generates a new object and populates it, but I need to copy DTO changes back into the original business object.
Is there an Map function that takes a source and target object?
The Map method is overloaded. You can use Map(src, dst).
What is the difference between the System.ComponentModel.BindingList methods Add(object) and AddNew()? The MSDN documentation says this:
Add: Adds an object to the end of the Collection<T>.
AddNew: Adds a new item to the collection.
It seems like both methods add an item to the collection, but Add(object) does it in one shot whereas AddNew() is slightly more complicated. My tests with Add(object) seem to be working, but I want to know if I am using the correct method.
So what is the difference between these methods?
AddNew() creates the object for you (that's why it doesn't have a parameter).
It's designed to be used by grids, which don't know how to create a new object to pass to Add().
AddNew() is very handy (it’s the well-known Factory design pattern) when you implement a class derived of BindingList().
It allows your code to initialize new items with values that depend on the list itself - e.g. a foreign key to the parent object if the binding list contains a list of children.