loading dropdown list with data from table in mvc4 - asp.net-mvc-4

I have 3 models and corresponding tables (EnquiryModel, EmployeeModel, RegionModel).
I want to populate a dropdown list in both the 'create' views of Enquiry and Employee.
That dropdown list should be filled with the data from the 'Region_Name' field in the RegionModel Table.
How can I do this?
I have RegionModel:
namespace MvcConQuery.Models
{
[Table("Region_Details")]
public class RegionModel
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public Int32 Region_id { get; set; }
public string Region { get; set; }
}
}
And also I have EmployeeModel and EnquiryModel, I give the following code in controller of these models:
public ActionResult Create()
{
IEnumerable<SelectListItem> abc = new SelectList(db.Regions, "Region_id", "Region");
ViewBag.regions = abc;
return View();
}
I give this code in Create View:
#Html.DropDownList("regions","select")
But I got the error:
There is no ViewData item of type 'IEnumerable' that has the key 'regions'.
Please help me to code the Create()function in controller and the Create View.

Try like this,
DATAEntities _context = new DATAEntities ();
var List = (from r in _context.Registrations select r).ToList();
ViewBag.CustomerName = new SelectList(List, "Region_id", "Region");
View
#Html.DropDownList("regions", (SelectList)ViewBag.CustomerName, "--Select--")
If you have any concerned let me know.

Related

How to filter data in model in ActionResult of controller in ASP.net core MVC?

I have an index.chtml set up with about 10 ActionLinks. Those actionLinks trigger different ActionResult functions within the controller since each of them essentially perform unique queries on a data model.
I also have an entities object named db which has all the data. Instead of just displaying all the data, I want to perform complex filtering on the entities object to find where certain properties of records are null or where a property is greater than some input then returns a view of all columns on only those records that were filtered.
Find nulls:
public class printJobsController : Controller {
private PrintJobsEntities db = new PrintJobsEntities
public ActionResult IncompleteJobs {
//get jobs where processDate is null
...
}
}
Find where count is greater than 10:
public class printJobsController : Controller {
private PrintJobsEntities db = new PrintJobsEntities
public ActionResult JobsGreaterThan(int limit) {
//group by printerName and find counts greater than limit
...
}
}
How do I go about doing this?
Seems you are trying to populate the View with filtered data as per your request parameter in controller action.
You could follow the below steps to achieve what you are trying to:
Your imaginary Data Model
public class PrinterJob
{
[Key]
public int PrinterId { get; set; }
public string PrinterName { get; set; }
public int PrintedBy { get; set; }
public int TotalPrint { get; set; }
}
Sample Data In Database:
Controller Action:
public ActionResult <PrinterJob> JobsGreaterThan(int limit) {
var printCountByGroup =
(from objPrint in _context.PrinterJobs group objPrint by new {
objPrint.PrinterName, objPrint.PrintedBy, objPrint.TotalPrint
}
into grp where grp.Sum(p => p.TotalPrint) > limit
select new {
PrinterName = grp.Key.PrinterName, PrintedBy = grp.Key.PrintedBy,
TotalPrint = grp.Key.TotalPrint
});
return View(printCountByGroup);
}
Output After Applying Filter:
Note: Here I am trying to filter printer information which printed more then 30 printing jobs.
Hope it would help you to achieve your goal. If you still have any problem feel free to let me know.

Getting model to viewmodel easily

I have a view-model like this:
public class U1MyProfile1ViewModel : U1Profile
{
public List<SelectListItem> CountryList { get; set; }
}
Thinking that I want the model accessible to the view, plus a some extra fields that aren't really part of the model, such as a drop down list of countries.
Then in the controller I try to "pass the model over to the view-model"
var myProfile = await _mainDbContext.U1Profiles
.AsNoTracking()
.FirstOrDefaultAsync(i => i.SiteUserId == mySiteUserId);
U1MyProfile1ViewModel myProfileViewModel = (U1MyProfile1ViewModel)myProfile;
this compiles, but I get a runtime error of:
InvalidCastException: Unable to cast object of type 'WebApp.Models.U1Profile' to type 'WebApp.ViewModels.U1MyProfile1ViewModel'.
Any ideas on how to do this easily?
Something simpler than assigning the model to the view-model field by field.
Set your View model like follow:
View modal
public class U1MyProfile1ViewModel
{
public List<SelectListItem> CountryList { get; set; }
public U1Profile U1Profile{get;set;}
public string othervariable{get;set;}
}
Controller
var myProfile = await _mainDbContext.U1Profiles
.AsNoTracking()
.FirstOrDefaultAsync(i => i.SiteUserId == mySiteUserId);
U1MyProfile1ViewModel myProfileViewModel = new U1MyProfile1ViewModel;
U1MyProfile1ViewModel.U1Profile=myProfile;
U1MyProfile1ViewModel.CountryList=yourcountrylist;
And finally just passed your viewmodal to View and you get your result.
For better understanding just see below link:
Link1
Link2

How HtmlHelper know data is on the ViewBag?

I was watching a tutorial about HtmlHelper for DropDown https://www.youtube.com/watch?v=79aYSOcmpV8
Around min 8, he is reading the db to replace some hardcode values.
To pass list of Departments from the controller, store them in "ViewBag"
public ActionResult Index()
{
// Connect to the database
SampleDBContext db = new SampleDBContext();
// Retrieve departments, and build SelectList
ViewBag.Departments = new SelectList(db.Departments, "Id", "Name");
return View();
}
Last step.
Now in the "Index" view, access Departments list from "ViewBag"
#Html.DropDownList("Departments", "Select Department")
I dont see anything like strong type model on the view.
So how the Helper know Departments refers to a value in the ViewBag?
When you add a value to ViewBag, it is also added to the ViewData property of ViewContext when the view is generated. The DropDownList() overload that your using in equivalent to passing a null SelectList in
#Html.DropDownList("Departments", null, "Select Department")
in which case, internally, the helper searches the ViewData property to find a matching key which is an IEnumerable<SelectListItem> (which "Departments" is). You can see the relevant code in the private static MvcHtmlString SelectInternal() method of the source code
// If we got a null selectList, try to use ViewData to get the list of items.
if (selectList == null)
{
selectList = htmlHelper.GetSelectData(name);
....
}
Note that the example in the tutorial is a poor approach, using 'magic' strings and requiring you to access the value in the POST method using Request.Form["Departments"]. A far better approach is to use a view model and strongly bind to your view model, for example
public class MyViewModel
{
public int SelectedDepartment { get; set; }
public IEnumerable<SelectListItem> DepartmentList { get; set; }
...
}
and the GET method would be
public ActionResult Create()
{
MyViewModel model = new MyViewModel
{
DepartmentList = new SelectList(db.Departments, "Id", "Name");
};
return View(model);
}
and in the view
#model MyViewModel
....
#Html.DropDownListFor(m => m.SelectedDepartment, Model.DepartmentList, "Select Department")
and post the form back to
[HttpPost]
public ActionResult Create(MyViewModel model)

How to bind a drop down with a model property while containing the list items of that drop down?

I am stuck in a problem, I have retrieved all the value for a drop down in a view bag and want to display them at run time. I have achieved it by using the following code for the controller
[HttpGet]
public ActionResult Index()
{
var categoryList = new PersonalApp();
SelectList catList = new SelectList(categoryList.GetAffinity().ToList(), "ClientName", "AffinityNum");
ViewBag.categoryList = catList;
return View();
}
and the following code for the view
#using (Html.BeginForm("index", "Home"))
{
#Html.DropDownList("categoryList", "Branch Type")
}
It really works but now I want to bind it with a model now. I have use the following code for this:
#Html.DropDownListFor(model=>model.AffinityNum, "categoryList", "BranchType")
But it gives me an error as CategoryList cannot be used as a parameter with the above code. How will I get this resolved as I can have all the values of a dropdown in the categorylist and I can bind it with a model property affinityNum with it as well.
Thanks
Your model should have an IEnumerable<SelectListItem> property that will hold the values:
public class PersonalApp
{
public string AffinityNum { get; set; }
public IEnumerable<SelectListItem> CategoryList { get; set; }
}
that you will populate in your controller action and pass to the view:
[HttpGet]
public ActionResult Index()
{
var model = new PersonalApp();
var categories = categoryList.GetAffinity().ToList();
SelectList catList = new SelectList(categories, "ClientName", "AffinityNum");
model.CategoryList = catList;
return View(model);
}
and finally in your strongly typed view you will use this property to bind the dropdown list to:
#model PersonalApp
...
#Html.DropDownListFor(x => x.AffinityNum, Model.CategoryList, "BranchType")
Please try;
#Html.DropDownListFor(model=>model.AffinityNum, (SelectList)ViewBag.categoryList)

Best Practice with MVC4 and EF5 to apply changes

I have a CustomerOrder-view where I would like to change an existing CustomerOrder.
I have a viewmodel that very simpliefied looks something like this:
public class CustomerOrderViewModel
{
public int ID { get; set; }
public Customer Customer { get; set; }
public DateTime Date { get; set; }
public IEnumerable<OrderRow> OrderRows { get; set; }
}
public class OrderRow
{
public int id { get; set; }
public int price { get; set; }
}
public class Customer
{
public string Name { get; set; }
}
I also have a database with mapping tables / fields.
In my GET Action Method I load the Order with the help of Automapper like this:
var customerOrder = using (var ctx = new My_Entities()) {
return ctx.CustomerOrders.
Include("Orderrows").
Include("Customer").
Single(o => o.CustomerOrderID == id);
}
var model= AutoMapper.Mapper.DynamicMap<DataAccessLayer.CustomerOrder, CustomerOrderViewModel>(customerOrder);
In the View I use Knockout to bind to a viewmodel there, where the user can update the CustomerOrder. That includes editing Customer information and adding new orderrows etc.
Then in the post back a map the ViewModel back to the ObjectContext CustomerOrder:
var customerOrderToBeSaved =
AutoMapper.Mapper.DynamicMap<CustomerOrderViewModel, CustomerOrder>(
customerOrderViewModel);
try
{
using (var ctx = new MyEntities())
{
ctx.CustomerOrders.Attach(customerOrderToBeSaved);
ctx.CustomerOrders.ApplyCurrentValues(customerOrderToBeSaved);
...
ctx.SaveChanges();
}
}
I get the error message: An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
OK, that I can understand. But how should I go about this? Can I get the existing object and apply Changes to that one, because that is really what I'd like. I've tried to look up the old one and detach it but I haven't got it to wrok.Perhaps I'm doing this in a completely wrong way. Please advice.
You should not attach customerOrderToBeSaved, see MSDN about the argument of ApplyCurrentValues.
The detached object that has property updates to apply to the original object.
So you've got to load the entity from the database into the context and then ApplyCurrentValues with the detached object that has the new values.
You don't have to load the row from the database to update it.
You can do something like this:
var entity = ctx.CustomerOrders.Attach(customerOrderToBeSaved);
ctx.Entry( entity ).State = EntityState.Modified;
ctx.SaveChanges();
This will tell EF to issue an UPDATE SQL statement that overwrites all the columns in the record.
You can select which columns you want to update like this:
var entity = ctx.CustomerOrders.Attach(customerOrderToBeSaved);
var entry = ctx.Entry( entity );
entry.Property( o => o.<ColumnPropertyToUpdate> ).IsModified = true;
entry.Property( o => o.<ColumnPropertyToUpdate> ).IsModified = true;
...
ctx.SaveChanges();
If you do this, EF will only include the columns you've marked as modified in the UPDATE statement.