Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ViewModels and object manipulation in MVC

I want to understand (and finally appreciate because now it's only pain...) more ViewModels and strongly-typed Views in MVC.

My ViewModel

public class Combined
    {
        public IEnumerable<Domain> Domains { get; set; }
        public IEnumerable<RegInfo> RegInfos { get; set; }

        public Combined(IEnumerable<Domain> domains, IEnumerable<RegInfo> reginfos)
        {
            this.Domains = domains;
            this.RegInfos = reginfos;
        }

In Controller I pass data from repositories to an object of type Combined.

public ActionResult RegDetails(int id = 0)
        {
            var domain = from x in unitofwork.DomainRepository.Get(n => n.ID == id)
                         select x;

            var reginfo = from y in unitofwork.ReginfoRepository.Get(n => n.ID == id)
                          select y;

            var regdetails = new Combined(domain, reginfo);

            return View(regdetails);
        }

In a View (using Razor) I have @model project.namespace.Combined so I'm passing an object that holds two lists.

1/ Why can't I access each list item like this @Model.Domain.Name (noobish question but please help me to understand logic behind it)? I can do it form View "level" by using join but it's totally against MVC pattern. I think that only place to join those two tables is in Controller but it will create totally new object so do I need to create a Model for it?

2/ What's the best approach to get an IEnumerable object that will hold data from 2 or more tables that can be used to populate View (join, automapper)?

3/ Is there an approach that will allow me to create a Model that I will be able to use to POST to multiple tables from one FORM?

Thanks in advance.

like image 280
Chris Hermut Avatar asked Nov 26 '25 02:11

Chris Hermut


2 Answers

The logic of fetching the entities in your controller action is fine; that's the job of the controller. You don't, however, need a custom constructor on your view model: just use object initialization.

var regdetails = new Combined { Domains = domain, RegInfos = reginfo }

Now, as far as your view model goes, Domains and RegInfos are IEnumerables, but you're only fetching a single object for each. If your intention is to have a list type, then you should modify your LINQ to select multiple items, but if your intention is to in fact have just one object for each, then you should not use IEnumerables in your view model.

public class Combined
{
    public Domain Domain { get; set; }
    public RegInfo RegInfo { get; set; }
}

If you do that, then you will be able to access the Name property on the Domain instance with just @Model.Domain.Name. However, if you keep them list-types, then you must loop through them in your view (even if there's only one item in the list):

@foreach (var domain in Model.Domains)
{
    // Do something with domain.Name
}
like image 93
Chris Pratt Avatar answered Nov 28 '25 15:11

Chris Pratt


You get indeed a Model property in your view, and you can use Domains and RegInfos properties like you would do in c#. For example :

@{
    var firstDomain = Model.Domains.FirstOrDefault();
    // do some process with this variable
}

Or :

@foreach(var regInfo in Model.RegInfos)
{
    // do some other process        
}

If displayed data come from various data sources, it is best to make a specific view model. You need to avoid making calculations or applying business rules in your view, data should be preformatted before that. Another benefit is to pass only required data to your view : you don't want to fetch a huge object (or collection) from your database just for 2 displayed properties.

That view model can also be used when you submit a form. You can get it back if your post action has a parameter of the view model type, and if you correctly generate inputs in your view (by using some HtmlHelper like Html.Editor(For), etc).

Anyway, there's a lot to say about strongly typed views, and many resources / tutorials can be found across the web.

like image 28
Réda Mattar Avatar answered Nov 28 '25 16:11

Réda Mattar



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!