Error when retrieving records - asp.net-mvc

I'm a beginner in ASP.NET MVC. I'm getting a error while trying to retrieve records from the database.
'System.Collections.Generic.List'
does not contain a definition for 'CategoryName'
LINQ to SQL Class:
Model:
namespace MvcApplication1.Models
{
public class CategoryRepository
{
private BusDataClassesDataContext dc = new BusDataClassesDataContext();
public List<tblCategory> GetAllCategory()
{
return dc.tblCategories.ToList();
}
}
}
Controller:
public class CategoryController : Controller
{
//
// GET: /Category/
CategoryRepository cat = new CategoryRepository();
public ActionResult ViewCategory()
{
var category = cat.GetAllCategory().ToList();
return View("ViewCategory", category);
}
}
View:
<p>
Category Name:<%=Html.Encode(Model.CategoryName)%>
</p>
<p>
Description:<%= Html.Encode(Model.Description)%>
</p>
UPDATE:

You are passing List<tblCategory> to the view. Hence the Model here will be the generic list. That is the reaons why you are getting the error message:-
'System.Collections.Generic.List' does not contain a definition for 'CategoryName'
Did you intend to pass tblCategory or else did you intend to iterate thought the model to get to each tblCategory?
You can do this way
<% foreach(var category in Model)
{%>
<p>
Category Name:<%=Html.Encode(category.CategoryName)%>
</p>
<p>
Description:<%= Html.Encode(category.Description)%>
</p>
<% } %>
On a little bit different note.
You are already returning the type as GenericList in your method.
public List<tblCategory> GetAllCategory()
{
return dc.tblCategories.ToList();
}
You don't need to again perform an ambiguous .ToList() conversion.
var category = cat.GetAllCategory().ToList();

Use this::
<% foreach (var category in Model)
ruther than ::
#foreach (var category in Model)
in the view.
Like This
<% foreach (var category in Model)
{ %>
<p>
Category Name :<%=Html.Encode(category.CategoryName)%></p>
<p>
Description :<%=Html.Encode(category.Description)%></p>
<% } %>

Related

How do I post two instances of the same property from a view to an action?

How can I send my data from form, two fields are the same: Station name, but they have different values. How send they via post method to controller. Asp.net mvc2
here what i try:
<% using (Html.BeginForm("ViewRes", "Shedule"))
{%>
<%= Html.ValidationSummary(true) %>
<fieldset>
<legend>Поиск по расписанию:</legend>
<ul>
<li>Из<%= Html.EditorFor(model => model.StationName) %></li>
<li>В<%= Html.EditorFor(model1 => model1.StationName) %></li>
<li>Дата отправления</li>
</ul>
<p>
<input type="submit" value="OK" />
</p>
</fieldset>
<% } %>
and such controller:
[HttpPost]
public ActionResult ViewRes(string a1, string b1)
{
DateTime dtm = Convert.ToDateTime("30.11.2011 0:00:00");
var res = (from d in db.RouteDetail
from m in db.RouteDetail
lalala
where (d.Station == a1
&&
m.Station == b1)
lalalal
}).ToList();
return View(res);
}
The way I would approach this is to refactor my model to encompass both of your existing inputs separately. That way each can be bound accordingly in the action.
public class RailwayRoute
{
public string StartStation { get; set; }
public string EndStation { get; set; }
}
View
<% using (Html.BeginForm("ViewRes", "Shedule"))
{%>
<%= Html.ValidationSummary(true) %>
<fieldset>
<legend>Поиск по расписанию:</legend>
<ul>
<li>Из<%= Html.EditorFor(model => model.StartStation) %></li>
<li>В<%= Html.EditorFor(model => model.EndStation) %></li>
<li>Дата отправления</li>
</ul>
<p>
<input type="submit" value="OK" />
</p>
</fieldset>
<% } %>
Controller/Action
[HttpPost]
public ActionResult ViewRes(string startStation, string endStation)
{
...
}
Expanding on tvanfosson's answer which pretty much sums up, I would try and decouple your data model from your view data. This is often done by using the MVVMC aproach where VM stands for view model. In your case you appear to be passing directly the data model to the view which is sometimes not the recommended approach.
So changing tvanfosson's RailwayRoute to a viewModel object I would ensure the controller action maps the data appropiately. Something like
[HttpPost]
public ActionResult ViewRes(RailwayRouteViewModel viewModel)
{
DateTime dtm = Convert.ToDateTime("30.11.2011 0:00:00");
var res = (from d in db.RouteDetail
from m in db.RouteDetail
lalala
where (d.Station == viewModel.StartStation
&&
m.Station == viewModel.EndStation)
lalalal
select new RailywayRouteViewModel()
{
StartStation = d.Station,
EndStation = m.Station
}
}).ToList();
return View(res);
}

.NET 4.0 Linq to SQL - Object update not working

I'm building a simple MVC Movie Application, using a repository pattern and Class Library for my Linq to SQL Classes. I can't seem to get my objects to UPDATE back to the database.. I'm missing something now sure what it is:
public class MovieRepository : BaseRepository, IMovieRepository
{
/// <summary>
/// Updates the specified movie.
/// </summary>
public void Update()
{
GetDataContext.SubmitChanges();
}
/// <summary>
/// Fetches the by id.
/// </summary>
/// <param name="id">The id.</param>
public Movie FetchById(int id)
{
Movie movie = (from n in GetDataContext.Movies
where n.ID == id
select n).First();
return movie;
}
}
BaseRepository.cs
public abstract class BaseRepository
{
private static VideoStoreDBDataContext _videoStoreDbDataContext;
protected static VideoStoreDBDataContext GetDataContext
{
get
{
if (_videoStoreDbDataContext == null)
{
_videoStoreDbDataContext = new VideoStoreDBDataContext();
}
return _videoStoreDbDataContext;
}
}
}
HomeController
public ActionResult EditMovie(int Id)
{
Movie movie = _movieRepository.FetchById(Id);
if (movie == null)
return RedirectToAction("Error", "Home");
return View(movie);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditMovie(Movie movie)
{
if (!ModelState.IsValid)
return View(movie);
// NOTE: movie object does infact contain changes made using the VIEW.
_movieRepository.Update();
return RedirectToAction("Index");
}
View
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Details</legend>
<p>
<label for="Title">Title:</label><br/>
<%= Html.TextBox("Title", Model.Title) %>
<%= Html.ValidationMessage("Title", "*") %>
</p>
<p>
<input type="submit" value="Update Movie" />
</p>
</fieldset>
<% } %>
<div>
<%=Html.ActionLink("Back to List", "Index") %>
</div>
In your method EditMovie, the object movie that you receive as the argument, is not actually a database-bound object. It gets constructed for you by MVC runtime, and your DataContext has no knowledge of it. Therefore, when you call Update(), the DataContext doesn't see any changes to write to the database.
What you should do instead is find this object in the database, then copy all fields from the method's argument into it, and then call Update(). Like so:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditMovie(Movie movie)
{
if (!ModelState.IsValid)
return View(movie);
var existingMovie = _movieRepository.FetchById( movie.Id );
existingMovie.Title = movie.Title;
_movieRepository.Update();
return RedirectToAction("Index");
}
For this to work, you also have to include your Movie's ID in your form (as a hidden field), so that it may be posted back by the browser, and thus enable you to distinguish update to one movie from update to another. Like so:
<legend>Details</legend>
<p>
<label for="Title">Title:</label><br/>
<%= Html.TextBox("Title", Model.Title) %>
<%= Html.ValidationMessage("Title", "*") %>
<%= Html.HiddenFor( m => m.Id ) %> //<------
</p>
EDIT: As Mystere Man pointed out, you do not need to add this hidden field if your URL contains the Id.
You are forgetting that http is a stateless system. Each page that gets served is a seperate request, and each set of objects are destroyed at the end of each request.
So, the objects returned by your get do not exist in your post, because this is a completely seperate request. In reality, the Default Model Binder is creating a new instance of your Movie object, not modifying the contents of the one you previously returned.
So the update won't work, because L2S doesn't know that your newly created Movie object should be updated.

Replicated nested repeater behaviour in MVC

Today I decided to give MVC a go, and although I really like the idea, I found it fairly difficult to transition from ASP.NET and grasp some basic concepts, like using foreach instead of nested repeaters.
It took me good few hours to come up with this solution, but it doesn't seem quite right. Could someone please explain what's wrong with this code, and what the right way to do it is. Here is my solution:
Essentially it's a survey that consists of several questions, each of which has several answers. I have tables in db, which are represented as strongly typed entities. The controller looks like this:
public ActionResult Details(int id)
{
return View(new Models.Entities().Questions.Where(r => r.PROMId == id));
}
and corresponding view like this:
<% foreach (var question in Model) { %>
<h3>Question <%: Array.IndexOf(Model.ToArray(), question) + 1 %></h3>
<p><%: question.QuestionPart1 %></p>
<p><%: question.QuestionPart2 %></p>
<% var answers = new Surveys_MVC.Models.Entities().Answers.Where(r => r.QuestionId == question.QuestionId); %>
<% foreach (var answer in answers) { %>
<input type="radio" /><%: answer.Text %>
<% } %>
<% } %>
All feedback appreciated.
As far as using for loops for the nested repeater behavior, I think that's the best way to do this in MVC. But I would suggest you use dedicated ViewModels.
ViewModel:
public class RadioQuestionListViewModel
{
public IEnumerable<RadioQuestionViewModel> Questions {get;set;}
}
public class RadioQuestionViewModel
{
public int QuestionNumber {get;set;}
public string InputName {get;set;}
public string QuestionPart1 {get;set;}
public string QuestionPart2 {get;set;}
public IEnumerable<RadioAnswerViewModel> PossibleAnswers {get;set;}
}
public class RadioAnswerViewModel
{
public int AnswerId {get;set;}
public string Text {get;set;}
}
Controller:
public ActionResult Details(int id)
{
var model = GetRadioQuestionListModelById(id);
return View(model);
}
View:
<% foreach (var question in Model) { %>
<h3>Question <%: question.QuestionNumber %></h3>
<p><%: question.QuestionPart1 %></p>
<p><%: question.QuestionPart2 %></p>
<% foreach (var answer in question.PossibleAnswers) { %>
<%: Html.RadioButton(question.InputName, answer.AnswerId) %>
<%: answer.Text %>
<% } %>
<% } %>
This approach has a few advantages:
It prevents your view code from depending on your data access classes. The view code should only be responsible for deciding how the desired view model gets rendered to HTML.
It keeps non-display-related logic out of your view code. If you later decide to page your questions, and are now showing questions 11-20 instead of 1-whatever, you can use the exact same view, because the controller took care of figuring out the question numbers to display.
It makes it easier to avoid doing a Array.IndexOf(Model.ToArray(), question) and a database roundtrip inside a for loop, which can become pretty costly if you have more than a few questions on the page.
And of course your radio buttons need to have a input name and value associated with them, or you'll have no way to retrieve this information when the form is submitted. By making the controller decide how the input name gets generated, you make it more obvious how the Details method corresponds to your SaveAnswers method.
Here's a possible implementation of GetRadioQuestionListModelById:
public RadioQuestionListViewModel GetRadioQuestionListModelById(int id)
{
// Make sure my context gets disposed as soon as I'm done with it.
using(var context = new Models.Entities())
{
// Pull all the questions and answers out in a single round-trip
var questions = context.Questions
.Where(r => r.PROMId == id)
.Select(r => new RadioQuestionViewModel
{
QuestionPart1 = r.q.QuestionPart1,
QuestionPart2 = r.q.QuestionPart2,
PossibleAnswers = r.a.Select(
a => new RadioAnswerViewModel
{
AnswerId = a.AnswerId,
Text = a.Text
})
})
.ToList();
}
// Populate question number and name
for(int i = 0; i < questions.Count; i++)
{
var q = questions[i];
q.QuestionNumber = i;
q.InputName = "Question_" + i;
}
return new RadioQuestionListViewModel{Questions = questions};
}
I don't know if it is better, but you can create a helper to do this for you:
public static void Repeater<T>(this HtmlHelper html, IEnumerable<T> items, string cssClass, string altCssClass, string cssLast, Action<T, string> render)
{
if (items == null)
return;
var i = 0;
foreach (var item in items)
{
i++;
if (i == items.Count())
render(item, cssLast);
else
render(item, (i % 2 == 0) ? cssClass : altCssClass);
}
}
Then you can call it like so:
<%Html.Repeater(Model, "css", "altCss", "lastCss", (question, css) => { %>
<h3>Question <%: Array.IndexOf(Model.ToArray(), question) + 1 %></h3>
<p><%: question.QuestionPart1 %></p>
<p><%: question.QuestionPart2 %></p>
<% var answers = new Surveys_MVC.Models.Entities().Answers.Where(r => r.QuestionId == question.QuestionId); %>
<% foreach (var answer in answers) { %>
<input type="radio" /><%: answer.Text %>
<% } %>
<% }); %>
This has a lot of power and the above is just a general example. You can read more here http://haacked.com/archive/2008/05/03/code-based-repeater-for-asp.net-mvc.aspx

ASP.NET MVC 2 UI Templates displaying data without markup. How to fix?

Using EditorFor( model lambda, "viewTemplateName"), my output is completely not as expected. This doesn't produce any errors, but it is rendering output without markup. What am I doing wrong?
The Output:
HarryTomRichard
The Expected Output (I need to figure out how to render the List [] indexes on id too but not to that problem yet):
<table>
<tr><td><span><input type="Text" id="Name[0]" value="Harry" /></span></td></tr>
<tr><td><span><input type="Text" id="Name[1]" value="Tom" /></span></td></tr>
<tr><td><span><input type="Text" id="Name[2]" value="Richard" /></span></td></tr>
</table>
My Classes:
namespace Marcs.Models {
public class Student { public string Name { get; set; } }
public class Classroom { public List<Student> Students { get; set; }
}
My Controller:
public ActionResult Index() {
var myStudents = new List<Student>();
myStudents.Add(new Student { Name = "Harry" });
myStudents.Add(new Student { Name = "Tom" });
myStudents.Add(new Student { Name = "Richard" });
var myClass = new Classroom {Students = myStudents};
return View(myClass);
}
My Index View:
Inherits="System.Web.Mvc.ViewPage<Marcs.Models.Classroom>" %>
<% using (Html.BeginForm()) { %>
<%= Html.EditorFor(m => m.Students, "Classroom") %>
<input type="submit" value="Save" />
<% } %>
My Classroom Template (notice the m => item so I can use the item, not the model):
Inherits="System.Web.Mvc.ViewUserControl<List<Marcs.Models.Student>>" %>
<table>
<% foreach (Marcs.Models.Student item in Model)
{ %><tr><td><%= Html.EditorFor(m => item, "Student")%></td></tr><%
} %>
</table>
My Student Template:
Inherits="System.Web.Mvc.ViewUserControl<Marcs.Models.Student>"
%><span><%= Html.Encode( Html.EditorFor( m => m.Name)) %></span>
jfar has the answer, and I will mark it appropriately when added. The solution was simply to ensure the files were located in Views->ControllerName->EditorTemplates and Views->ControllerName->DisplayTemplates. These can also be located in the Shared folder too.
I like this post. Now I need to learn how to use the MVC 2 template Html helpers that reference collections. It's in MVC 2 RC.

Trouble passing ViewModel to Partial View

My ViewModel class (ItemViewModel.cs) looks like this:
public class ItemViewModel
{
public ItemViewModel(xxx.Product product)
{
this.product = product;
}
private readonly xxx.xxx.Product product;
private readonly Pers pers;
private readonly Item item;
public xxx.xxx.Product Product
{
get{ return product;}
}
public Item Item
{
get { return item; }
}
public ItemList Items
{
get { return product.Items; }
}
public Pers Pers
{
get { return pers; }
set { value = pers; }
}
public PersList PersList
{
get { return product.PersList; }
}
}
The view has this code defined in it (I took out some other case lines, just to show one of them as an example):
<%# Page Language="C#" MasterPageFile="~/Views/Shared/MasterPages/Item.Master" Inherits="System.Web.Mvc.ViewPage<xxx.ViewModels.ItemViewModel>" %>
<% foreach (Pers p in Model.Perslist)
{
switch(p.DispType)
{
case DisType.Dropdown:
Model.Pers = p;
Html.RenderPartial("~/Views/Shared/Controls/Custom/PForm/DropDown.ascx",*Model);
break;
}
}
%>
And the RenderPartial looks like this:
<fieldset>
<div class="xxx">
<span class="xxx">*</span><label><%=Model.Pers.Name %></label>
<p class="xxx"><%=Model.Pers.Info %></p>
</div>
<div class="formField"><% Html.DropDownList(Model.Pers.Name, new SelectList(Model.Items[0].DropdownItems));%></div>
</fieldset>
The problem or dilemma I'm having is I not only need the p from the foreach but the entire ItemViewModel instance that was originally passed to my View. Because I need to use the Pers in that foreach as well as be able to reference the Items. So what I tried is to set the Pers property of the ItemViewModel class instance to the current p in the foreach. Then tried to send the whole Model (now that I have that Pers set on the property) which is of type ItemViewModel so that I can now use the property Pers on that object and also still be able to reference the Items property that was populated already when it hit the View.
So when the page renders I get:
System.NullReferenceException: Object reference not set to an instance of an object.
for this line:
<span class="xxx">*</span><label><%=Model.Pers.Name %></label>
So far I'm unsuccesful because I still get a null reference error on the property Pers when I attempt to use the ITemViewModel in my Partial View.
This could be because your partial view file needs this line above your html:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<xxx.ViewModels.**ItemViewModel**>" %>
So this is how your partial view should look:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<xxx.ViewModels.**ItemViewModel**>" %>
<fieldset>
<div class="xxx">
<span class="xxx">*</span><label><%=Model.Pers.Name %></label>
<p class="xxx"><%=Model.Pers.Info %></p>
</div>
<div class="formField"><% Html.DropDownList(Model.Pers.Name, new SelectList(Model.Items[0].DropdownItems));%></div>
</fieldset>
Good God, I set the property wrong. resolved. duh.

Resources