I have a following function in a controller. It is called from index.cshtml. var relays works fine and I got the replays.count(). PRESETDETAILS has some columns from which I want to access specific columns in a loop (like I have mentioned in response.write).
Kindly tell me how I can get the specific columns in the for loop.
#region "Apply Preset Handlers"
public ActionResult btnApply_Click(int? id)
{
var relays = db.PRESETDETAILS.ToList().Where(t => (t.PRESETID).Equals(id));
for (int k = 0; k < relays.Count(); k++)
{
Response.Write(relays.Select(s => new relays{PRESETDETAILID = s.PRESETDETAILID }).ToString());
}
return View("Index");
}
#endregion
you need to loop through them, you're simply select the same things over and over...
var relays = db.PRESETDETAILS.Where(t => t.PRESETID == id).ToList();
foreach (var replay in replays)
{
Response.Write(string.Format("{0}", relay.ID));
}
NOW... looking at your code:
always use ToList() at the end of the query;
ToList() actually makes the call to the database, until then, it's just a promise
Don't use Response.Write in your Controller, send the data to the View instead
your code should be:
public ActionResult btnApply_Click(int? id)
{
var model = db.PRESETDETAILS.Where(t => t.PRESETID == id).ToList();
return View(model);
}
in your View you can loop through the records
#model List<YOUR_CLASS>
<ul>
#foreach(var replay in Model)
{
<li>#replay.ID</li>
}
</ul>
I can see that some MVC conventions are not yet in place with you, and I know it can be somewhat overwhelm from someone that comes from WebForms or a linear code approach, but why don't you take some time and check the FREE available course about ASP.MVC in the ASP.NET Website?
See the videos in the right side of this page: http://www.asp.net/mvc
Related
I have a piece of code that gets the contents of a view and returns them in a list to populate a drop-down menu on the front end.
public ActionResult GetMeetingList()
{
using (var context = new ClerkEntities())
{
var meetingList = context.vwGetMeetings.ToList();
return Json(new { data = meetingList }, JsonRequestBehavior.AllowGet);
}
}
There are 4 columns in this view: [MeetingID], [MeetingName],[MeetingTitle],[MeetingDate]
I need to have the results sorted by MeetingDate.
How can I specify the OrderBy in this line?:
context.vwGetMeetings.ToList();
Thank you for your help.
Erasmo
Context.vwGetMeetings.OrderBy(x => x.MeetingDate).ToList();
And if you want to order descending:
Context.vwGetMeetings.OrderByDescending(x => x.MeetingDate).ToList();
What you are using is Linq, which will give you more relevant results (Linq sort) than (Entity Framework sort).
I'm having a problem with an application I made for my company. We are taking queries out of an ERP system. People can search for an article, and then the application shows them all relevant technical data, pictures and/or datasheets.
Problem is: it's loading very slow. Queries seem to run fine, but the generation of the view takes ages.
This is my search code (don't mind the Dutch parts):
public IQueryable<Item> GetItems(string vZoekString)
{
db.Configuration.LazyLoadingEnabled = false;
//Split de ZoekString
var searchTerms = vZoekString.ToLower().Split(null);
// TODO: alles in een db query
//Resultaten oplijsten
var term = searchTerms[0];
var results = db.item_general.Where(c => c.ITEM.Contains(term) || c.DSCA.Contains(term));
//Zoeken op alle zoektermen
if (searchTerms.Length > 1)
{
for (int i = 0; i < searchTerms.Length; i++)
{
var tempTerm = searchTerms[i];
results = results.Where(c => c.ITEM.Contains(tempTerm) || c.DSCA.Contains(tempTerm));
}
}
//Show
return results;
And then, these results are returned to the view like this:
public ActionResult SearchResults(string vZoekString, string filterValue, int? pageNo)
{
//Bewaking zoekstring
if (vZoekString != null)
{
pageNo = 1;
}
else
{
vZoekString = filterValue;
}
//De zoekstring doorgeven
if (vZoekString == null)
{
return RedirectToAction("Index", "Home");
}
else
{
ViewBag.ZoekString = vZoekString;
}
//Ophalen Items via Business-Object
//var vItems = new SearchItems().GetItems(vZoekString);
SearchItems vSearchItems = new SearchItems();
IQueryable<Item> vItems = vSearchItems.GetItems(vZoekString);
//Nummering
int pageSize = 10;
int page = (pageNo ?? 1);
//Show
return View(vItems.OrderBy(x => x.ITEM).AsNoTracking().ToPagedList(page, pageSize));
}
What can be wrong in my situation? Am I overlooking something?
UPDATE:
I've checked my code, and it seems that everything works very quickly, but it takes more than 10 seconds when it reaches .ToPagedList(). So my guess is that there is something wrong with that. I'm using the paged list from Nuget.
While I can't evaluate your view code without seeing it the problem could very well be in the database query.
An IQueryable does not actually load anything from the database until you use the results. So the database query will only be run after the View code has started.
Try changing the View call to:
var items = vItems.OrderBy(x => x.ITEM).AsNoTracking().ToPagedList(page, pageSize);
return View(items);
And then check to see if the View is still the bottleneck.
(This should probably be a comment instead, but I don't have the reputation....)
In most cases where you face performance issues with MVC and EF it is due to returning entities to views and getting stung by lazy loading. The reason for this is that when ASP.Net is told to send an object to the browser it needs to serialize it. The process of serialization iterates over the entity which touches lazy-load proxies, triggering those related entities to load one at a time.
You can detect this by running a profiler against your database, set a breakpoint point prior to the end of your action, then watch what queries execute as the action call returns. Lazy loading due to serialization will appear as a number of individual (TOP 1) queries being executed in rapid succession after the action has completed prior to the page rendering.
The simplest suggestion to avoid this pain is don't return entities from controllers.
IQueryable<Item> vItems = vSearchItems.GetItems(vZoekString);
var viewModels = vItems.OrderBy(x => x.ITEM)
.Select(x => new ItemViewModel
{
ItemId = x.ItemId,
// .. Continue populating view model. If model contains a hierarchy of data, map those to related view models as well.
}).ToPagedList(page, pageSize);
return View(viewModels);
The benefit of this approach:
The .Select() will result in a query that only retrieves the data you actually need to populate the view models. (The data your view needs) Faster query, less data across the wire between DB server -> App server -> Browser
This doesn't result in any lazy loads.
The caveat of this approach:
You need to take care that the .Select() expression will go to SQL, so no .Net or private functions for stuff like translating/formatting data. Populate raw values into the view model then expose properties on the view model to do the translation which will serialize that formatted data to the client. Basic stuff like FullName = x.FirstName + " " + x.LastName is fine, but avoid things like OrderDate = DateTime.Parse(x.DateAsISO) if the DB stored dates as strings for example.
You can leverage mappers like Automapper to assist with mapping between Entity and ViewModel. Provided the mapping tool inspects/traverses the destination to populate rather than the source, you should be good. Automapper does support integration within IQueryable so it would be a worthwhile investment to research that if you want to leverage a mapper.
We can implementing pagination in C#, ASP.NET in ActionResult function like this
public ActionResult Index(int? page)
{
Entities db = new Entities();
return View(db.myTable.ToList().ToPagedList(page ?? 1,8 ));
}
how to implementing pagination in JsonResult function that sending result to ajax in html view?
public JsonResult GetSearchingData(string SearchBy, string SearchValue)
{
var subCategoryToReturn = myList.Select(S => new { Name = S.Name });
return Json(subCategoryToReturn, JsonRequestBehavior.AllowGet);
}
stop thinking in terms of UI and start thinking in terms of data.
you have some data you want to paginate. That's it. Forget about MVC at this point or JSONResult or anything else that has nothing to do with the data.
One thing to be aware of, this code you posted above:
db.myTable.ToList().ToPagedList(page ??1,8 )
if you do it like this, your entire table will be returned from the database and then it will be paginated. What you want is to only return the data already paginated, so instead of returning 100 records and then only taking the first 20, only return the 20.
Don't use ToList() at that point, use something like this instead:
var myData = db.myTable.Skip(pageNumber * pageSize).Take(pageSize)
I don't have any running code to check this, but hopefully you get the idea, only return the data already paginated, so only return the data you will display and nothing more. The UI can send the page index you click on, the pageSize can be a predefined number stored in appSettings for example.
You can use, .Skip() for skipping first n elements and Take() for fetching the next n rows.
int pageNumber = 0;
int ItemsPerPage= 10;
var Results = db.myTable.ToList().Skip(ItemsPerPage* pageNumber).Take(numberOfObjectsPerPage);
Suppose that you only need 10 items Per page. Number of Pages would be equal to
TotalPages = Math.Ceiling(TotalItems/ItemsPerPage); // IF 201 Items then 201/10 ceiling = 21 pages
Now you can make Pagination buttons in html. I suggest you use Jquery Pagniation Library
https://esimakin.github.io/twbs-pagination/
I encountered a very strange (and annoying) issue:
in MVC 4 web application while loading data from the database and using a foreach on the Model within the view:
#foreach (var meeting in Model)
i have a breakpoint in the method's beginning and examining the object meeting i see that it misses some data (reference to other tables). if I open (+) other object within meeting the missing data appears.
Why?
Thanks!
here is my controller method:
public ActionResult GetMeetingMR(int id = 0)
{
var meetingPurpose = db.MeetingPurposes.ToList();
ViewBag.MeetingPurpose = new SelectList(meetingPurpose, "MeetingPurposeID", "MeetingPurposeName");
ViewBag.MRID = id;
List<Meeting> meetings = (db.MortgageRequests.Find(id)).Meetings.ToList();
return View(meetings);
}
Including your title in your question, my guess is you do not experience the problem (yet) without the debugger attached.
As others have commented it is due to LazyLoading.
The problem may occur sometimes because while rendering the View the entities container is being disposed, most probably because it is collected by the GarbageCollector which calls the destructor of the container.
If you wish to access the entities on your View you can use Include on the ObjectSet.
Let's say MeetingPurposes has an associated EntitySet of Dates:
If you wish to include them in the loadoperation you can do the following:
db.MeetingPurposes.Include("Dates").ToList();
public ActionResult GetMeetingMR(int id = 0)
{
//Load the MeetingPurposes including their dates
var meetingPurpose = db.MeetingPurposes.Include("Dates").ToList();
ViewBag.MeetingPurpose = new SelectList(meetingPurpose,
"MeetingPurposeID",
"MeetingPurposeName");
ViewBag.MRID = id;
List<Meeting> meetings = (db.MortgageRequests.Find(id)).Meetings.ToList();
return View(meetings);
}
If you wish to do this for Meetings and Meetings has an EntitySet of Dates you could do:
public ActionResult GetMeetingMR(int id = 0)
{
var meetingPurpose = db.MeetingPurposes.ToList();
ViewBag.MeetingPurpose = new SelectList(meetingPurpose,
"MeetingPurposeID",
"MeetingPurposeName");
ViewBag.MRID = id;
var meetings = (from mee in db.Meetings.Include("Dates")
join mga in dbo.MortgageRequests.Where(m => m.Id == id)
on mee.MortgageRequestID equals mga.ID
select mee).ToList();
return View(meetings);
}
Not really sure what your Find extension method is so I used a Where on MortgageRequests.
I'm trying to set up a page where I display a list of items and the details of the selected item. I have it working but wonder whether I have followed the correct approach. I'll use customers as an example
I have set the aspx page to inherit from an IEnumerable of Customers. This seems to be the standard approach to display the list of items. For the Details I have added a Customer user control which inherits from customer.
I think i'm on the right track so far but I was a bit confused as to where I should store the id of the customer whose details I intend to display. I wanted to make the id optional in the controller action so that the page could be hit using "/customers" or "customers/1" so I made the arg optional and stored the id in the ViewData like this:
public ActionResult Customers(string id = "0")
{
Models.DBContext db = new Models.DBContext();
var cList = db.Customers.OrderByDescending(c => c.CustomerNumber);
if (id == "0")
{
ViewData["CustomerNumber"] = cList.First().CustomerNumber.ToString();
}
else
{
ViewData["CustomerNumber"] = id;
}
return View("Customers", cList);
}
I then rendered the User control using RenderPartial in the front end:
<%var CustomerList = from x in Model
where x.CustomerNumber == Convert.ToInt32(ViewData["CustomerNumber"])
select x;
Customer c = (Customer)CustomerList.First(); %>
<% Html.RenderPartial("Customer",c); %>
Then I just have an actionLink on each listed item:
<%: Html.ActionLink("Select", "Customers", new { id = item.CustomerNumber })%>
It all seems to work but as MVC is new to me I would just be interested in others thoughts on whether this is a good approach?
In regards to proper MVC and separations of concerns, you shouldn't be calling LINQ queries in your view. To get around that, change your controller action code from what you have to this:
if (id == "0")
{
ViewData["CustomerDetails"] = cList.First();
}
else
{
ViewData["CustomerDetails"] = From x in db.customers where x.id = cInt(id);
}
then your partial
<% Html.RenderPartial("Customer",ViewData["CustomerDetails"]); %>
Are you showing the customer information on the same screen that you have your list of customers and not a separate view?
In this case I would take the following approach.
Display a list of customer's, be it a listbox or drop down list.
Let's assume it's a drop down list, probably not very user friendly
You would have the text as the customer name and then the value as the customer id
<select title="Customers">
<option label="Pieter" value="001"></option>
</select>
and using JQuery's $.getJSON you could load the new data via a call to an asp.net MVC action.
Note that your Action should return JsonResult