0

Goal: to save ViewModel object by Entity Framework. I have UserViewModel object which has list of UnitViewModel. Then, I have a UserAdapter class which converts UserViewModel into Entity Framework User object (see Convert()below how).

Now, my question is how do I convert this list of UnitViewModel to its corresponding Entity Framework Unit list? - Do I have to get each object from DB Context by calling something like context.Units.Where(u=>myListofUnitIDs.Contains(u.UnitID))?

public class UserViewModel
{
    public Guid? UserID { get; set; }
    public string UserName { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Password { get; set; }
    public DateTime? CreateTime { get; set; }
    public List<UnitViewModel> UserUnits { get; set; }
}


public class UnitViewModel
{
    public Guid UnitID { get; set; }
    public string Name { get; set; }
    public int? SortIndex { get; set; }
    public DateTime CreateTime { get; set; }
    public bool Assigned { get; set; }
}


public class UserAdapter
{
    public static User Convert(UserViewModel userView)
    {
        User user;
        if (userView.UserID.HasValue)
        {
            using (var provider = new CoinsDB.UsersProvider())
            {
                user = provider.GetUser(userView.UserID.Value);
            }
        }
        else
        {
            user = new User();
        }

        user.FirstName = userView.FirstName;
        user.LastName = user.LastName;
        user.Password = StringHelper.GetSHA1(userView.Password);
        user.UserName = user.UserName;
        user.CreateTime = DateTime.Now;

        // Problem here :)
        // user.Units = userView.UserUnits;

        return user;
    }
}

UPDATE: The main concern here is that I have to retrieve each Unit from database to match (or map) it with ViewModel.Unit objects, right? Can I avoid it?

5
  • 2
    Perhaps AutoMapper may become handy in this case. Commented Dec 11, 2015 at 7:39
  • 2
    If you do not want unexpected behaviors, prevent using any Auto... things, and write plain code such as userView.UserUnits.forEach(p=>user.Units.Add(new Unit{...})). It look ugly but work 100% Commented Dec 11, 2015 at 7:52
  • @GeneR, then I will have to get each Unit from database, right? Can I somehow avoid this? Commented Dec 11, 2015 at 8:02
  • 1
    provider.GetUser() may return user with all his units, then you can map it Commented Dec 11, 2015 at 8:06
  • Yes, but user may choose some new Unit(s) which do not exist in user.Units list Commented Dec 11, 2015 at 8:08

1 Answer 1

2

For your information, this operation is called as Mapping mainly. So, you want to map your view model object to the entity object.

For this, you can either use already existed 3rd party library as AutoMapper. It will map properties by reflection which have same name. Also you can add your custom logic with After method. But, this approach has some advantages and disadvantages. Being aware of these disadvantages could help you to decide whether you must use this API or not. So, I suggest you to read some articles about advantages and disadvantages of AutoMapper especially for converting entities to other models. One of such disadvantages is that it can be problem to change the name of one property in the view model in the future, and AutoMapper will not handle this anymore and you won't get any warning about this.

foreach(var item in userView.UserUnits)
{
     // get the mapped instance of UnitViewModel as Unit
     var userUnit = Mapper.Map<UnitViewModel, UserUnit>(item);
     user.Units.Add(userUnit);
}

So, I recommend to write your custom mappers. For example, I have created a custom library for this and it maps objects lik this:

 user.Units = userView.UserUnits
       .Select(userUnitViewModel => userUnitViewModel.MapTo<UserUnit>())
       .ToList();

And I am implementing these mapping functions as:

 public class UserUnitMapper:
        IMapToNew<UnitViewModel, UserUnit>
    {
        public UnitViewModel Map(UserUnit source)
        {
            return new UnitViewModel
            {
                Name = source.Name,
                ...
            };
        }
    }

And then in runtime, I am detecting the types of the objects which will be used during mapping, and then call the Map method. In this way, your mappers will be seperated from your action methods. But, if you want it urgently, of course you can use this:

foreach(var item in userView.UserUnits)
{
     // get the mapped instance of UnitViewModel as Unit
     var userUnit= new UserUnit()
           {
               Name = item.Name,
               ...
           };

     user.Units.Add(userUnit);
}
Sign up to request clarification or add additional context in comments.

11 Comments

Thanks for answer. Can you review my update too? Also, I want to map it backwards Get EF.Unit from ViewModel.Unit. For this I'm afraid I will have to retrieve each EF.Unit from database. Can I somehow avoid this database retrieval?
@levi If you want to update then, you need original unit entities in context. Do you want to send update query based on new view models?
@levi If you don't need their original values somehow, then you can create new Unit objects and just set their Primary Key properties only.
Yes exactly, point is update User with all its Units and other properties of course
So, the update is happening in Users table and UserUnits table. The latter contains UserID, UnitID only. I do not want to update Units table itself, but only UserUnits
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.