Using Entity Framework (.edmx Model) and Razor Views, create a dropdown list for MVC3 and insert a database record into several tables.

asp.net-mvc-3 edmx entity-framework html.dropdownlistfor razor

Question

I searched through hundreds of articles on this site on how to use Razor Views in MVC 3 to build DropDown Lists, but I was unable to locate one that worked for me.

Situation: In the end, I want to create a view that would let me add an employee to a database.

Here is a picture of the.EDMX model I'm using, along with the tables that the create() function will use:

enter image description here

Objectives:

  1. I am using a different @model in the Notify Partial View from the Create View; I'm not sure if that is safe??? @model ShadowVenue.Models.Employee & @model ShadowVenue.Models.StaffNotify) when creating an employee (I have the Create.cshtml (strongly typed) made with a Partial View for the StaffNotify Checkboxes).

  2. Create a drop-down box for StaffTypeId that displays the [Type] string value in the drop-down but inserts the [StaffTypeId] value from the table "StaffType," which has a 1 to many connection.

  3. Create a drop-down box for GenderId that displays the text value [Gender] but inserts the [GenderId] value from the table "Genders," which has a 1 to many connection.

  4. The Record is added to the database (I have the Staff Notifications in a separate table with a 1 to 1 relationship on the StaffId Primary Key)

I feel as if the Controller code is giving me problems in this.

I am unsure of the appropriate approach and am not sure whether I should develop a stored procedure inside the EDMX model or come up with some query or method syntax.

My first substantial MVC3 application utilizing an Entity Framework model.

(Please let me know if you need any of the Navigation Property Names to aid with the solution, and I'll provide them to you.)

1
49
1/14/2018 7:51:50 PM

Accepted Answer

Do not send database models straight to your views. Since you have the good fortune to be utilizing MVC, use view models to encapsulate.

Create the following view model class:

public class EmployeeAddViewModel
{
    public Employee employee { get; set; }
    public Dictionary<int, string> staffTypes { get; set; }
    // really? a 1-to-many for genders
    public Dictionary<int, string> genderTypes { get; set; }

    public EmployeeAddViewModel() { }
    public EmployeeAddViewModel(int id)
    {
        employee = someEntityContext.Employees
            .Where(e => e.ID == id).SingleOrDefault();

        // instantiate your dictionaries

        foreach(var staffType in someEntityContext.StaffTypes)
        {
            staffTypes.Add(staffType.ID, staffType.Type);
        }

        // repeat similar loop for gender types
    }
}

Controller:

[HttpGet]
public ActionResult Add()
{
    return View(new EmployeeAddViewModel());
}

[HttpPost]
public ActionResult Add(EmployeeAddViewModel vm)
{
    if(ModelState.IsValid)
    {
        Employee.Add(vm.Employee);
        return View("Index"); // or wherever you go after successful add
    }

    return View(vm);
}

Finally, change the inherited type to ShadowVenue in your view (you may scaffold it first using Visual Studio). Models.EmployeeAddViewModel. Use: also in the locations of the drop-down menus.

@Html.DropDownListFor(model => model.employee.staffTypeID,
    new SelectList(model.staffTypes, "ID", "Type"))

similar with the gender dropdown

@Html.DropDownListFor(model => model.employee.genderID,
    new SelectList(model.genderTypes, "ID", "Gender"))

as of the comments

If you can do without the genderTypes in the view model mentioned above for gender, you could also do this (however, on second thought, maybe I'd produce this server side in the view model as an IEnumerable). hence, instead ofnew SelectList... You would utilize your IEnumerable as shown below.

@Html.DropDownListFor(model => model.employee.genderID,
    new SelectList(new SelectList()
    {
        new { ID = 1, Gender = "Male" },
        new { ID = 2, Gender = "Female" }
    }, "ID", "Gender"))

The last alternative is a lookup table. In essence, you store key-value pairs connected to a Lookup type. Gender is one category, whereas States, etc. are additional examples. My preferred format for my is as follows:

ID | LookupType | LookupKey | LookupValue | LookupDescription | Active
1  | Gender     | 1         | Male        | male gender       | 1
2  | State      | 50        | Hawaii      | 50th state        | 1
3  | Gender     | 2         | Female      | female gender     | 1
4  | State      | 49        | Alaska      | 49th state        | 1
5  | OrderType  | 1         | Web         | online order      | 1

When a collection of data doesn't change often but has to be periodically enumerated, I prefer to utilize these tables.

Hope this is useful!

76
3/23/2011 2:31:45 PM

Popular Answer

Actually, I must concede that David's idea is sound, however the following issues really trouble me:

  1. Never send your model to the This is accurate. view.
  2. If you design aViewModel , then add the Model as a participant in theViewModel Once you have successfully submitted your model to the View => this is AWFUL
  3. sending the available choices to the view => this is a bad fashion using dictionaries

How therefore can you improve coupling?

I'd use a device likeAutoMapper alternatively use the mapping between ValueInjecterViewModel both Model.AutoMapper While it does appear to have a better syntax and feel, the present version is lacking a very critical feature: It cannot execute the mapping fromViewModel to Specify (under certain circumstances like flattening, etc., but this is off topic) I thus now favor usingValueInjecter .

So you design aViewModel with the fields in the view that you need. The SelectList entries you need are added as lookups. And you've already added them to SelectLists. So you can do a search from a source that supports LINQ, choose the ID and text field, and then save it as a selectlist: You benefit from not having to construct a new type (dictionary) for lookup; instead, simply transfer the existing type.new SelectList from the controller to the view.

  // StaffTypes is an IEnumerable<StaffType> from dbContext
  // viewModel is the viewModel initialized to copy content of Model Employee  
  // viewModel.StaffTypes is of type SelectList

  viewModel.StaffTypes =
    new SelectList(
        StaffTypes.OrderBy( item => item.Name )
        "StaffTypeID",
        "Type",
        viewModel.StaffTypeID
    );

In the perspective, all you have to do is dial

@Html.DropDownListFor( model => mode.StaffTypeID, model.StaffTypes )

You must take a parameter representing the type of your controller back in the post element of your method in the controller.ViewModel . After that, you validate. You must keep in mind to re-populate the form if the validation fails.viewModel.StaffTypes Because this item will be null when you enter the post function, utilize SelectList. Therefore, I usually split such population-related issues into a function. Just make a call backreturn new View(viewModel) if anything is not right. MVC3 will automatically display validation problems in the view.

You may add validation errors by indicating which field they pertain to if you have your own validation code. Verify the documentation onModelState to learn more about it

If theviewModel If legitimate, you must take the following action:

You must fill a model from the data if you are creating a new item.viewModel (Best suited isValueInjecter ). After that, you may commit modifications and add it to the EF collection for that type.

If there is an update, you load the most recent database item into a model first. The values from the then you may copy theviewModel returning to the model, utilizingValueInjecter does things for you quickly). Thereafter, you canSaveChanges and finished.

If something is confusing, please inquire.



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow