8

Probably simple, but I seem to be missing something.

Two Models:

public class Hardware
{
    [Required]
    public int Id { get; set; }

    public int SerialNum { get; set; }
    public int ProductNum { get; set; }
    public string Notes { get; set; }
    public DateTime PurchaseDate { get; set; }
    public DateTime WarrantyExpiration { get; set; }

    public virtual Manufacturer Manufacturer { get; set; }
}

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

    [Required]
    public string Name { get; set; }

    public virtual ICollection<Hardware> Hardware { get; set; }
}

When I go to the Hardware Create view, I want to to be able to select from a dropdown of Manufacturers, and when it submits it should establish a relationship between the piece of hardware and the select Manufacturer.

At the moment, I've been using the following to build a selectList in the controller

SelectList selectList = new SelectList(db.Manufacturers, "Id", "Name");
ViewBag.selectList = selectList;

And then casting it in the view:

@Html.DropDownListFor(model => model.Manufacturer, ViewBag.selectList as SelectList)\

However, it seems like there should be a better way to do this - perhaps creating a viewModel that inherits from Hardware with a SelectList typed property?

Nick Brown
  • 1,167
  • 1
  • 21
  • 38
  • 1
    Having a View Model inherit from an Entity Framework entity would be a really bad idea. You should strive to completely isolate your views from your entities. It might be more work at first, but once you get the pattern down you will be really glad that you did. – Dismissile Jan 22 '13 at 21:51

1 Answers1

17

As your application gets more and more complicated, you will see your MVC application turning into M-VM-V-C, VM is dedicated ViewModels that usually adds all the things that your UI layer need in order to generate the UI.

I personally wouldn't go with inheritance in this case, because your ViewModel is not a specialized version of your Model. It's just what your UI need to create a View (this is really up to you).

My ViewModel would look something like this:

public class HardwareVm
{
     public Hardware Hardware { get; set; }
     public IEnumerable<SelectListItem> Manufacturers { get; set; }
} 

in the View:

@Html.DropDownListFor(model => model.Hardware.Manufacturer,  Manufacturers)

controller:

var manufacturers = db.Manufacturers.Select(m => new SelectListItem {Text = m.Name, Value = m.Id });
var model = new HardwareVm { Manufacturers = manufacturers };
Bassam Mehanni
  • 14,796
  • 2
  • 33
  • 41
  • Good advice, and it makes a lot of sense. Unfortunately, using a SelectList this way also produces a 'No parameterless constructor defined for this object' error. The relevant info I found was here: http://stackoverflow.com/a/7849504/451075 Unless of course I am using it wrong. – Nick Brown Jan 22 '13 at 23:00
  • Hmm, now I'm at a loss as how to assign it in my controller. I was using: HardwareVm hardware = new HardwareVm { Manufacturers = new SelectList(db.Manufacturers, "Id", "Name" )}; to create my SelectList – Nick Brown Jan 22 '13 at 23:55
  • Sadly, not. The initial issue is that `Name` can't be converted to Int type. However, even if you do get past that, you still wind up with a `There is no ViewData item of type 'IEnumerable' that has the key 'Hardware.Manu'` upon submission. I'm starting to think the ViewBag may not be so bad after all :D but I appreciate the help - the point about ViewModels is well-received. https://github.com/jelatin/inventoryTracker – Nick Brown Jan 23 '13 at 22:25
  • @NickBrown in the application I am currently working on, I have this type of dropdown lists all over the place, the error you are getting make me think you are still using `ViewData.Manufacturars` instead on `Model.Manufacturars` – Bassam Mehanni Jan 23 '13 at 22:39
  • 1
    I ended up using `SelectList selList = new SelectList(db.Manufacturers, "Id", "Name");` to build the list in the controller, as `Value = m.Id` threw an error about converting integers to strings and it did not like `.ToString()` – Nick Brown Jan 24 '13 at 17:47
  • I had this error as well, but the problem is with Linq to Entities somehow. You just have to make sure you are using `.Select(...)` on an `IEnumerable` and not on an `IQueryable`. If necessary you can cast with `.AsEnumerable()`. To be complete, the `Value = m.Id` in this code got me a compiler error; that's where the `.ToString()` needs to take place for me (and probably for Nick Brown as well). Might be something else that's not correct? Other than that, thanks for this answer. – Rodi Feb 25 '13 at 14:04