Creating dropdownlist for entity in MVC - asp.net-mvc

I'm new to MVC and are having a hard time figuring some "basic" things out.
I have a ViewModel shaped as follows:
public class ProjectViewModel
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
public string Description { get; set; }
public DateTime CreatedDate { get; set; }
[Required]
[Display(Name = "Final due date")]
public DateTime FinalDueDate { get; set; }
[Required]
[Display(Name = "Attached equipment")]
public Equipment AttachedEquipment { get; set; }
}
In my Create view I would like to be able to select the value for AttachedEquipment from a dropdownlist. I have a table in my database with all the available Equipments.
I know there is an #Html helper #Html.DropDownListFor which serves this very purpose. However I fail to see how I get the values from the database and spit them out into my view.
My ProjectController looks like this:
private AdventureWorks db = new AdventureWorks();
// GET: Project
public ActionResult Index()
{
return View();
}
[HttpGet]
public ActionResult Create()
{
// I'm guessing this is where I need to do some magic
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ProjectViewModel model)
{
if (ModelState.IsValid)
{
var project = new Project
{
Title = model.Title,
Description = model.Description,
CreatedDate = DateTime.Now,
FinalDueDate = model.FinalDueDate,
Equipment = model.Equipment
};
db.Projects.Add(project);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
How do I load the Equipment values from my DB into a dropdownlist in my Create view?

Since you cant bind a dropdownlist to the complex object AttachedEquipment, I would change the view model to include properties for the selected equipment and a SelectList for the options
public class ProjectViewModel
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
public string Description { get; set; }
public DateTime CreatedDate { get; set; }
[Required]
[Display(Name = "Final due date")]
public DateTime FinalDueDate { get; set; }
[Required(ErrorMessage="Please select equipment)]
public int? SelectedEquipment { get; set; }
public SelectList EquipmentList { get; set; }
}
Controller
public ActionResult Create()
{
ProjectViewModel model = new ProjectViewModel();
// Assumes your Equipments class has properties ID and Name
model.EquipmentList = new SelectList(db.Equipments, "ID", "Name");
return View(model);
}
View
#model ProjectViewModel
#using(Html.BeginForm())
{
....
#Html.DropDownListFor(m => m.SelectedEquipment, Model.EquipmentList, "--Please select--")
....
}
Alternatively you can bind to m => m.AttachedEquipment.ID (assuming Equipment contains property ID)

Related

There is no ViewData item of type 'IEnumerable<SelectListItem> MVC

I've done this EF MVC Application (Code First) with listing/editing/deleting functions. Everything works fine, but now I need to add two dropdown fields. Product has a category and a subcategory which needed to be edited. This is what I have so far:
Main class where ProductSubcategoryID is a foreign key
public class Product
{
public int ProductID { get; set; }
public string Name { get; set; }
public string ProductNumber { get; set; }
public int? ProductSubcategoryID { get; set; }
public IEnumerable<SelectList> SelectedCat = new List<SelectList> {};
public IEnumerable<SelectList> SelectedSubCat = new List<SelectList> {};
}
public class ProductCategory
{
public int ProductCategoryID { get; set; }
public string Name { get; set; }
}
public class ProductSubcategory
{
public int ProductSubcategoryID { get; set; }
public int ProductCategoryID { get; set; }
public string Name { get; set; }
}
On the Product controller class I have:
public ActionResult Create()
{
ViewBag.SubcatSelection = new SelectList(dbSubcat.ProductSubcategories, "ProductSubcategoryID", "Name"); ;
return View();
}
and on Edit:
#Html.LabelFor(model => model.ProductSubcategoryID)
#Html.DropDownListFor(model => model.SelectedSubCat, ViewBag.SubcatSelection as SelectList, "ProductSubcategoryID", "Name");
The result:
There is no ViewData item of type 'IEnumerable<SelectListItem>' that has the key 'SelectedSubCat'.

Drop down list's selected value resets on form submit

When I go to edit a members Member Type by changing the drop down selected value, on postback the selected value resets itself to the top item and the user gets that member type.
Any ideas where I am going wrong?
View -
#Html.DropDownListFor(model => model.SelectedMemberType, new SelectList(Model.MemberTypes, "ID", "Name", (int)Model.MemberType))
Model -
public class MemberDetailModel
{
public int Id { get; set; }
public int CustomerId { get; set; }
[Required]
[DisplayName("First Name")]
public string FirstName { get; set; }
[Required]
[DisplayName("Last Name")]
public string LastName { get; set; }
public int SelectedMemberType { get; set; }
[Required]
[DisplayName("Member Type")]
public int MemberType { get; set; }
public virtual IList<MemberTypeModel> MemberTypes { get; set; }
public MemberDetailModel()
{
MemberTypes = new List<MemberTypeModel>();
}
}
Controller -
[Authorize]
public ActionResult Details(int id = 0)
{
ViewBag.MemberType = new SelectList(_memberTypeService.GetAll(), "ID", "Name");
MemberDetailModel member = _memberService.GetById(id);
IEnumerable<Gender> genders = Enum.GetValues(typeof(Gender))
.Cast<Gender>();
return View(member);
}
[HttpPost]
public ActionResult Details(MemberDetailModel model)
{
model.MemberType = model.SelectedMemberType;
if (ModelState.IsValid)
{
_memberService.UpdateMember(model);
return View(member);
}
return View(model);
}
As selectlist will be lost between postbacks, so just don't forget to set the MemberTypes again on postback. Most of the cases that is the issue.

MVC save to database

How to correctly save to database? I have the following but not working. I am using a custom ModelMetadata (ORDERMetadata) and setting it equal to the .edmx / order.cs model and trying to save it.
The key field in Order.cs model is [OrderID], but I am passing [model.Order_Number] which is unique value. I am currently, not passing [OrderID] in ORDERMetadata model. Is this required?
Order.cs:
public partial class ORDER
{
public int OrderID { get; set; }
public int Order_Number { get; set; }
public string Order_Type { get; set; }
}
ORDERMetadata model:
[MetadataType(typeof(ORDERMetadata))]
public partial class ORDER
{
// Blank. It's just here to add the class-level attribute.
}
public class ORDERMetadata
{
[Display(Name = "Order Number")]
public int Order_Number { get; set; }
[Display(Name = "Order Type")]
public string Order_Type { get; set; }
}
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(ORDERMetadata model)
{
if (!ModelState.IsValid)
{
return View(model);
}
try
{
// update order
ORDER order = new ORDER();
order.Order_Number = model.Order_Number;
order.Order_Type = model.Order_Type;
db.Entry(order).State = EntityState.Modified;
db.SaveChanges();
ViewBag.UpdateResult = "Order updated!";
return View();
}
}
Change to:
ORDER order = db.ORDERS.SingleOrDefault(p => p.Order_Number == model.Order_Number);

MVC Automapper update

i tried to update my database table some fields
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(MemberTasks membertaskdetails)
{
if (ModelState.IsValid)
{
MemberTasks Mtasks = db.MemberTask.Find(membertaskdetails.id);
Mtasks.Taskid = membertaskdetails.Taskid;
Mtasks.status = membertaskdetails.status;
AutoMapper.Mapper.Map(membertaskdetails,Mtasks);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(membertaskdetails);
}
ViewModel
public class MemberTasks
{
[Key]
[Display(Name = "ID")]
public int id { get; set; }
[Display(Name = "Task ID")]
public int Taskid { get; set; }
[Display(Name = "Status")]
public int status { get; set; }
[Display(Name = "Created By")]
public string createdby { get; set; }
[Display(Name = "Team Lead")]
public string TeamLead { get; set; }
[Display(Name = "Note")]
public string Note { get; set; }
[Display(Name = "Members")]
public string Membersid { get; set; }
}
Code is executed successfully but the problem is remaining fields also updated with null value i have 6 columns i want to update 2 columns only.
Any help ?
Your source and destination object used in AutoMapper are of the same type (MemberTasks). That's not how AutoMapper is supposed to be used. AutoMapper is used to map between domain models and view models.
So you must have a view model containing the properties passed from the view:
public class MemberTasksViewModel
{
public int Id { get; set; }
public int Taskid { get; set; }
public int Status { get; set; }
}
and then:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(MemberTasksViewModel viewModel)
{
if (ModelState.IsValid)
{
MemberTasks domainModel = db.MemberTask.Find(viewModel.Id);
Mapper.Map(viewModel, domainModel);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel);
}

Saving Viewmodel data to the Database in ASP.NET MVC

I am new to ASP.net MVC and am using a viewmodel rather than viewbags to populate my dropdowns since I've seen most people recommend against them. I have a slick UI that does cascading dropdowns and autocompletes (not shown here) but I can't seem to get my data saved back to the database.
Models:
public partial class Car
{
public int CarID { get; set; }
public string CarName { get; set; }
public int ModelID { get; set; }
public int ManufacturerID { get; set; }
public int CarColorID { get; set; }
public Nullable<decimal> Price { get; set; }
public string Description { get; set; }
public virtual CarColor CarColor { get; set; }
public virtual Manufacturer Manufacturer { get; set; }
public virtual CarModel CarModel { get; set; }
}
public partial class CarColor
{
public CarColor()
{
this.Cars = new HashSet<Car>();
}
public int ColorID { get; set; }
public string ColorName { get; set; }
public virtual ICollection<Car> Cars { get; set; }
}
public partial class CarModel
{
public CarModel()
{
this.Cars = new HashSet<Car>();
}
public int CarModelID { get; set; }
public int ManufacturerID { get; set; }
public string CarModelName { get; set; }
public virtual ICollection<Car> Cars { get; set; }
public virtual Manufacturer Manufacturer { get; set; }
}
public partial class Manufacturer
{
public Manufacturer()
{
this.Cars = new HashSet<Car>();
this.Manufacturer1 = new HashSet<Manufacturer>();
this.CarModels = new HashSet<CarModel>();
}
public int ManufacturerID { get; set; }
public string ManufacturerName { get; set; }
public Nullable<int> ParentID { get; set; }
public virtual ICollection<Car> Cars { get; set; }
public virtual ICollection<Manufacturer> Manufacturer1 { get; set; }
public virtual Manufacturer Manufacturer2 { get; set; }
public virtual ICollection<CarModel> CarModels { get; set; }
}
ViewModel:
public class AnotherTestViewModel
{
public Car car { get; set; }
public IEnumerable<SelectListItem> CarModels { get; set; }
public IEnumerable<SelectListItem> Manufacturers { get; set; }
public IEnumerable<SelectListItem> CarColors { get; set; }
}
Controller:
public ActionResult Create()
{
var model = new AnotherTestViewModel();
using (new CarTestEntities())
{
model.CarModels = db.CarModels.ToList().Select(x => new SelectListItem
{
Value = x.CarModelID.ToString(),
Text = x.CarModelName
});
model.Manufacturers = db.Manufacturers.ToList().Select(x => new SelectListItem
{
Value = x.ManufacturerID.ToString(),
Text = x.ManufacturerName
});
model.CarColors = db.CarColors.ToList().Select(x => new SelectListItem
{
Value = x.ColorID.ToString(),
Text = x.ColorName
});
}
return View(model);
}
//
// POST: /AnotherTest/Create
[HttpPost]
public ActionResult Create(AnotherTestViewModel model)
{
if (ModelState.IsValid)
{
db.Entry(model).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Details", "AnotherTestViewModel", new { id = model.car.CarID });
}
return View();
}
I saw a few recommendations to use Automapper because EntityState.Modified won't work, but I'm not sure how to configure it because using the code below didn't work.
Mapper.CreateMap<AnotherTestViewModel, Car>();
Mapper.CreateMap<Car, AnotherTestViewModel>();
var newCar = Mapper.Map<AnotherTestViewModel, Car>(model);
Any ideas?
Your view model should not be interacting with the database. View Models should only be used in the presentation layer (user interface) - hence the term "View" model. You should have another model (data model) that interacts with your database. Then you should have some type of service layer that handles your conversion between your view model and your data model (and vice versa). Your data model is the model generated by Entity Framework (which I assume is what you are using). To handle updates to your database, you need to instantiate a data context, grab the data entity from your database, make changes to that entity, and call save changes all in that data context. The data context will keep track of all changes to your entities and apply the necessary changes to your database when you call "save changes".
Example:
public void UpdateCar(CarViewModel viewModel)
{
using (DataContext context = new DataContext())
{
CarEntity dataModel = context.CarEntities.where(x => x.Id == viewModel.Id).First();
dataModel.Name = viewModel.Name;
dataModel.Type = viewModel.Type;
context.SaveChanges();
}
}
In this example, context will keep track of any changes to "dataModel". When "context.SaveChanges" is called, those changes will automatically be applied to the database.

Resources