Mapping domain model to view model via AutoMapper or not - c#

I want to use view model for display insted of domain model. And I want to customise a property for display, how should I do this? And is it a good practice to use AutoMapper for display?
Below is the code sample:
public class BookController : BaseController
{
private IBookService bookService;
public BookController(IBookService bookService)
{
this.bookService = bookService;
}
public ActionResult Details(int id)
{
var book = bookService.GetBookById(id);
return View(Mapper.Map<BookView>(book));
}
}
public class Book
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
public class BookView
{
public int Id { get; set; }
public string Name { get; set; }
}
If I use another way, I can customise any property, like below:
public ActionResult Details(int id)
{
var book = bookService.GetBookById(id);
return View(new BookView(book));
}
public class BookView
{
public BookView(Book book){
Name = book.Name +" Decorated";
}
public int Id { get; set; }
public string Name { get; set; }
}
How should I do this? And is it a good practice to use AutoMapper for display?
Update
It seems using automapper in the scenario below is more appropriate. For example, mapping a view model to domain model like below. Any opinions?
[HttpPost]
public ActionResult Create(BookView bookView)
{
try
{
var book = Mapper.Map<Book>(bookView); //this is wrong
bookService.SaveOrUpdate(book);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
Update 2
For complex custom display via view model, I don't want to use automapper to map display logic, assuming automapper can map it. Because it mixes different purposes. For example:
Mapper.CreateMap<Book, BookView>()
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name + " this is for display purpose"));
However, using manual mapping like below seems intuitive.
public BookView(Book book){
//mapping here
}
Update 3
Quote from Jimmy Bogard:
I think using AutoMapper because you don’t want to use the “=”
operator is a bit lazy. Instead, we use it to flatten and reshape,
optimizing for the destination type’s environment. Remember, my
original motivation for AutoMapper was:
Enable protecting the domain layer from other layers by mapping to
DTOs
Thanks #AndrewWhitaker for the link

This is a good use case for AutoMapper (I've used it this way extensively on many projects with success). Generally you do not want to expose domain entities to your view (in MVC, this would be exposing your model directly to your view, which is incorrect).
You do not need a 1-1 mapping between domain entity and viewmodel. You can make them look completely different and customize the mapping in your CreateMap<> call. To use your example:
Mapper.CreateMap<Book, BookView>()
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name + " Decorated"));
Worst case, you can ditch automapper for complex cases or use a custom type resolver with automapper to get the job done.
In fact, this is how Jimmy Bogard (the author) recommends using AutoMapper. He specifically mentions mapping from domain entities to ASP.NET MVC ViewModels for use with strongly typed views.
Another advantage is that you can unit test your mapping profiles. This way if you end up with a mismatch between ViewModel and Model you'll get a failing unit test.
Updates:
I think the quote you added to your question further supports using AutoMapper for mapping from domain models to ViewModels:
Instead, we use it to flatten and reshape, optimizing for the destination type’s environment.
So in my example you'd definitely be optimizing for the destination type's environment (in this case a view).
Also per the link I reference above you should not be using automapper to map to the domain, only from. With that in mind, you'll have to write some logic to create/update domain entities from what you receive from the View no matter what. Remember that controller actions should not take domain entities directly (you should not trust data that comes directly from the view--let the model determine if a domain entity would be valid or not).

Related

Best way to project ViewModel back into Model

Consider having a ViewModel:
public class ViewModel
{
public int id { get; set; }
public int a { get; set; }
public int b { get; set; }
}
and an original Model like this:
public class Model
{
public int id { get; set; }
public int a { get; set; }
public int b { get; set; }
public int c { get; set; }
public virtual Object d { get; set; }
}
Each time I get the view model I have to put all ViewModel properties one by one into Model. Something like:
var model = Db.Models.Find(viewModel.Id);
model.a = viewModel.a;
model.b = viewModel.b;
Db.SaveChanges();
Which always cause lots of problems. I even sometimes forget to mention some properties and then disaster happens!
I was looking for something like:
Mapper.Map(model, viewModel);
BTW: I use AutoMapper only to convert Model to ViewModel but vice-versa I always face errors.
Overall that might be not the answer, that you are looking for, but here's a quote from AutoMapper author:
I can’t for the life of me understand why I’d want to dump a DTO
straight back in to a model object.
I believe best way to map from ViewModel to Entity is not to use AutoMapper for this. AutoMapper is a great tool to use for mapping objects without using any other classes other than static. Otherwise, code gets messier and messier with each added service, and at some point you won't be able to track what caused your field update, collection update, etc.
Specific issues often faced:
Need for non-static classes to do mapping for your entities
You might need to use DbContext to load and reference entities, you might also need other classes - some tool that does image upload to your file storage, some non-static class that does hashing/salt for password, etc etc... You either have to pass it somehow to automapper, inject or create inside AutoMapper profile, and both practices are pretty troublemaking.
Possible need for multiple mappings over same ViewModel(Dto) -> Entity Pair
You might need different mappings for same viewmodel-entity pair, based on if this entity is an aggregate, or not + based on if you need to reference this entity or reference and update. Overall this is solvable, but causes a lot of not-needed noise in code and is even harder to maintain.
Really dirty code that's hard to maintain.
This one is about automatic mapping for primitives (strings, integers, etc) and manual mapping references, transformed values, etc. Code will look really weird for automapper, you would have to define maps for properties (or not, if you prefer implicit automapper mapping - which is also destructive when paired with ORM) AND use AfterMap, BeforeMap, Conventions, ConstructUsing, etc.. for mapping other properties, which complicates stuff even more.
Complex mappings
When you have to do complex mappings, like mapping from 2+ source classes to 1 destination class, you will have to overcomplicate things even more, probably calling code like:
var target = new Target();
Mapper.Map(source1, target);
Mapper.Map(source2, target);
//etc..
That code causes errors, because you cannot map source1 and source2 together, and mapping might depend on order of mapping source classes to target. And I'm not talking if you forget to do 1 mapping or if your maps have conflicting mappings over 1 property, overwriting each other.
These issues might seem small, but on several projects where I faced usage of automapping library for mapping ViewModel/Dto to Entity, it caused much more pain than if it was never used.
Here are some links for you:
Jimmy Bogard, author of AutoMapper about 2-way mapping for your entities
A small article with comments about problems faced when mapping ViewModel->Entity with code examples
Similar question in SO: Best Practices For Mapping DTO to Domain Object?
For this purpose we have written a simple mapper. It maps by name and ignores virtual properties (so it works with entity framework). If you want to ignore certain properties add a PropertyCopyIgnoreAttribute.
Usage:
PropertyCopy.Copy<ViewModel, Model>(vm, dbmodel);
PropertyCopy.Copy<Model, ViewModel>(dbmodel, vm);
Code:
public static class PropertyCopy
{
public static void Copy<TDest, TSource>(TDest destination, TSource source)
where TSource : class
where TDest : class
{
var destProperties = destination.GetType().GetProperties()
.Where(x => !x.CustomAttributes.Any(y => y.AttributeType.Name == PropertyCopyIgnoreAttribute.Name) && x.CanRead && x.CanWrite && !x.GetGetMethod().IsVirtual);
var sourceProperties = source.GetType().GetProperties()
.Where(x => !x.CustomAttributes.Any(y => y.AttributeType.Name == PropertyCopyIgnoreAttribute.Name) && x.CanRead && x.CanWrite && !x.GetGetMethod().IsVirtual);
var copyProperties = sourceProperties.Join(destProperties, x => x.Name, y => y.Name, (x, y) => x);
foreach (var sourceProperty in copyProperties)
{
var prop = destProperties.FirstOrDefault(x => x.Name == sourceProperty.Name);
prop.SetValue(destination, sourceProperty.GetValue(source));
}
}
}
I want to address a specific point in your question, regarding "forgetting some properties and disaster happens". The reason this happens is that you do not have a constructor on your model, you just have setters that can be set (or not) from anywhere. This is not a good approach for defensive coding.
I use constructors on all my Models like so:
public User(Person person, string email, string username, string password, bool isActive)
{
Person = person;
Email = email;
Username = username;
Password = password;
IsActive = isActive;
}
public Person Person { get; }
public string Email { get; }
public string Username { get; }
public string Password { get; }
public bool IsActive { get; }
As you can see I have no setters, so object construction must be done via constructor. If you try to create an object without all the required parameters the compiler will complain.
With this approach it becomes clear, that tools like AutoMapper don't make sense when going from ViewModel to Model, as Model construction using this pattern is no longer about simple mapping, its about constructing your object.
Also as your Models become more sophisticated you will find that they differ significantly from your ViewModels. ViewModels tend to be flat with simple properties like string, int, bool etc. Models on the other hand often include custom objects. You will notice in my example there is a Person object, but UserViewModel would use primitives instead like so:
public class UserViewModel
{
public int Id { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public string Email { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public bool IsActive { get; set;}
}
So mapping from primitives to complex objects limits AutoMapper's usefulness.
My approach is always manual construction for the ViewModels to Model direction. In the other direction, Models to ViewModels, I often use a hybrid approach, I would manually map Person to FirstName, LastName, I'd but use a mapper for simple properties.
Edit: Based on the discussion below, AutoMapper is better at unflattering than I believed. Though I will refrain from recommending it one way or the other, if you do use it take advantage of features like Construction and Configuration Validation to help prevent silent failures.
Use Newtonsoft.Json to serialize viewmodel first and deserialize it to model.
First we need to Serialize the viewmodel:
var viewmodel = JsonConvert.SerializeObject(companyInfoViewModel);
Then Deserialize it to model:
var model = JsonConvert.DeserializeObject<CompanyInfo>(viewmodel);
Hence, all the data is passed from viewmodel to model easily.
One Line Code:
var company = JsonConvert.DeserializeObject<CompanyInfo>(JsonConvert.SerializeObject(companyInfoViewModel));

retrieving database-computed properties of classes within entity framework

I have a good understanding of EF, and generated my database successfully. Now, I am struggling with adding dynamic properties to one of the entity classes. For example, I have a Post class, and other users can make comments to the posts. When I list the existing posts, I want to display the number of comments made to corresponding post.
One solution might be having a property called CommentCount, and updating the Post by increasing the (int) value of the CommentCount property by 1 when a new comment is made.
The other solution, and I think it is a better solution, is that when retrieving the post from the DB, the number of comments associated with the post can be computed and retrieved at the same time and assigned to CommentCount property of the post instance. However, I do not know how to achieve this with EF.
Which approach is highly recommended? Or, is there any other ways of doing this? If it is the second one, how can I achieve this with EF?
1) You should simply consider not putting the property called CommentCount into your model. When you develop for example a WPF Windows application, you should consider using MVVM pattern and the CommentCount would belong to your ViewModel class and not to your Model class. There you implement INotifyPropertyChanged and you can use it from your frontend Views. Analogically there is MVC pattern for ASP.NET etc.
There are other design patterns like Repository pattern. Using this pattern you can create the CommentCount in your repository class and not in your
model class. This would be similar to your second solution.
2) I assume from your question that you are using code-first approach:
generated my database successfully
If you do so and you wish to include CommentCount directly in your Model class, you can do it this by adding partial class file to your project like this:
namespace DBModel.Models
{
public partial class Post
{
public int CommentsCount
{
get { return this.Comments.Count; }
}
...
But I cannot see why to create extra property in your model just for that.
On the other hand adding this field as a computed field into your SQL database could make sense and then it would be part of your EF model.
If you calculation is very complex you should try creating a View in your DB and then add it to your Model?
But if your Model have something simple like
class Post {
public int postid { get; set; }
public virtual ICollection<comment> comment { get; set; }
}
In your controller you can do
db.post(x => x.postid == yourid).comments.count()
to get total of comment
or in your view
#foreach (var item in Model)
{
<li>item.postid;</li>
<li>item.comment.Count();</li>
}
Or update your class
class Post {
public int postid { get; set; }
public virtual ICollection<comment> comment { get; set; }
public int CommentCount
{
get
{
return comment.Count();
}
}
}
Just remember bring related data in your query.
In my case POI have properties parish_id, sector_id, city_id and parish have municipality, and municipality have state.
Using this query I can get Poi with all the related data.
filter = db.poi
.Include("parish")
.Include("sector")
.Include("city")
.Include("parish.municipality")
.Include("parish.municipality.state")
.Where(x => x.sector_id == SectorID);

Decorating an enum on the EF object model with a Description attribute?

I have defined an enum in my Entity Framework 5 model, which I'm using to define the type of a field on a table, e.g.
public enum PrivacyLevel : byte {
Public = 1,
FriendsOnly = 2,
Private = 3,
}
And I have a table Publication that has a tinyint field PrivacyLevel, which I've mapped in the EF model to use the PrivacyLevel type defined above, using the method described here.
But I also want to be able to display a string description for each value of the enum. This I've done in the past for enums by decorating them with a Description attribute, e.g.
public enum PrivacyLevel : byte {
[Description("Visible to everyone")]
Public = 1,
[Description("Only friends can view")]
FriendsOnly = 2,
[Description("Only I can view")]
Private = 3,
}
I've got some code that converts enums to strings by checking if they have a Description attribute, and that works well. But here, because I had to define the enum in my model, the underlying code is auto-generated, and I don't have anywhere stable to decorate them.
Any ideas for a workaround?
Not sure if this is what you are after but from what I understand i will try to be as clear as possible, since you have a concrete database first approach, you can abstract much of your Entity models to ViewModels using a Dto Approach through AutoMapper.
Using automapper profiles you can quickly setup profiles for all sorts of environments and scenarios for flexibility and adaptability
So here is this "Enum" which is causing me a problem
here is my view model for this Enum
First here is my layout
here is a simply mapping for the Account entity to a viewmodel for Account
public class AccountProfile : Profile
{
protected override void Configure()
{
// Map from Entity object to a View Model we need or use
// AutoMapper will automatically map any names that match it's conventions, ie properties from Entity to ViewModel have exact same name properties
Mapper.CreateMap<Account, AccountViewModel>()
.ForMember(model => model.CurrentPrivacy, opt => opt.MapFrom(account => (PrivacyLevelViewModel)account.PrivacyLevel));
Mapper.CreateMap<Account, EditAccountViewModel>()
.ForMember(model => model.SelectedPrivacyLevel, opt => opt.MapFrom(account => (PrivacyLevelViewModel) account.PrivacyLevel));
// From our View Model Changes back to our entity
Mapper.CreateMap<EditAccountViewModel, Account>()
.ForMember(entity => entity.Id, opt => opt.Ignore()) // We dont change id's
.ForMember(entity => entity.PrivacyLevel, opt => opt.MapFrom(viewModel => (PrivacyLevel)viewModel.NewSelectedPrivacyLevel));
}
}
Note that this does not have to apply to MVC, this can be used in WPF or other applications not tied to the Web, but since it's a good way of explaining, it's why I used MVC for this example.
When I first get a Http Get request for my profile, I grab the entity from the database
and map anything I actually need to the view
public ActionResult Index()
{
// Retrieve account from db
var account = new Account() { Id = 1, Name = "Patrick", AboutMe = "I'm just another dude", ProfilePictureUrl = "", PrivacyLevel = PrivacyLevel.Private, Friends = new Collection<Account>() };
// ViewModel abstracts the Entities and ensures behavour that only matters to the UI
var accountViewModel = Mapper.Map<AccountViewModel>(account);
return View(accountViewModel); // strongly typed view model
}
So my profile index view can use my enum view model
Here's the output
Now when I want to change what my privacy setting is, I can create a new EditAccountViewModel which allows me to submit a new value in a dropdown
public class EditAccountViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public string AboutMe { get; set; }
public int NewSelectedPrivacyLevel { get; set; }
public PrivacyLevelViewModel SelectedPrivacyLevel { get; set; }
public SelectList PrivacyLevels
{
get
{
var items = Enum.GetValues(typeof (PrivacyLevelViewModel))
.Cast<PrivacyLevelViewModel>()
.Select(viewModel => new PrivacyLevelSelectItemViewModel()
{
Text = viewModel.DescriptionAttr(),
Value = (int)viewModel,
});
//SelectPrivacyLevel was mapped by AutoMapper in the profile from
//original entity value to this viewmodel
return new SelectList(items, "Value", "Text", (int) SelectedPrivacyLevel);
}
}
}
Now once I send a post of my new changed value, the interesting part is how I modify the "real" entity from the db with the updated privacy setting
On submitting the form back to my edit action you can i get the original real db entity and then merge changes if the ViewModel state is valid
AutoMapper allows you to configure how ViewModels can be mapped to Entities,
if some properties should change, from integer entities to string values for view models,
maybe you want an enum to really be a string in the "view" and only the enum for the db,
with auto mapper it allows you to configure all these scenarious, and through convention
you dont need to configure "every single property" if your view models have the same
property names/camel case to upper case.
Lastly, before you can use these Profiles, you must load them at the application entry point, like global.asax or Main.
AutoMapper only needs to be 'configured' once to load any sort of profiles defined in the application. With some reflection you can load all Profiles in your assembly with this code:
public class AutoMapperConfig
{
public static void RegisterConfig()
{
Mapper.Initialize(config => GetConfiguration(Mapper.Configuration));
}
private static void GetConfiguration(IConfiguration configuration)
{
configuration.AllowNullDestinationValues = true;
configuration.AllowNullCollections = true;
IEnumerable<Type> profiles = Assembly.GetExecutingAssembly().GetTypes().Where(type => typeof(Profile).IsAssignableFrom(type));
foreach (var profile in profiles)
{
configuration.AddProfile(Activator.CreateInstance(profile) as Profile);
}
}
}
I call the configuration in my global.asax:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
AutoMapperConfig.RegisterConfig(); // AutoMapperConfig.cs
}
More information about how to use AutoMapper and how it can benefit you can be found
here:
AutoMapper Github
In the end I came up with a much simpler solution: I just used an extension method to get the description of the enum. That also made it a lot easier for localization, so I could use a Resource string.
public static string Description(this PrivacyLevel level) {
switch (level) {
case PrivacyLevel.Public:
return Resources.PrivacyPublic;
case PrivacyLevel.FriendsOnly:
return Resources.PrivacyFriendsOnly;
case PrivacyLevel.Private:
return Resources.PrivacyPrivate;
default:
throw new ArgumentOutOfRangeException("level");
}
}
Some other idea:
Use byte PrivacyLevelByte in your EF classes. Create additional partial class for that particular model where you define property
PrivacyLevel PrivacyLevelEnum
{
get { return (PrivacyLevel)PrivacyLevelByte; }
set { PrivacyLevelByte = (byte)value;}
}
and define PrivacyLevel enum in your code and not by EF designer.
That allows you to handle any attributes but still gives you enum properties on EF models.

Exposing an object through a 'view' interface

I've been trying to find a flexible way of exposing an object through a 'view'. I'm probably better off explaining by way of example.
I have an Entity Framework entity model, and a web service that can be used to query it. I am able to return the entity classes themselves, but this would include some fields I might not want to share - IDs, for examples, or *Reference properties from any associations in the entity model.
I figure what I need is a view of the data, but I don't particular want to write a view wrapper class for every return type. I'm hoping I'll be able to define an interface and somehow make use of that. For example:
interface IPersonView
{
string FirstName { get; }
string LastName { get; }
}
-
// (Web service method)
IPersonView GetPerson(int id)
{
var personEntity = [...];
return GetView<IPersonView>(personEntity);
}
However, in order to do something like this, I'd have to have my entities implement the view interfaces. I was hoping for a more flexible 'duck-typed' approach as there may be many views of an object, and I don't really to want to have to implement them all.
I've had some success building a dynamic type by reflecting the interface and copying fields and properties across, but I'm not able to cast this back to the interface type in order to get strong typing on the web service.
Just looking for some comments and advice, both would be welcome. Thanks.
You shouldn't ever really be passing entities directly out to a client, they should be used for persistance only. You should introduce DTOs/POCOs tailored to whatever data your API wants to return e.g.
public class PersonDto
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
// public API method
public PersonDto GetPersonApi(int id)
{
var personEntity = // pull entity from db
return new PersonDto()
{
FirstName = personEntity.FirstName,
LastName = personEntity.LastName
};
}
This keeps a clean separation between your persistence layer & public interface. You can use a tool like AutoMapper to do the legwork in terms of mapping the data across. Just setup a mapping once e.g. in your global asax:
protected void Application_Start()
{
Mapper.CreateMap<Person, PersonDto>();
}
...
// public API method
public PersonDto GetPersonApi(int id)
{
var personEntity = // pull entity from db
return Mapper.Map<Person, PersonDto>(personEntity);
}
I typically see this done with AutoMapper or a similar tool. It makes mapping between similar classes much simpler. You still have to create the Views (which in an MVC-context would be a Model), but the most tedious part (the mapping) is taken care of for you so long as you use the same field names.
As a side note, sharing IDs and other reference data will be necessary if you want to update the data, since you'll need to know the keys in order to know which record(s) to update.

ASP.net MVC - Should I use AutoMapper from ViewModel to Entity Framework entities?

I am currently using AutoMapper to map my Entity Framework entities to my View Model:
public class ProductsController : Controller
{
private IProductRepository productRepository;
public ProductsController(IProductRepository productRepository)
{
this.productRepository = productRepository;
}
public ActionResult Details(int id)
{
var product = productRepository.GetProduct(id);
if( product == null )
return View("NotFound");
ProductDetailsViewModel model = Mapper.Map<Product, ProductDetailsViewModel>(product);
return View(model);
}
}
This works well. The question I have is when I need to go from my View Model to my entity in order to update the database. Should I be using AutoMapper for this? Is this a bad/dangerous practice?
It seems like AutoMapper is good for flattening a complex type to a simple (flat) type, but so far I'm struggling trying to go from a flat/simple to a more complex type like my entity with the various navigation properties.
If it is a bad idea to use AutoMapper to do this, then what would my code look like for a Create action?
public ActionResult Create(CreateProductViewModel model)
{
if( ModelState.IsValid )
{
// what do i do here to create my Product entity?
}
}
What about an Edit action?
public ActionResult Edit(int id, EditProductViewModel model)
{
Product product = productRepository.GetProduct(id);
// how do i convert my view model to my entity at this point???
}
I'm a of the mindset that updating your entities is a pretty big deal and that no automated tool should ever be used. Set the properties manually.
Yes its a very tiny amount of more code but automapper or running updatemodel on database entities can sometimes have unintended consequences. Better to make sure your writes are done correctly.
I use AutoMapper with a specialized mapping class that understands how to make a complex model from a simple one. AutoMapper is used to handle the one-to-one mapping and the custom logic in the class for doing the more complex things (like relationships, etc.). All of the AutoMapper configuration is done in the static constructor for the mapping class, which also validates the mapping configuration so that errors fail early.
public class ModelMapper
{
static ModelMapper()
{
Mapper.CreateMap<FooView,Foo>()
.ForMember( f => f.Bars, opt => opt.Ignore() );
Mapper.AssertConfigurationIsValid();
}
public Foo CreateFromModel( FooView model, IEnumerable<Bar> bars )
{
var foo = Mapper.Map<FooView,Foo>();
foreach (var barId in model.BarIds)
{
foo.Bars.Add( bars.Single( b => b.Id == barId ) );
}
return foo;
}
}
You could also try configuring AutoMapper to only map Scalar properties (instead of having to .Ignore() every single property you don't want it to (including inherited properties like .EntityKey and .EntityState).
AutoMapper.Mapper.CreateMap<EntityType, EntityType>()
.ForAllMembers(o => {
o.Condition(ctx =>
{
var members = ctx.Parent.SourceType.GetMember(ctx.MemberName); // get the MemberInfo that we are mapping
if (!members.Any())
return false;
return members.First().GetCustomAttributes(typeof(EdmScalarPropertyAttribute), false).Any(); // determine if the Member has the EdmScalar attribute set
});
});
Some more info at http://www.prosoftnearshore.com/blog/post/2012/03/14/Using-AutoMapper-to-update-Entity-Framework-properties.aspx
Essentially automapping is bad, I wrote a blog post on this http://blog.gavryli.uk/2015/12/02/why-automapping-is-bad-for-you/

Categories

Resources