aman
aman

Reputation: 6252

Correctly Mapping viewmodel to entity

I have my entity as:

public class User
{
    public int Id { get; set; }

    public string Name { get; set; }

public string Address { get; set; }
}

I have my UserViewModel as

public class UserViewModel 
{
    public int Id { get; set; }

    public string Name { get; set; }

    public string Address { get; set; }
}

I am using these as below in my controller:

//This is called from my view via ajax
 public void Save(UserViewModel uv)
 {
    // this throws error: cannot convert from UserViewModel to Entity.User
    MyRepository.UpdateUser(uv);
 }

My UpdateUser in repository class is as below:

  public void UpdateUser(User u)
  {        
   var user = GetUserDetails(u.Id);

    user.Name = u.Name;
    user.Address = u.Address;

   //using entity framework to save
  _context.SaveChanges();
  }

How can I correctly map UserViewModel in my controller to my entity

Upvotes: 2

Views: 17488

Answers (3)

Aria
Aria

Reputation: 3844

By using AutoMapper you can do something like:

 public void Save(UserViewModel uv)
 {
    // this throws error: cannot convert from UserViewModel to Entity.User
   var config = new MapperConfiguration(cfg => {

                cfg.CreateMap<UserViewModel , User>();

            });
    User u = config.CreateMapper().Map<User>(uv);
    MyRepository.UpdateUser(u);
 }

Or manually :

 public void Save(UserViewModel uv)
 {
    User u = new User()
      {
        Id = uv.Id
        Name = uv.Name;
        Address = uv.Address;
      };
    MyRepository.UpdateUser(u);
 }

Which is not good to do it manually if you change your view-model and your model then you should change your code also, but with Automapper you don't need to change the code.

EDIT1:

This is not good idea to use model-view in repository (DataAccess Core) so it would be better to keep your public void UpdateUser(User u) and don't change it, in outside it is better to pass user to UpdateUser not UserViewModel like what you have done before.

EDIT2:

In my opinion non of answered posts doesn't related to SOC (Separation on concerns) even mine...

1- When I passed UserViewModel I've violated the SOC ....

2- In the other side if I got User in Peresentation layer directly I also violated the SOC.

I think the best way is a middle layer as proxy....

Presentation <----> Proxy <----> Repository.

Upvotes: 8

Shyju
Shyju

Reputation: 218782

You are doing the mapping of property values(view model->enity model) inside your repositories UpdateUser method. So use the view model class (UserViewModel) as the parameter type of that.

public void UpdateUser(UserViewModel  u)
{        
    // Get the entity first
    var user = GetUserDetails(u.Id);

    // Read the property values of view model object and assign to entity object
    user.Name = u.Name;
    user.Address = u.Address;

    //using entity framework to save
    _context.SaveChanges();
}

Now from your Save method ,you can pass the view model object to this method.

This will fix your compile time error (which is your current problem in the question), but be careful about what classes you are using in what layers. If you are too much worried about using a view model class in your data access layer, you can do that in a middle service layer. But then you are getting the entity model in that layer and doing the update there.

Remember, there is no definite answer for that question. Use the approach you think is readable and consistent with the project/ team. Often times, i tend to use the term "Common DTO classes" than "View models" so i can peacefully pass those around to another layer. I keep them in a separate project (called Common DTO) and this will be cross cutting across other projects. That means i will add a reference to this Common DTO project in my Web/UI layer and my data access/service layer and use those as needed.

Upvotes: 2

JuanR
JuanR

Reputation: 7783

Your repository deals with objects of type User, so you need to map the values back to an instance of that type and then make the call.

Assuming you have a method to get the user called GetUser:

public void Save(UserViewModel uv)
{
    var user = MyRepository.GetUser(uv.Id);
    user.Name = uv.Name;
    user.Address = uv.Address;
    MyRepository.UpdateUser(user);
}

You can then save the changes in your repository class. You can attach the object to make sure there are no issues if the object was created in a different context:

public void UpdateUser(User u)
{      
    _context.Users.Attach(u);
    _context.Entry(u).State = EntityState.Modified;
    _context.SaveChanges();
}

Upvotes: 2

Related Questions