MVC View Model Organization - model-view-controller

I'm new to MVC and I'm trying to understand how to organize my ModelViews. The first problem is Drop Down data. I have an Equipment Model and an EquipmentViewModel that looks like this:
public class EquipmentViewModel
{
public Equipment Equipment { get; private set; }
public SelectList EquipmentCategories { get; private set; }
private MyEntities db = new MyEntities();
public EquipmentViewModel(Equipment equipment)
{
Equipment = equipment;
EquipmentCategories = new SelectList(db.EquipmentCategories.Where(c => c.IsActive),
"EquipmentCategoryID", "Description");
}
Please note the SelectList for my category dropdown. This is all well and good. However I have another Model called Inventory. Inventory has an EquipmentID property (corresponding to a piece of equipment you see). For the creation of an inventory item it would be useful to have a drop down for the equipment category. I already have this select list in my EquipmentViewModel and it feels wrong some how to duplicate that code for the InventoryViewModel.
I have considered something like this:
public class InventoryViewModel
{
MyEntities db = new MyEntities();
public Inventory Inventory { get; set; }
public EquipmentViewModel EquipmentViewModel { get; set; }
}
This seems okay to me except I am going to have an Index page for the InventoryViewModel. Basically I would be returning a List of InventoryViewModels which each has an EquipmentViewModel where in each of those has the exact same list of categories. This, too, feels wrong and I think I am misunderstanding some crucial piece of the MVC puzzle.
It also leads me to my second question: How would I return such a monstrosity from the controller? I imagine it looking something like this:
var list = db.Inventories
.Select(i => new InventoryViewModel
{
Inventory = i,
EquipmentViewModel = new EquipmentViewModel(i.EquipmentID)
});
Which means that I'd basically be making separate trips to the database (inside the EquipmentViewModel constructor) for each EquipmentID rather than being able to join on the id. For example if I just needed the description I could do this:
var list = from i in db.Inventories
join e in db.Equipments
on i.EquipmentID equals e.EquipmentID
select new InventoryViewModel
{
Inventory = i,
EquipmentName = e.Description
};
Which I believe would have much better performance. I greatly appreciate any wisdom that anyone could offer. Thanks!

I have and idea for you,
there is no point of ducplicating your views if they are doing same thing. however if they are not doing exactly the same is better to exted or create new view than have one big one that is shared for all parts.
You can have model such as this
public class InventoryViewModel{
// contains all categories for every inventory
public SelectListItem EquipmentSelect {get;set;}
//this will contain all the items you want to assign
public List<Inventories> ListOfInventories{get;set;}
}
after in view you can create partial view for every item with the select list item in to it

Related

One to many, one view do I need a custom model?

I have a database base first application so I have no homemade modals as such, just the ones created automatically. I want to display in a single view the one and many parts from a select in single row in an html table/list, here is the SQL that works great in a re-created MS Access Query, - some brackets:
SELECT Facilitiy.FacilityName, Facilitiy.FacilityImage, FacilityDetail.FacilityDetailDescription
FROM FacilityDetail INNER JOIN Facilitiy ON FacilityDetail.FacilityDetailID = Facilitiy.FacilityFK
WHERE FacilityFK = id
And the LINQ that gives me the correct many part of the list:
from fd in db.FacilityDetails
join f in db.Facilities on fd.FacilityID equals f.FacilityFK
where f.B FacilityFK == id
select f
I had kind of hoped that would do it as the SQL does but I need to create a modal that I can put in a view to display:
FacilityImage(one side) | FacilityName(one side) | FacilityDetailDescription(many side)
I have heard I can simply do it by doing something like this???
from fd in db.FacilityDetails.Include("Facilities")
but it seems to make no difference!
Which leads me to believe I need to create a new custom model? If so how would i write it?
I tried something like this but I cant get it to work.
public class FacilitiyDetails
{
public string FacilitiesDescription { get; set; }
public string FacilitiesImage { get; set; }
public string BeachFacilitiesDescription { get; set; }
{
I'm not quite sure what i'm supposed to do here!
Yes you will need a custom model because you're wanting to display multiple types. You'll need to have something like:
public class FacilityModel
{
public Facility Facility { get; set; }
public List<FacilityDetails> FacilityDetails { get; set; }
}
Based on your class above and assuming you have a Facility class already. Then you'll need to change your LINQ to first get the Facility details:
var facility = (from f in db.Facilities
where f.FacilityID == id
select f)
.FirstOrDefault(); //just being safe here,
//if it's null, you'll want to escape out of
//the code below
Then you'll need to get all equivalent FacilityDetails for that facility by doing:
var facilityDetails = (from fd in db.FacilityDetails
where fd.FacilityFK == id
select fd).ToList()
Then you can create a new instance of your Model by doing:
var model = new FacilityModel
{
Facility = facility,
FacilityDetails = facilityDetails
};

ASP.NET MVC 3 multiple Models to single Form using DB

I have a question.
My question actually extends from this one:
Shortly - what I want to get: 3 models, and 1 super model for this specific view. This super model fills(properly) IENumerable, IENumerable, IENumerable, to use them in View part. (as far as I understand it, at least...)
In this other topic Dan Revell proposed verry nice and elegant solution, but this solution does not fetch data from DB itself...
Question:
What must be done to get data in this model from DB, not from "new" instance constructors?
While using this approach tried to fetch data from DBContext. And got some problems in it ) I can't understand when (or how) to create my DBContext... Or how to access one that is created by application...
Tried to create it forcefully in Controller, like
using (var Db = new thetaskermvc.Models.TaskerDBContext())
{
var themodel = new thetaskermvc.Models.TotalView();
//Jobbers
themodel.Jobberz = new Dictionary<int, thetaskermvc.Models.Jobbers>();
var jobbers = from Jobbers in Db.Jobbers.OrderBy(g => g.jobb_name) select Jobbers;
foreach (Models.Jobbers ad in jobbers)
{
themodel.Jobberz.Add(ad.jobb_id,
new Models.Jobbers(ad.jobb_id, ad.jobb_name, ad.jobb_from, ad.jobb_carma, ad.jobb_status, ad.jobb_balance, ad.jobb_time));
}
if (themodel.Jobberz.Count == 0)
{
themodel.Jobberz.Add(-1, new Models.Jobbers(0, "NOTHING FOUND",DateTime.Now,0,"",0,0));
}
}
But as created that way Context stops it's existence (?) after passing data away from controller - I can't use it any other way but to get all data inside this controller, and fill data in model by direct add into collections in it (while use of IENumerable would fetch data on-demand, as far as I get it).
So.. If it ain't hard please enlighten me about - is it Ok to use such approach, or there is some other "common" way? Becaus beside it's clumsiness - this approach works...
PS I'm quite new to Asp, yet...
I have one view model per view with data from multiple tables (if required). On my view I have data that needs to be loaded from 2 different database tables. In my grant application controller I have the following:
private readonly IBankService bankService;
private readonly IAccountTypeService accountTypeService;
public GrantApplicationController(IBankService bankService, IAccountTypeService accountTypeService)
{
// Check incoming parameters for null values
this.bankService = bankService;
this.accountTypeService = accountTypeService;
}
In my Create action method I populate my banks and account types (to be used in drop downs) like this (different tables):
public ActionResult Create()
{
GrantApplicationCreateViewModel viewModel = new GrantApplicationCreateViewModel
{
Banks = bankService.FindAll(),
AccountTypes = accountTypeService.FindAll()
}
// Do what ever else you need to get done
return View(viewModel);
}
My partial view model would like this:
public class GrantApplicationCreateViewModel
{
public int BankId { get; set; }
public IEnumerable<Bank> Banks { get; set; }
public int AccountTypeId { get; set; }
public IEnumerable<AccountType> AccountTypes { get; set; }
// Other properties
}
In my repository class I would use the database context like this (I use Entity Framework code first):
public class BankRepository : IBankRepository
{
HefContext db = new HefContext
public IEnumerable<Bank> FindAll()
{
return db.Banks.OrderBy(x => x.Name);
}
}
In my database context class:
public class HefContext : DbContext
{
public DbSet<Bank> Banks { get; set; }
public DbSet<AccountType> AccountTypes { get; set; }
}
Doing it this way you can have one view model that has data from multiple sources. I hope this answers your question? If you need more explanation please let me know :)
You may want to have a look at this post, it explains (with a sample project) how an ideal MVC application architecture should be.
In your code sample above, your shouldn't have any references to DbContexts in a controller. Controller's job is to control the flow of requests not to connect to the DB and perform Model population.

Using LINQ to combine similar rows of grouped data

I've got some data in a table that looks like so:
Recipe | Category | Email
What I'd like to do is pull this data back from the source and put it into something that looks like so:
public class RecipeItem
{
public long Recipe { get; set; }
public long Category { get; set; }
public List<string> Names {get; set; }
}
Grouping by the Recipe and Category ids and putting all the emails that into the list.
So, what I've tried is to do something like this:
var recipeItems =
from entry in list
group entry by new { entry.Recipe, entry.Category}
into aRecipe
select new RecipeItem()
{
Recipe = aRecipe.Key.Recipe,
Category = aRecipe.Key.Category,
// ? Not sure how to stick the list of names in here
};
list is the data pulled back via entity framework.
But this isn't quite right - I think I'm close here (maybe). What am I missing here on this?
Follow-up:
Thanks to Aducci for clearing this up. The answer is that you can do this:
Names = aRecipe.Select(x => x.Name)
and this will add all those Names which are in each group into the Names collection for that group. Pretty nifty.
I would modify your class to look like this
public class RecipeItem
{
public long Recipe { get; set; }
public long Category { get; set; }
public IEnumerable<string> Names {get; set; }
}
And your link to entities query to:
var recipeItems =
from entry in list
group entry by new { entry.Recipe, entry.Category}
into aRecipe
select new RecipeItem()
{
Recipe = aRecipe.Key.Recipe,
Category = aRecipe.Key.Category,
Names = aRecipe.Select(x => x.Name)
};

ASP.NET MVC 3 nested lists

I'm new to the MVC world and need some guidance. I'm trying to create a vertical multi level menu for a website. The data for the menu is stored in a database table with the following structure:
ID, categoryName, parentID
How do I go about this with regular ADO.NET and MVC? As far as I can tell I need to make a MenuItem class with int ID, string name and List<MenuItem> Children properties. I then need to make and instance of this class representing the vertical menu and then I need to genereate the HTML for the view.
I have searched the net for an easy to follow example but I'm not finding anything I can understand. If there is anyone out there that can guide me through this it would be very much apprediated!
You should edit your question or split it up into more concrete questions.
I will answer the concrete question in your comment on how to load your MenuItems recursively.
You wrote you use regular ADO.NET. I was free to use dapper in my sample code which makes life a bit easier:
So here is you MenuItem class:
public class MenuItem
{
public int Id { get; set; }
public int? ParentId { get; set; }
public List<MenuItem> Children { get; set; }
}
Now we open a connection and load the whole MenuItems table into a single collection:
SqlConnection conn = new SqlConnection("...");
conn.Open();
IEnumerable<MenuItem> allItems = conn.Query<MenuItem>("SELECT * FROM MenuItems");
I pretend you will have a single MenuItem as the root item with ParentId = null. Lets find it:
MenuItem rootMenu = allItems.Single(m => m.ParentId == null);
The last thing we have to do is to rearrange the items in a hierachical tree. We do this with a function which works recursively:
loadChildren(rootMenu, allItems);
Here is the function. It simply looks up the children of the passed item and calls itself on all found childnodes:
private static void loadChildren(MenuItem currentItem,
IEnumerable<MenuItem> allItems)
{
currentItem.Children = allItems
.Where(m => m.ParentId == currentItem.Id).ToList();
foreach (var childItem in currentItem.Children)
{
loadChildren(childItem, allItems);
}
}

Populate a DropdownList with composite key records in MVC3.net?

I don't know if I'm missing something obvious, but I really want to grab names of clients associated with a composite key.
Controller Code:
Job job = db.Jobs.Find(id);
ViewBag.jobClientsList = new SelectList(job.JobClients.ToList(), "ClientNumber", "ClientNumber");
View Code:
<%: Html.DropDownList("ClientNumber", ViewData["JobClientsList"] as SelectList)%>
Model:
namespace Sample.CustomerService.Domain {
using System.ComponentModel.DataAnnotations;
public class JobClient {
public JobClient() { }
[Key]
[Column(Order = 1)]
public virtual int JobNumber { get; set; }
[Key]
[Column(Order = 1)]
public virtual int ClientNumber { get; set; }
public virtual Client Client { get; set; }
public virtual Job Job { get; set; }
}
}
This code works, but all I get in the dropdownlist is a bunch of numbers. What I would really like is the client names associated with the numbers but I'm really not sure how to do it! I've been looking around for ages!
After re-reading your question your answer seems simpler then expected.
Check out the Select list class http://msdn.microsoft.com/en-us/library/system.web.mvc.selectlist.aspx
The constructor your using in your controller is wrong, it should be:
ViewBag.jobClientsList = new SelectList(job.JobClients.ToList(), "ClientNumber", "Client");
You were setting the text value of the selectList to be "ClientNumber" which is why you had a list of numbers and not names!
By default the select list is showing you the property that is marked [Key]
<%: Html.DropDownList("ClientNumber",
ViewData["JobClientsList"].Client as SelectList)%>
Should print the client name (assuming the primary Key on the Client object is their name, otherwise You'd need something like ViewData["JobClientsList"].Client.FullName
The best solution would be to use a ViewModel instead of using ViewBag or ViewData for this, it'll help avoid a lot of headaches both now and in the future.
What I have done in the past to get DropDownLists working is save the List to the Session Variable, and then create my SelectList in the actual DropDownList.
Controller:
Job job = db.Jobs.Find(id).ToList();
ViewBag.jobClientList = job;
View:
<%: Html.DropDownList("ClientNumber", new SelectList((If you view is strongly typed, put that here) ViewData["JobClientsList"],"ClientNumber","ClientNumber")%>
This may be poorly worded, so I think I can clarify if need be
Anyone looking for a solution, try the following:
In your controller:
1) Get the list:
var allCountries = countryRepository.GetAllCountries();
2) define a variable:
var items = new List<SelectListItem>();
3)loop each item:
foreach(var country in allCountries)
{
items.Add(new SelectListItem() {
Text = coutry.Name,
Value = Country.Id.ToString(),
// Put all sorts of business logic in here
Selected = country.Id == 13 ? true : false
});
}
model.Countries = items;
In your view:
#Html.ActionLink("StringToDisplay", "actionName", "controllerName", new SelectList(Model.Countries, "Value","Text"),"--Please Select--", new{#class="form-control"})
Not to mention Model should have a property with
public IEnumerable<Country> Countries {get; set;}

Resources