pass dynamic summary queries to an MVC view from an EF model - asp.net-mvc

Translate code in Laravel to asp.net mvc. I am passing a subset of the model and summarizing the fields by year. My EF model has 50+ fields.
This is my Laravel route:
Route::get('/metrics', 'MetricsController#index');
My Laravel Controller
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
class MetricsController extends Controller
{
public function index()
{
$metrics = DB::select('select year(date_id) as Year, Sum(Revenue) from metrics Group By year(date_id)');
return ($metrics);
}
}
I would like to display the model data in a #foreach loop in the view? The dump in the Laravel view displays the data in the following way.
[{"Year":2009,"Sum(Revenue)":"61302670.65"},
{"Year":2011,"Sum(Revenue)":"68397989.00"},
{"Year":2012,"Sum(Revenue)":"69245803.00"},
{"Year":2013,"Sum(Revenue)":"67184051.00"},
{"Year":2014,"Sum(Revenue)":"33445434.00"}]

I will keep it simple, sticking to the fact that you need to show the data in the View. For that, I will assume that you already have your DbContext, Models and data loading parts ready.
Model
I will create a sample model just for the sake of example. But it could, obviously, be more advanced.
public class Result
{
public string Year { get; set; }
public decimal SumRevenue { get; set; }
}
Action Method (in the Controller)
The most important here is the fact that you are loading a "List of" model as result of your query. As you are using EF, you could load it directly from your DbContext or probably use a repository pattern. Since we don't know, I am just making a simple method call so just imagine the DB logic is in there :)
public ActionResult Index()
{
// Here is where you load your data. I am using this line just as example.
List<Result> resultList = RandomLibrary.LoadData();
return View(resultList)
}
View
Remember to prepare your View to receive the List you got in the Action Method.
#model List<Result>
#foreach(var item in Model)
{
<p>
<strong>Year: </strong>#item.Year
<br />
<strong>Sum of revenue: </strong>#item.SumRevenue
</p>
}
This is an oversimplification of the process. You can see it in more details in the official documentation. Or just let us know if you will need a more detailed explanation as your case might be a bit different.

Related

How to save views input data into different tables?

I'm an ASP.NET MVC beginner and currently I use EF with a database-first approach to do my work. Everything goes well and every model have its controller and views files. I face problem when I want to save multi model data on a view.
In my case:
I have ASP.NET MVC form for teacher details data, and another for teacher employment history (this two are auto generate from scaffolding database approach)
I want a view Create.cshtml where user inputs teacher details and employment history and this can be saved into their own tables. Therefore, I use tuple and follow what (Multiple models in a view) and (Two models in one view in ASP MVC 3) did.
As a result, I successfully create teacher details and employment history on a view (Just interface).
But I have no idea how to save the input into the different tables (2 tables: teacher, employmentHistory). Now, when I save the input, nothing happens.
I guess I need to do something on controllers parts, please give me some ideas on how to do it.
Thanks in advance
First, welcome to StackOverflow!
You are correct, you should do something on the controller part.
I would create a ViewModel for the view. By doing this you can project the data from the database in any way that is needed in the view. Also, with this approach you don't return the full entity, maybe there is some sensitive information there. And you can get the benefit of the model validations also. (For example, what if at some point you need to add another field from another entity?)
I would also create partial views for the information in the view model and pass that model to the partial view, this way enabling the re-use of the views, if needed.
When passing the data to the controller you can pass the ViewModel and then save the data in the database.
Since you didn't give no model info of your classes, I give below an example. Either way (view model or tuple example you followed), you should change the controller code similar to what I'm writing below.
public class TeacherViewModel
{
//teacher details
[Required]
public int TeacherId {get; set;}
[Required]
public string TeacherName {get; set;}
// {...}
//teacher employment info
//here you can have a list of information or the last entry in the history,
//or what's required to add a new entry
public string LastWorkPlace {get; set;}
public DateTime From {get; set;}
public To {get; set; }
//{...}
}
public class TeacherController: Controller
{
//{...}
[HttpPost]
public ActionResult SaveTeacherInfo(TeacherViewModel model){
if (ModelState.IsValid) {
var teacher = new TeacherEntity
{
TeacherId = model.TeacherId, //if update otherwise leave blank
TeacherName = model.TeacherName
//{...}
};
//your context name here
_dbContext.Teachers.Add(teacher);
var teacherEmploymentInfo = new TeacherEmploymentHistory
{
TeacherId = teacher.TeacherId,
LastWorkPlace = model.LastWorkPlace,
From = model.From,
To = model.To
//{...}
};
_dbContext.TeachersEmploymentInfo.Add(teacherEmploymentInfo);
_dbContext.SaveChanges();
//_dbContext.SaveChangesAsync(); if using async await
}
return View(model); //return any validation errors from the view model
// to the user to fix.
}
}
If you are using the ErrorHandler as a global filter no need for try..catch block if you are not planing to return custom errors (BusinessException or DatabaseException, for example) from the controller, if not, you should wrap the code in a try..catch block.

Why shouldn't use Linq in View

Somewhere I had to use a linq statement for select a result set from my Model that Controller returned in Index ActionResult.
for doing this, I googled "how to use linq in view razor" and I get the result and my application worked properly, but I see some recommendation that say "Don't use Linq in view".
Why we shouldn't use it however it's possible?
And if I don't want using it what's the solution?
This is my query :
#using System.Linq
#{var lst = (from x in item.Showtimes select x.ShowtimeDate).Distinct();}
#foreach (var showTimeItem in lst)
{
<option value="#showTimeItem">#showTimeItem</option>
}
UPDATE
This is my controller Index
public ActionResult Index()
{
MelliConcert.Models.MelliConcertEntities db = new Models.MelliConcertEntities();
var listOfConcerts = (from x in db.Concert
orderby x.ID ascending
select x).Take(15).ToList();
return View(listOfConcerts);
}
And i use it in the view like this :
#model IEnumerable<MelliConcert.Models.Concert>
#foreach (var item in Model)
{
#if (item.OpenedForFirst == true)
{
//...
}
//Some Codes
#using System.Linq
#{var lst = (from x in item.Showtimes select x.ShowtimeDate).Distinct();}
#foreach (var showTimeItem in lst)
{
<option value="#showTimeItem">#showTimeItem</option>
}
}
My linq statement placed in this loop.
What should i do?
There's nothing inherently wrong with using LINQ in a view per se. The problem isn't that you're using LINQ, the problem is that you're doing this:
#{var lst = (from x in item.Showtimes select x.ShowtimeDate).Distinct();}
Any time you have to declare and set a variable inside your view, that's probably an indication that you need to modify your model. Your view model should have a property on it for this purpose. Something like this:
public IEnumerable<SomeType> DistinctShowtimes
{
get
{
return (from x in item.Showtimes select x.ShowtimeDate).Distinct();
}
}
Then the point about LINQ in the view becomes moot, as all you'd need is this:
#foreach (var showTimeItem in Model.DistinctShowtimes)
{
<option value="#showTimeItem">#showTimeItem</option>
}
UPDATE (in response to your updated question):
Now the problem (albeit slightly less of one) is this:
#model IEnumerable<MelliConcert.Models.Concert>
While this works fine, it's limiting. And what you're experiencing is that limitation. You're asking yourself, "How do I return more than one thing to the view?" The answer is to create a custom view model for that view. Right now your view is binding to an enumeration of Concert objects. Which is fine, if that's all it needs. But it turns out that's not all it needs. It has some custom logic that requires a little more. So, you create a custom view model. Something like this:
public class ConcertsViewModel
{
public IEnumerable<Concert> Concerts { get; set; }
// other properties, methods, anything
}
Then in your controller action, you return one of those instead:
public ActionResult Index()
{
using(var db = new Models.MelliConcertEntities())
{
var concertsModel = new ConcertsModel();
concertsModel.Concerts = (from x in db.Concert
orderby x.ID ascending
select x).Take(15).ToList();
return View(concertsModel);
}
}
(Note also the use of the using statement, which should always be employed when making use of IDisposable resources.)
So now your view is still getting the list of Concert objects, but it's packaged in a custom view model onto which you can add any more functionality you need for that view. Next, in your view, change the model declaration:
#model MelliConcert.Models.ConcertsViewModel
(This assumes you put it in the Models namespace. Depending on the scale of your application, you might want to break out view models into their own namespace. I don't often use the Models namespace in the actual application for core business objects, so our projects are likely structured very differently. This should get you going, but you'll want to make sure you keep your concerns cleanly separated.)
Then in the view code you can reference what you need from that object. So if you need to access the list, instead of just calling something like #foreach (var item in model) you would call #foreach (var item in model.Concerts).
I think in this case the argument would be to do the maximum amount of processing on your model before returning it to the view.
So why not return distinct showtimes to the view and then just loop through them?
The only problem with your current set up is it may undermine the spirit of MVC which was to separate concerns. The view shouldn't be applying any logic that needs to be tested (or as little as possible). By keeping logic in the models and controllers you make unit testing easier and the views are simpler for a developer to read.
EDIT
Hey #samangholami, you can return multiple objects to a view using a class. Create a class called "PAGENAMEViewModel" or something similar and create a property for every value you want to return. For example:
public class MovieViewModel
{
public string MovieName { get; set; }
public IEnumerable<string> Actors { get; set; }
public IEnumerable<ShowTimeRecord> Showtimes { get; set; }
public class ShowTimeRecord
{
public string TheaterName { get; set; }
public string TheaterAddress { get; set; }
public DateTime ShowtimeDate{ get; set; }
}
}
Then return your complex model like so:
public ActionResult Index()
{
MovieViewModel model = myMovieHelper.GetMovieData();
return View(model);
}
Besides the possible separation of concerns problem you also might have a performance problem that can be more difficult to diagnose.
If your LINQ query is somehow connected to the database via some ORM or something like that by looping through the results you might create a N+1 problematic scenario.
Moving it off the view might not prevent it, but at least puts it into somewhere that is more visible.
I believe that's because it's not respecting the separation of concerns principle, which is a fundamental concept of MVC. By performing that query in the view, you're taking business logic to it.
It has nothing to do with Linq itself. You could, for example, have a Linq statement to perform an OrderBy. That's ok because it's not business logic, it's a proper view operation (to order data into a table, let's say).

How do I scaffold when creating a Controller that represents more than 1 Entity?

I have Entity Framework modeling a legacy database that has about 30 tables. I am using ASP.NET MVC 4 and would love to use scaffolding based on an Entity in my EDM. I have seen a ton of examples on this but I am running into an issue. My needs are not so cookie cutter as the examples I have seen which are like this: create a Controller that scaffolds a 'Customer' entity, and upon saving changes the Controller action takes in a Customer as it's parameter and using model binding all is well after the following is done:
[HttpPost]
public ActionResult Create(Customer customer)
{
if (ModelState.IsValid)
{
db.Customers.AddObject(customer);
db.SaveChanges();
return RedirectToAction("Index");
}
}
Perfect and pretty right; well this does not work for me. In my situation my screen needs fields from about 6 different entities and updates back to those same 6 entities.
So a 2 part question:
How do I even scaffold my controller and resulting view(s) when it is not a simple 1 entity to 1 screen deal like the simple example from above?
Will I still be able to use model binding to persist changes back to my entities since once again the resulting view will be a result of about 6 different entities, and without a lot of manual updating of properties on each individual entity?
If I am totally off base please guide me back. I want to know exactly how I accomplish this task as it will happen repeatedly throughout my MVC application and I need to know how to still use scaffolding and model binding when possible.
Thanks!
When you run into a scenario like this, it's time to start considering using ViewModels and EditModels, which are models dedicated to showing the exact properties needed by the View.
One strategy for doing this:
Create new folders in your project: ViewModels and EditModels.
For each details view, add a ViewModel class, and for each edit/create view, add an EditModel class.
In your controller, map from your entities to your ViewModel/EditModel when the page is first requested. On postbacks, perform validation and map from you EditModel back to your entities.
A few notes:
This does add some work, but it's really the only solid way to take advantage of the strongly-typed view capability of MVC.
To minimize the tedium of going from entities to ViewModels, you can use something like AutoMapper to automatically map between properties with the same name (and set up rules for the remaining mappings).
Some manual work will likely be needed to go from EditModels back to entities. AutoMapper can handle some scenarios, but it's probably not the ideal tool for that type of mapping (it works much better for going from an entity to a ViewModel). I have heard of people using the command pattern and rules engines for performing the mapping back to entities, but thus far, a truly detailed explanation or tutorial for these techniques has evaded me.
ViewModel example (from the NerdDinner tutorial)
public class DinnerFormViewModel {
// Properties
public Dinner Dinner { get; private set; }
public SelectList Countries { get; private set; }
// Constructor
public DinnerFormViewModel(Dinner dinner) {
Dinner = dinner;
Countries = new SelectList(PhoneValidator.AllCountries, dinner.Country);
}
}
// controller actions
[Authorize]
public ActionResult Edit(int id) {
Dinner dinner = dinnerRepository.GetDinner(id);
return View(new DinnerFormViewModel(dinner));
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection collection) {
Dinner dinner = dinnerRepository.GetDinner(id);
try {
UpdateModel(dinner);
dinnerRepository.Save();
return RedirectToAction("Details", new { id=dinner.DinnerID });
}
catch {
ModelState.AddModelErrors(dinner.GetRuleViolations());
return View(new DinnerFormViewModel(dinner));
}
}
Source: http://nerddinnerbook.s3.amazonaws.com/Part6.htm

Correct use of Model vs Controller in MVC / ASP.NET MVC

I have a Service class with a method called GetProducts(). That encapsulates business logic and calls the repository to get a list of products.
My MVC view wants to show that list of products as an MVC SelectList. Where is the correct place for that logic to go. I seem to have 3 options:
Model
The Model should expose a property called ProductSelectList. When the getter of this property is called by the View, the Model should call Service.GetProducts() and convert the result to a SelectList before passing it on.
Plausible argument: The Model should make calls to business logic and the repository. The View should merely render predetermined data. The Controller should not be involved, save for passing contextual data to the Model.
View
The View should contain code that calls Service.GetProducts() directly and converts the result to a SelectList inline.
Plausible argument: The View should call for this data directly as it is specifically for use on the View. There is no need to involve the Model or Controller, as we are calling an abstracted Service method anyway, so anything else just adds extra overhead.
Controller
The Controller should make the call to Service.GetProducts(), convert the results to a SelectList and pass it through to the Model, which should contain a simple ProductSelectList property. The View will access this property for rendering.
Plausible argument: The Controller knows which parameters to provide to the Service method, so it should make the call. The Model should be a simple placeholder for data, filled by the Controller. The View's job is to simply render the data from the Model.
I have a feeling that the correct answer is Model, but the other two make some reasonable points. Perhaps I've muddied the waters by already having a Service class that's separate to the Model?
Would anybody care to share their opinion? Is this just a matter of taste?
I personally subscribe to the logic of Number 3, allowing the controller to populate the Model (or View Model as is sometimes differentiated).
I have my views dumb and only displaying data.
I have my View Models store the information that the View will need, occasionally exposing 'get only' properties that format other properties into a nicer format. If my model needs access to my services, then I feel I'm doing something wrong.
The controllers arrange and gather all the information together (but do no actual work, that is left for the services.
In your example, I would have my controller action similar to:
public ActionResult Index()
{
IndexViewModel viewModel = new IndexViewModel();
viewModel.ProductSelectList = new SelectList(Service.GetProducts(), "Value", "Name");
return View(viewModel);
}
and my view model similar to:
public class IndexViewModel()
{
public SelectList ProductSelectList { get; set; }
public int ProductID { get; set; }
}
With the appropriate part of the view looking like:
#Html.DropDownListFor(x => x.ProductID, Model.ProductSelectList);
This way I'm content that I know where to look if there is an issue with anything and everything has a very specific place.
However, there is no correct way as seems always to be the case with these things. Stephen Walther has a good blog series on MVC tips. In one he talks about the View Model emphasis and although not a SelectList he populates, the SelectList is still data in much the same way his list of products is.
In a classic MVC architecture your Model shouldn't be much more than a container for your view data hence the reason it's often called a ViewModel. A ViewModel is different from the Entity Model(s) that your service layer manages.
Your controller is then responsible for populating your ViewModel from the entity model(s) returned by your service layer.
Due to convenience some developers will use their service layer entities directly in their ViewModels but long term that can lead to headaches. One way around that is to use a tool such as AutoMapper to automate the shuffling of data to and from your ViewModel and entity models.
Here's what a controller might look like. Notice that data such as the SSN does not get exposed to the view since there is a mapping from your Entity Models to your View Model.
public class Customer : IEntity
{
public string CustomerID { get; set; }
public string SSN { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Address Address { get; set; }
}
public class CustomerEditViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Country { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
public string PhoneNumber { get; set; }
}
public class CustomerController
{
[AcceptVerbs (HttpVerbs.Get)]
public ActionResult Edit ()
{
Customer customer = _customerService.GetCustomer (User.Identity.Name);
var model = new CustomerEditViewModel ()
{
FirstName = customer.FirstName,
LastName = customer.LastName,
Address1 = customer.Address.Address1,
Address2 = customer.Address.Address2,
Country = customer.Address.Country,
City = customer.Address.City,
State = customer.Address.State,
Zip = customer.Address.Zip,
PhoneNumber = customer.Address.PhoneNumber,
};
return View (model);
}
}
You're right that there are a number of ways to handle this, and that's even before considering variations like MVP, MVVM, et cetera. Since you're asking about ASP.Net MVC in particular, I will defer to Microsoft:
An MVC model contains all of your application logic that is not
contained in a view or a controller. The model should contain all of
your application business logic, validation logic, and database access
logic. For example, if you are using the Microsoft Entity Framework to
access your database, then you would create your Entity Framework
classes (your .edmx file) in the Models folder.
A view should contain only logic related to generating the user
interface. A controller should only contain the bare minimum of logic
required to return the right view or redirect the user to another
action (flow control). Everything else should be contained in the
model.
In general, you should strive for fat models and skinny controllers.
Your controller methods should contain only a few lines of code. If a
controller action gets too fat, then you should consider moving the
logic out to a new class in the Models folder.
Source
I would say your call belongs in the Model.
One thing to keep in mind is that the SelectList class is specific to MVC only. So in my opinion it shouldn't be included in any business logic, and model classes fall into that category. Therefore your select list should be a part of a view model class instead.
This is the way it works in my projects:
Controller method is called
Controller uses repository (business logic, in other words) to get model data
Controller converts the model data if necessary and creates a view model object
Controller passes the view model to the view
The view displays the data in the view model with limited logic to show or hide things, etc
I'd go with option 3. In general, I'll construct my MVC apps such that the controller makes a call to the service to return a model (or collection of models) which are then passed to the view.
I generally keep my models very thin. They are a flattened representation of the data with validation attributes and that's it. I use a service (or model builder) layer to construct the models and do business logic on them. Some folks embed that into the model, but I find that makes for a messy project.
You definitely don't want the view making any calls to your services.
Update...
I'm assuming that this SelectList is your model. If instead it's a part of your model, then you're right, you should put it in your model. I generally don't like to make it a method call, though. I'd have a property on my model:
public SelectList Products { get; set; }
And have my service or model builder class actually populate it. I don't usually have any data-oriented methods on my models.
I'm going with option 1.
Models are the place to make calls to business logic, et cetera.
View - Should display only what the ViewModel already has been populated with.
Controller - the job of the Controller is to direct the traffic coming in (from Web requests) to the Logic that is responsible for handling the request. Hence the term 'controller'.
There are always exceptions to these, but the best place (structurally) is the Model.
I had this problem when I started into MVC and came up with this solution.
The controller talks to a Service Layer. The service layer contains my Domain models and does all the processing for request from the Controllers. The service layer also returns ViewModels to satisfy requests from the controller.
The service layer calls a repository and gets the entities it will need to build the ViweModels. I often use Automapper to populate the ViewModel or collections within the view model.
So, my view models contain all that is needed by the View, and the Controller is doing nothing but handling request and forwarding them to the appropriate service handler.
I don't see a problem with having view specific items like SelectLists in the view Model either.
None of the above.
In my web layer I basically just have html and javascript views. The model shouldn't leak into the view and neither should the services.
I also have an Infrastructure layer which binds the services and model to the views. In this layer there are ViewModels, which are classes that represent what will be displayed on the screen, Mappers, which do the work getting data from services/model and mapping it to the view model, and Tasks, which perform tasks such as Saving, Updating and Deleting data.
It is possible to put a lot of this infrastructure in the Controllers, similar to the example Todd Smith has given above, but I find for anything other than trivial views the Controller becomes littered with code to load data and populate view models. I prefer a dedicated single responsibility mapper class for each view model. Then my controller will look something like
public class CustomerController
{
[AcceptVerbs (HttpVerbs.Get)]
public ActionResult Edit (int id)
{
return View (CustomerEditMapper.Map(id));
}
[AcceptVerbs (HttpVerbs.Post)]
public ActionResult Save(CustomerEditViewModel model)
{
var errors = CustomerEditUpdatorCommand.Execute(model);
ModelState.AddErrors(errors);
return View ();
}
}
I'm torn between option 1 and option 3. I've ruled option 2 out completely as to me that's polluting the view with procedure calls not just presentation layer work.
Personally I would do it in the model and the getter would call the Service layer but I also subscribe to the belief that the model should only contain the information the view needs to render the page, by not fully containing the data in the model at the time you pass it to the view you are breaking this.
Another option here though would be to avoid tightly coupling the view and model by putting a Dictionary of the Products into the view through a Service Call then using the view to transform the Dictionary to a SelectList but this also gives you the ability to just output the information as well.
I think this boils down to a preference as to where you are happy having your logic.

ASP.Net MVC - Passing posted value to view

I am creating a search page, the user types in the textbox and click 'Search', the controller takes the FormCollection in its Action method.
I do the search and return the results to the view however I want to return what the user searched for to the view. Is the TempData the best place for this or is this a risk?
I'd say that your model for the results view should contain both the results and the search criteria.
Examples:
public class ResultsViewModel
{
public SearchModel SearchCriteria { get; set; }
...
}
public class SearchModel
{
public string Category { get; set; }
...
}
then, just populate the SearchCriteria in your results view model and you can retrieve it from there.
This assumes that your results view is strongly typed to ResultsViewModel.
TempData is primarily used when the result of an action is a redirect to another action, and you need to keep some state around.
All you need to do is add another entry to the ViewData dictionary with "what the user searched for". Something roughly like this:
public ActionResult Search(FormCollection form)
{
// search algorithm
ViewData["keywords"] = form["keywords"];
return View();
}
The TempData is if you need that item the next time the user requests something else. Using the ViewData is what you're looking for. Also remember, the value he/she searched for is still available in the View as Request[searchBoxName].
Create a strongly typed view using a view model that will pass all the information you want on to the view and encode all user imputed information.
public class ResultsSetViewModel
{
public string Query { get; set; }
public IList<Result> Results { get; set; }
}
Encode the user imputed data.
<h3>Search Results For: <%=Html.Encode(Model.Query) %></h3>
Using both the suggestions above will work, however it is better practice to add the data you need into the model than passing it via the ViewData.
If you pass it in the model then you get the advantages of it being strongly typed and remove the need to add logic to cast the ViewData entry into your view.

Resources