0

I have a pretty long model class with lots of properties and navigation fields.

public class Customers
{
    public Customers()
    {
        this.Files = new HashSet<Files>();
    }

    public int CustomerID { get; set; }
    public int InspectionID { get; set; }
    public int Position { get; set; }
    public Nullable<int> Height { get; set; }
    public Nullable<int> Weight{ get; set; }
    //.....many more properties
//there are some navigation properties below
//.....
}

In order to break up the view (and the business logic requires it), I created about 14 partial views that have subsets of the properties in this class and the corresponding partial view is loaded onto a main edit view on page load.(updated after comments) On another view, when a link is clicked, the edit GET action is called with the CustomerID parameter passed to the controller which loads the Edit view with corresponding partialview like this

@model myApplication.Models.CustomersViewModel //Trial 2 from below uses                    //this and 
@model myApplication.Models.Customers //Trial 1 from below uses this 
 
@{
    ViewBag.Title = "Edit";
}
@section Styles {
}
<h2>Edit</h2>
@using (Html.BeginForm())
{
   @Html.AntiForgeryToken()
        <div>
          @*All commong properties here*@
        </div>
          
    @*the corresponding PartialView with subset /selected/ properties here -UPDATE: please note that the partailview is named as the PK i.e. inspection id (Sorry, I worte wrongly on the initial post)
  
    @Html.Partial("_edittemplates/" + Model.InspectionID)

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-primary" />
            </div>
        </div>
    </div>

Now, I don't want to create 14 ViewModels for each of the 14 partialviews with the subsets of these properties because it seemed wasteful. What I wanted to do is use one big ViewModel and use automapper to manage which properties are loaded on the view (both from main & partial) and map these specific properties without having to duplicating(copy-pasting) all the properties of the Model class into CustomersViewModel.

Trial 1:

I tried to map the class to itself but it back-fired by messing with foreign key values/database relationships - error message goes like "The relationship could not be changed because one or more of the foreign-key properties is non-nullable....". Then I added .ForAllMembers(opt=>opt.Ignore()) and it got messier.

            Customers customers= db.Customers .SingleOrDefault(c => c.CustomerID == id);
        Customers editcustomers = AutoMapperMappings.mapper.Map<Customers , Customers >(customers);

Trial 2: So, what I thought would be another way to get away without creating 14 partialviews and without copy-pasting all the properties using automapper was something like this

public class CustomersViewModel
{

    public Customers customers { get; set; }
}

then map & reverse map

 cfg.CreateMap<CustomersViewModel, Customers>().ReverseMap();

the GET controller

                Customers customers = db.Customers.SingleOrDefault(c => c.CustomerID == id);
        CustomerEditViewModel editcustomers = AutoMapperMappings.mapper.Map<Customers, CustomersEditViewModel>(customers);

        editcustomers.customers = customers;
return View(editcustomers);

then the POST method

Customers locate = db.Customers .Find(editcustomers.customers.customersID);

            AutoMapperMappings.mapper.Map(editcustomers.customers, locate);
            //locate = editcomponents.components;
            //db.Entry(locate).State = EntityState.Modified;
            db.SaveChanges(); 

but, even though the mapping went well with no errors and the GET loaded the view and the POST received the modified values the db.SaveChanges(); does not receive the modified values update doesn't take place.

But if copy all the properties from the Model class and copy them in the ViewModel, the mapping via automapper works and the data on the view gets saved

public class CustomersViewModel
{

    public int CustomerID { get; set; }
    public int InspectionID { get; set; }
    public int Position { get; set; }
    public Nullable<int> Height { get; set; }
    public Nullable<int> Weight{ get; set; }
    //...and all other properties 
}

My question is, is there a way to do this with one big ViewModel without re-listing all the properties of the Model Class again? Many thanks in advance for your suggestions!

user3590235
  • 153
  • 7
  • Please let me know if there anything I can clarify? I did not understand why the down votes... I may not expressed my problem as well as I thought :( – user3590235 May 17 '16 at 17:40
  • I'm not quite sure what you expect from AutoMapper here. The tool can't magically know your partial view only used a subset of the (large) View Model (which is essentially identical to the entity). Map your entity to view models once in the app configuration. In the controller actions, use the mapping to populate the view models from the entity. [Manually write your properties back to a proper entity for saving](http://stackoverflow.com/questions/7588907/asp-net-mvc-should-i-use-automapper-from-viewmodel-to-entity-framework-entitie). – Jasen May 17 '16 at 18:06
  • Thank you Jasen for your response!! I see your point; if I understand you correctly, I should define properties in the VM then automapper will use that to know which ones to map in the Model. I was wondering, if I define in the VM- public Customers customers { get; set; }, weather automaper can use that to map all fields with the Model (like map to itself). In other words, I am only breaking up the view not the model class. – user3590235 May 17 '16 at 18:33
  • Yes, model ABC can be broken into view model A, vm B, and vm C. Configure AutoMapper for `ABC => A`, `ABC => B`, `ABC => C`. You write this configuration once and thereafter use as `var vm = mapper.Map(db.ABC.Where(condition))`. – Jasen May 17 '16 at 18:45
  • Sorry for not being clear! Yes, I use automapper just like that usually. But, now what I wanted to do is not break up model ABC. I want to use automapper to map model ABC to itself or to a big ABCVM of the same size, because I won't know the properties BiginForm() has when it's created on page load since I broke up the big view it into small partials which load with different combination of properties the at page load. I can settle for copy-pasting all properties as I shown above but that will force me to update it whenever I update form model from the database. Thanks! – user3590235 May 17 '16 at 19:10

0 Answers0