ViewBag multiple SelectList for dropdown list
asp.net-mvc-3, selectlist, viewbag
Solution
This is how I would have done it..
I would suggest that you don't send your domain models to the view, but rather create a view model for each view. Doing it this way you will only include what is needed on the screen.
Create a new view model for your Create view:
public class ProductCreateViewModel
{
// Include other properties if needed, these are just for demo purposes
public string Name { get; set; }
public string SKU { get; set; }
public string LongDescription { get; set; }
// This is the unique identifier of your category,
// i.e. foreign key in your product table
public int CategoryId { get; set; }
// This is a list of all your categories populated from your category table
public IEnumerable<Category> Categories { get; set; }
// This is the unique identifier of your model,
// i.e. foreign key in your product table
public int ModelId { get; set; }
// This is a list of all your models populated from your model table
public IEnumerable<Model> Models { get; set; }
}
Category class:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
}
Model class:
public class Model
{
public int Id { get; set; }
public string Name { get; set; }
}
In your Create view you would have the following:
@model MyProject.ViewModels.ProductCreateViewModel
@using (Html.BeginForm())
{
<table>
<tr>
<td><b>Category:</b></td>
<td>
@Html.DropDownListFor(x => x.CategoryId,
new SelectList(Model.Categories, "Id", "Name", Model.CategoryId),
"-- Select --"
)
@Html.ValidationMessageFor(x => x.CategoryId)
</td>
</tr>
<tr>
<td><b>Model:</b></td>
<td>
@Html.DropDownListFor(x => x.ModelId,
new SelectList(Model.Models, "Id", "Name", Model.ModelId),
"-- Select --"
)
@Html.ValidationMessageFor(x => x.ModelId)
</td>
</tr>
</table>
<!-- Add other HTML controls if required and your submit button -->
}
Your Create action methods:
public ActionResult Create()
{
ProductCreateViewModel viewModel = new ProductCreateViewModel
{
// Here you do database calls to populate your dropdowns
Categories = categoryService.GetAllCategories(),
Models = modelService.GetAllModels()
};
return View(viewModel);
}
[HttpPost]
public ActionResult Create(ProductCreateViewModel viewModel)
{
// Check that viewModel is not null
if (!ModelState.IsValid)
{
viewModel.Categories = categoryService.GetAllCategories();
viewModel.Models = modelService.GetAllModels();
return View(viewModel);
}
// Mapping
Product product = ... // Do your mapping here
// Insert product in database
productService.Insert(product);
// Return the view where you need to be
}
I would also recommend that you use AutoMapper to do the mappings for you between your domain model and view model. I would also recommend that you look at Fluent Validation to take care of your view model validations.
I hope this helps.
UPDATED ANSWER
The service that was used to get all the categories could look like this:
public class CategoryService : ICategoryService
{
private readonly ICategoryRepository categoryRepository;
public CategoryService(ICategoryRepository categoryRepository)
{
// Check if category repository is not null, throw exception if it is
this.categoryRepository = categoryRepository;
}
public IEnumerable<Category> GetAllCategories()
{
return categoryRepository.GetAllCategories();
}
}
categoryRepository is injected by Autofac.
Category service interface:
public interface ICategoryService
{
IEnumerable<Category> GetAllCategories();
}
I currently still use `Entity Framework 4.1` code first.
My category repository:
public class CategoryRepository : ICategoryRepository
{
MyContext db = new MyContext();
public IEnumerable<Category> GetAllCategories()
{
return db.Categories
.OrderBy(x => x.Name);
}
}
My category repository interface:
public interface ICategoryRepository
{
IEnumerable<Category> GetAllCategories()
}
Problem
I am trying to use dropdownList with two foreign keys which are modelId, and categoryId. And I am using ViewBag with selectList. ``` public ActionResult Create() { ViewBag.categoryId = new SelectList(db.Category, "categoryId", "name"); ViewBag.modelId = new SelectList(db.Model, "modelId", "name"); return View(); } // // POST: /Product/Create [HttpPost] public ActionResult Create(Product product) { if (ModelState.IsValid) { db.Product.Add(product); db.SaveChanges(); return RedirectToAction("Index"); } ViewBag.categoryId = new SelectList(db.Category, "categoryId", "name", product.categoryId); ViewBag.modelId = new SelectList(db.Model, "modelId", "name", product.modelId); return View(product); } ``` And here is my Create.cshtml. ``` <div class="editor-label"> @Html.LabelFor(model => model.Category) </div> <div class="editor-field"> @Html.DropDownList("categoryId", "--Select--") </div> <div class="editor-label"> @Html.LabelFor(model => model.Model) </div> <div class="editor-field"> @Html.DropDownList("modelId", "--Select--") </div> ``` When I press submit button, error come up, 'An item with the same key has already been added' What is problem? Is it problem with in Model? Here is my models. ``` --Prodruct.cs-- public class Product { [Key] public int productId { get; set; } [Required(ErrorMessage = "Please select category")] public int categoryId { get; set; } [Required(ErrorMessage = "Please select model")] public int modelId { get; set; } [DisplayName("Model name")] public String model { get; set; } public virtual Category Category { get; set; } public virtual Model Model { get; set; } } --Category.cs-- public class Category { [Key] public int categoryId { get; set; } public String name { get; set; } } --Model.cs-- public class Model { [Key] public int modelId { get; set; } public String name { get; set; } } --RentalDB.cs-- public class rentalDB : DbContext { public DbSet<Product> Product { get; set; } public DbSet<Model> Model { get; set; } public DbSet<Customer> Customer { get; set; } public DbSet<Order> Order { get; set; } public DbSet<Cart> Cart { get; set; } public DbSet<Category> Category { get; set; } public DbSet<OrderDetails> OrderDetails { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); } } ``` Where it is wrong? Index page in Create can get category data and model data. However, when I submit it, it has error, 'An item with the same key has already been added'. Could you help me where has got problem? Thank you. --added more coding-- I am using this LINQ. Probably here has problem. How can I add 'Model' entity in here? ``` var product = from a in db.Product.Include(a => a.Category) select a; ```