MVC 4 Simple Populate DropDown from database model - c#

I feel a bit stupid.
I'm trying to get a hang of MVC 4, using boxing as a functional example.
I have WeightCategories in the database (Heavyweights, etc), and Boxers.
Seem simple. The relation is a boxer has a current weight category, but when I edit, I want it to be able to change it with a drop down.
I understand how to do it if it's a list I've made myself in the code, but I have problem understanding how to "load" the list from the WeightCategory table and show it in the view/model of the boxer.
So, here is my code for the WeightCategory item:
[Table("WeightCategories")]
public class WeightCategory
{
[Key]
public int WeightCategoryId { get; set; }
public WEIGHT_CATEGORIES WeightCategoryType { get; set; }
[Display(Name = "Weight Category Name")]
[Required]
[MinLength(5)]
public string Name { get; set; }
[Display(Name = "Weight Limit In Pounds")]
public int? WeightLimit { get; set; }
}
Here is the code for the boxer item
[Table("Boxers")]
public class Boxer
{
[Key]
public int BoxerId { get; set; }
public WeightCategory CurrentWeightCategory { get; set; }
[Required]
public string Name { get; set; }
public int Wins { get; set; }
public int Losses { get; set; }
public int Draws { get; set; }
public int Kayos { get; set; }
}
In the view, I'm really not sure how to tackle that, I'm pretty sure it's not automatic and I need to load the table somewhere in the controller maybe... I'm looking for best practice or something.
Something like that in the view at the end:
#Html.DropDownListFor(model => model.CurrentWeightCategory.WeightCategoryId,
new SelectList(Model.WeightCategories, "WeightCategoryId", "Name",
Model.WeightCategories.First().WeightCategoryId))

You could design a view model:
public class MyViewModel
{
public Boxer Boxer { get; set; }
public IEnumerable<SelectListItem> WeightCategories { get; set; }
}
and then have your controller action populate and pass this view model to the view:
public ActionResult Edit(int id)
{
var model = new MyViewModel();
using (var db = new SomeDataContext())
{
// Get the boxer you would like to edit from the database
model.Boxer = db.Boxers.Single(x => x.BoxerId == id);
// Here you are selecting all the available weight categroies
// from the database and projecting them to the IEnumerable<SelectListItem>
model.WeightCategories = db.WeightCategories.ToList().Select(x => new SelectListItem
{
Value = x.WeightCategoryId.ToString(),
Text = x.Name
})
}
return View(model);
}
and now your view becomes strongly typed to the view model:
#model MyViewModel
#Html.DropDownListFor(
x => model.Boxer.CurrentWeightCategory.WeightCategoryId,
Model.WeightCategories
)

Related

LINQ EF Grouping and Include exception

Need help in creating LINQ query to group and filter with related entities.
Here is my model classes.
public class Application
{
[DisplayName("Application")]
public int ApplicationId { get; set; }
[DisplayName("Application")]
public string Name { get; set; }
public List<DashboardEntry> DashboardEntries { get; set; }
}
public class Cluster
{
[DisplayName("Cluster")]
public int ClusterId { get; set; }
[DisplayName("Cluster")]
public string Name { get; set; }
}
[Bind(Exclude = "AlbumId")]
public class DashboardEntry
{
[ScaffoldColumn(false)]
public int DashboardEntryId { get; set; }
public int ClusterId { get; set; }
public int ApplicationId { get; set; }
public HealthStatusIndicator Status { get; set; }
public string Incident { get; set; }
public string Remarks { get; set; }
public virtual Cluster Cluster { get; set; }
public virtual Application Application { get; set; }
}
Index action method is as follows
public ActionResult Index()
{
//var dashboardEntries = db.DashboardEntries.Include(d => d.Application).Include(d => d.Cluster);
var dashboardEntries = db.DashboardEntries
.Include(d => d.Application)
.Include(d => d.Cluster)
.GroupBy(d => d.Application);
return View(dashboardEntries.ToList());
}
In the view, model declaration is as below.
#model IEnumerable<HealthCheckIndex.Models.DashboardEntry>
I'm getting an error
The model item passed into the dictionary is of type
'System.Data.Entity.Infrastructure.DbQuery1[System.Linq.IGrouping2[HealthCheckIndex.Models.Application,HealthCheckIndex.Models.DashboardEntry]]',
but this dictionary requires a model item of type
'System.Collections.Generic.IEnumerable`1[HealthCheckIndex.Models.DashboardEntry]'.
If I change the model declaration in view as below, I'm getting a another error that Cluster is not accessible.
#model IEnumerable>
I want to group the dashboard entries into different applications and filter the groups by choosing the max dashboard entry from each group.
The type that you are passing currently to the view does not match the specified type
#model IEnumerable<HealthCheckIndex.Models.DashboardEntry>
Currently you are passing something like a dictionary where the key is Application and the value is a IEnumerable of HealthCheckIndex.Models.DashboardEntry
In order to make it you have one of 2 options:
Replace the last line of the controller action with
return View(dashboardEntries.SelectMany(c=> c).ToList());
Change model definition in the view to match the list your returning

Fill dropdown list from database in create view

How can I fetch and insert data at a specific time in one view in mvc razor view? I mean to fill a dropdown list from the database in create view.
I want to fill the following when I add the subject and cheater models.
department list
semester list
standard list
stream list
cheater model:
namespace firstapp.Models
{
public class chepter
{
[ForeignKey("dip_id")]
public int dipart_id { get; set; }
public int chep_id { get; set; }
public string subject { get; set; }
public string chepter { get; set; }
public List<dipartment> dipartlist { get; set; }
public List<dipartment> stdlist { get; set; }
public List<dipartment> semlist { get; set; }
public List<dipartment> stremlist { get; set; }
}
}
department model:
namespace firstapp.Models
{
public class dipartment
{
public int dip_id { get; set; }
public string dipart { get; set; }
public string std { get; set; }
public string sem { get; set; }
public string strem { get; set; }
}
}
#Html.DropDownListFor(model => model.dipart_id, new SelectList(Model.dipartlist.Select(s => new SelectListItem() { Value = s.dip_id, Selected = false, Text = s.dipart })), "Select")
Change your model so the list property is a selectlist:
public SelectList<dipartment> dipartlist { get; set; }
Then, when you populate the model call a service class method(you might not have a service layer, I just prefer to not have database calls in the controller)
dipartlist = _departmentService.GetAsSelectList();
The GetAsSelectList service method looks like this:
public SelectList GetAsSelectList()
{
return (from d in _context.Set<department>().OrderBy(x => x.dipart)
select new
{
Id = d.dipart_id,
Name = d.dipart
}).ToList();
}
And finally your view:
#Html.DropDownListFor(model => model.dipart_id, Model.dipartlist)
This technique means you don't have linq in either the view or controller. Also as you're only creating the selectlist in one place (the service), you can cache it with MemoryCache to prevent multiple requests for the same data. And as it looks like you're populating 4 selectlists, this might be useful.

Using two models in one controller?

I currently have an application with a home page that shows a list of ten movies based on the date they were "created", or entered into the database. I would also like to show a list of the top ten movies based on the rating of each movie. Is there a way to pass in another model or alter my current ViewModel to do this? Here is the Index section of my Home Controller:
public ActionResult Index()
{
var model =
_db.Movies
.OrderByDescending(m => m.DateEntered)
.Take(10)
.Select(m => new MovieListViewModel
{
Id = m.Id,
Title = m.Title,
Genre = m.Genre,
ReleaseDate = m.ReleaseDate,
CountOfReviews = m.Reviews.Count()
});
return View(model);
}
And the ViewModel being passed in:
public class MovieListViewModel
{
public int Id { get; set; }
public string Title { get; set; }
public string Genre { get; set; }
[Display(Name="Year Released")]
public DateTime ReleaseDate { get; set; }
public int CountOfReviews { get; set; }
}
Create a model that encompasses both lists:
public class MovieListViewModel
{
public List<MovieModel> Top10ByCreated { get; set; }
public List<MovieModel> Top10ByRating { get; set; }
}
public class MovieModel
{
public int Id { get; set; }
public string Title { get; set; }
public string Genre { get; set; }
[Display(Name="Year Released")]
public DateTime ReleaseDate { get; set; }
public int CountOfReviews { get; set; }
}
Then in your controller:
var model = new MovieListViewModel();
model.Top10ByCreated = ...
model.Top10ByRating = ...
return View(model);
In your view, use MovieListViewModel as your model and use your two lists as needed.
Just create another viewmodel, with two properties for the two lists:
public class MovieIndexViewModel
{
public IEnumerable<MovieListViewModel> TopTenByDate { get; set; }
public IEnumerable<MovieListViewModel> TopTenByRating { get; set; }
}
In the controller you can create this viewmodel and pass the two lists:
public ActionResult Index()
{
var vm = new MovieIndexViewModel();
vm.TopTenByDate = ....;
vm.TomTenByRating = ...;
return View(vm );
}
You can compose a single view model that contains the two result sets. The controller then instantiates the parent type and populates the child collections as you see fit.
public sealed class HomeViewModel{
public MovieListViewModel TopTenByRating { get; set; }
public MovieListViewModel TopTenByDate { get; set; }
}
public ActionResult Index()
{
var model = new HomeViewModel();
model.TopTenByDate =
_db.Movies
.OrderByDescending(m => m.DateEntered)
.Take(10)
.Select(m => new MovieListViewModel
{
Id = m.Id,
Title = m.Title,
Genre = m.Genre,
ReleaseDate = m.ReleaseDate,
CountOfReviews = m.Reviews.Count()
});
model.TopTenByRating = // something else
return View(model);
}
For more complex scenarios, I prefer a dedicated composer that is responsible for setting up the view model (rather than having all the logic in the action method).
For a simple scenario like this, setting it up in the controller is the easiest way. If you find yourself needing to reuse the query logic, consider abstracting it to a helper class.
A different approach would be to create the main view and get it to render the results of 2 action methods returning 2 partial views each typed to one of the models.
You have different options you can use anyone of them
Use ViewModel
For view model you have to create a class and in this class you will define all models as properties of this class.Here are two classes.
public class EmployeeDetails
{
[Required]
[Display(Name = "Name")]
public string Name { get; set; }
}
public class Employee
{
public int Id { get; set; }
}
Here is viewmodel
public class ViewModel
{
public Employee emp { get; set; }
public EmployeeDetails empdet{ get; set; }
}
Now in Controller you will do like this
public ActionResult About()
{
ViewModel vm = new ViewModel();
vm.emp = new Employee();
vm.empdet = new EmployeeDetails();
return View(vm);
}
And in view you will receive it like this
#model ViewModel
Use Tuple
Tuple is used to store different types.You can store your required classes object in it and pass to view
In controller
Tuple<int, string> tuple = new Tuple<int, string>(1, "Hello world");
return View(tuple);
In view you will receive it like this
#model Tuple<int,string>

Show multiple models in a single view using ViewModel in Razor MVC3 (with only Details in view)

My task is to show multiple models into a single view.I've created a ViewModel for my requirement but I'm not meeting my requirement.
please have a look into the below code and rectify me where m i going wrong ???
public partial class StudentsDetail
{
public int StudentID { get; set; }
public int ParentID { get; set; }
public string StudentName { get; set; }
public string Gender { get; set; }
public string FatherName { get; set; }
public string MotherName { get; set; }
public Nullable<System.DateTime> DateOfBirth { get; set; }
public virtual ParentsDetail ParentsDetail { get; set; }
public virtual SchoolDetail SchoolDetail { get; set; }
}
//Model 2
public partial class ParentsDetail
{
public ParentsDetail()
{
this.StudentsDetails = new HashSet<StudentsDetail>();
}
public int ParentID { get; set; }
public string Occupation { get; set; }
public string Organization { get; set; }
public string AnnualIncome { get; set; }
public virtual ICollection<StudentsDetail> StudentsDetails { get; set; }
}
//ViewModel Which I have created
public class ParentsInformationViewModel
{
public List<StudentsDetail> StudentsDetails { get; set; }
public List<ParentsDetail> ParentsDetails { get; set; }
public ParentsInformationViewModel(List<StudentsDetail> _studentDetails, List<ParentsDetail> _parentsDetails) //Should i pass all the required parameters that i want to display in view ????
{
StudentsDetails = _studentDetails;
ParentsDetails = _parentsDetails;
}
//And finally this is my method defined in the StudentController (Have i defined it in a right place/way??)
public ActionResult StudentViewModel()
{
ViewBag.ParentsDetail = new ParentsDetail(); //ParentsDetail is my controller
List<StudentsDetail> studentListObj = StudentsDetailsDAL.GetStudentDetails();
List<ParentsInformationViewModel> ParentInfoVMObj = new List<ParentsInformationViewModel>();
//foreach (var student in studentListObj)
//{
// ParentInfoVMObj.Add(new ParentsInformationViewModel(student.StudentID, student.ParentID));
//}
//ParentInfoVMObj.Add(ParentInfoVMObj); /// don't know how to call the required viewmodel
return View(ParentInfoVMObj);
}
I know that the above method of a ViewModel is wrong but how to use it or where am i going wrong I can't get.
I want to display the ViewModel in the view as a detailed view .
Please, correct me as I'm a starter in MVC3 .
Thanks In Advance!!
In your controller, define your action method as follows.
public ActionResult ParentsDetails()
{
var studentDetails = new List<StudentDetail>();
var parentDetails = new List<ParentsDetail>();
// Fill your lists here, and pass them to viewmodel constructor.
var viewModel = new ParentsInformationViewModel(studentDetails, parentDetails)
// Return your viewmodel to corresponding view.
return View(viewModel);
}
In your view define your model.
#model MySolution.ViewModels.ParentsInformationViewModel
Is there in your view declared that you are receiving model of type
In view:
#model IEnumerable<ParentsInformationViewModel>

Entity framework add collection to model not saving correctly

Maybe a simple question, but I can't seem to figure it out. Saving a collection to a model when adding a model to the database isn't working. I have a site which uses asp.net MVC and entity framework.
The models:
public class Event
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<EventRange> Ranges { get; set; }
}
public class EventRange
{
public int Id { get; set; }
public string RangeName { get; set; }
public string RangeDescription { get; set; }
public int Capacitiy { get; set; }
}
The controller actions:
[HttpPost]
public ActionResult Create(Event model)
{
ICollection<EventRange> eventRanges = new Collection<EventRange>();
var range = new EventRange {RangeName = "testrange", RangeDescription = "test", Capacitiy = 5}
eventRanges.Add(range);
model.Ranges = eventRanges;
db.Events.Add(model);
db.SaveChanges();
return View();
}
public ActionResult Events()
{
return View(db.Events);
}
When setting a breakpoint in the Events action and evaluated the query, the Range isn't saved to the event:
Code Screenshot
Note that that the database created for the eventrange model by EF does save the range:
EF DB Screenshot
Am I doing something wrong?
What if you mark the Ranges property as virtual?
public virtual ICollection<EventRange> Ranges { get; set; }

Categories