adding new comment in database for a post - asp.net-mvc

I am creating a forum application in mvc3...
I have a link called Add New Comment on Post page where user can add the comments for that post... for creating new comment i have written following code....
public ActionResult Addnew(int id)
{
Answer ans = new Answer();
ans.QuestionQId = id;
return View();
}
[HttpPost]
public ActionResult Addnew(Answer ans,int id)
{
_db.Answers.Add(ans);
_db.SaveChanges();
return View("Details");
}
but it is giving mean error whenever i try to save the code as follows:
Value cannot be null.
Parameter name: entity
I have two different table Question{id(pk), Question} and Answer{id(pk), ans, Qid(fk)}
All i want to do is While adding the comment for a perticular question, its Qid will be stored in answer database .....
Help me!!
View Related --
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Answer</legend>
<div class="editor-label">
#Html.LabelFor(model => model.AId)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.AId)
#Html.ValidationMessageFor(model => model.AId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Ans)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Ans)
#Html.ValidationMessageFor(model => model.Ans)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.QuestionQId)
</div> <div class="display-field">
#Html.DisplayFor(modelItem => modelItem.QuestionQId)
</div>
}

I think you are not passing the Answer object to the view, may caused the problem. have you tried following
public ActionResult Addnew(int id)
{
Answer ans = new Answer();
ans.QuestionQId = id;
return View(ans);
}

is it in your route define parameter for your controller?
may be this is your problem!

Related

Why would Entity Framework carry out update when RowVersion has changed?

I'm having a problem trying to catch a DbUpdateConcurrencyException using Entity Framework 5. The problem that I'm having is that EF is updating the record, even though the RowVersion (Timestamp) property has changed since the row was retrieved from the database. The HttpGet Edit action gets a user profile from the database and I pass the values to a ViewModel, including a list of checkboxes for the user to select the roles and pass this to the view.
public ActionResult Edit(int id = 0)
{
UserProfile userProfile = unitOfWork.UserProfileRepository.GetUserProfileById(id);
UserProfileEditViewModel viewModel = new UserProfileEditViewModel
{
UserId = userProfile.UserId,
UserName = userProfile.UserName,
FirstName = userProfile.FirstName,
LastName = userProfile.LastName,
Email = userProfile.Email,
RowVersion = userProfile.RowVersion,
};
var allRoles = unitOfWork.RoleRepository.GetAllRoles();
var userProfileRoles = userProfile.Roles;
foreach (var role in allRoles)
{
if (userProfileRoles.Contains(role))
{
viewModel.Roles.Add(new RoleViewModel
{
RoleId = role.RoleId,
RoleName = role.RoleName,
Assigned = true,
});
}
else
{
viewModel.Roles.Add(new RoleViewModel
{
RoleId = role.RoleId,
RoleName = role.RoleName,
Assigned = false,
});
}
}
return View(viewModel);
}
I then have a basic edit view that has a HiddenFor for the RowVersion property.
#model MvcWebsite.ViewModels.UserProfileEditViewModel
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>UserProfile</legend>
#Html.HiddenFor(model => model.UserId)
#Html.HiddenFor(model => model.UserName)
#Html.HiddenFor(model => model.RowVersion)
<div class="editor-label">
#Html.LabelFor(model => model.UserName)
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Email)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Email)
#Html.ValidationMessageFor(model => model.Email)
</div>
<div class="editor-field">
<table>
<tr>
#Html.EditorFor(model => model.Roles)
#Html.ValidationMessageFor(model => model.Roles)
</tr>
</table>
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
I then have a HttpPost Edit action that takes the data from the viewModel and adds it to a user profile that I've retrieved from the database. I then change the properties of this profile to those that were retrieved from the client, including the RowVersion (changing the RowVersion back to its original state)
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(UserProfileEditViewModel model)
{
try
{
if (ModelState.IsValid)
{
var userProfile = unitOfWork.UserProfileRepository.GetUserProfileById(model.UserId);
userProfile.UserName = model.UserName;
userProfile.FirstName = model.FirstName;
userProfile.LastName = model.LastName;
userProfile.Email = model.Email;
userProfile.RowVersion = model.RowVersion;
var roleAssignments = model.Roles;
foreach (var roleAssignment in roleAssignments)
{
if (roleAssignment.Assigned)
{
userProfile.Roles.Add(unitOfWork.RoleRepository.GetRoleById(roleAssignment.RoleId));
}
else
{
userProfile.Roles.Remove(unitOfWork.RoleRepository.GetRoleById(roleAssignment.RoleId));
}
}
unitOfWork.UserProfileRepository.UpdateUserProfile(userProfile);
unitOfWork.Save();
return RedirectToAction("Details", new { id = userProfile.UserId });
}
}
catch (DbUpdateConcurrencyException ex)
{
... Code omitted for brevity
}
}
return View(model);
}
I test this by opening the edit page twice. I then update the second page and click save, which commits the changes to the database. The database shows that the row version has in fact been changed to reflect the update. When I change the second page and click save, even though the row version of this profile is different from the row version that was created when the first profile was saved, the changes are saved to the database also. I've checked that indeed, the row version in the database is actually changed twice.
I have a funny feeling that I'm missing the obvious here, but any help would be greatly appreciated.
typically you don't change the row version explicitly. this would be handled by the ORM itself. What you would do is compare the view model version to the domain version. if they do not match you then need to handle that scenario.
if(viewmodel.RowVersion != domainModel.RowVersion)
{
//model has changed, notify user...
}
else
{
//update domain model
//save changes
}
You could further prevent this by making RowVersion immutable
class domainmodel
{
...
public int RowVersion {get; private set;}
}

MVC4 Pass custom view Model back to Controller Action

I have a custom class
public class BloggerViewModel
{
public Person Blogger;
public List<BloggerWebsite> BloggerWebsites;
}
That I pass into a view
[HttpGet]
public ActionResult Edit(int id)
{
blogger = GetById(id);
var WebSites = GetBloggersWebsites(Id);
var BloggerViewModel = new BloggerViewModel();
BloggerViewModel.Blogger = blogger;
BloggerViewModel.BloggerWebsites = WebSites;
return View(BloggerViewModel);
}
Then when I post back to the edit action
[HttpPost]
public ActionResult Edit(BloggerViewModel entity)
{
return View(entity);
}
entity is null.
My view is something like this ( I took out allot of the code that you didn't need to see. Such as most of the text box bindings)
#model Bloginect.Model.Models.BloggerViewModel
<h2>Edit</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Person</legend>
#Html.HiddenFor(model => model.Blogger.Id)
<div class="editor-label">
#Html.LabelFor(model => model.Blogger.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Blogger.FirstName)
#Html.ValidationMessageFor(model => model.Blogger.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Blogger.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Blogger.LastName)
#Html.ValidationMessageFor(model => model.Blogger.LastName)
</div>
<div class="editor-field">
#if (Model.BloggerWebsites[0].Website != null)
{
Html.EditorFor(model => model.BloggerWebsites[0].Website);
}
else
{
#Html.TextBox("Website1")
}
</div>
<div class="editor-field">
#if (Model.BloggerWebsites[1].Website != null)
{
Html.EditorFor(model => model.BloggerWebsites[0].Website);
}
else
{
#Html.TextBox("Website2")
}
</div>
<div class="editor-field">
#if (Model.BloggerWebsites[2].Website != null)
{
Html.EditorFor(model => model.BloggerWebsites[0].Website);
}
else
{
#Html.TextBox("Website3")
}
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Is there something I am doing wrong? I have checked out some of the other replies to similar questions on this and they did not answer my question.
You must use editors to handle the bindings to your nested model properties, a good example on how to do it can be found here.

Saving forms in mvc

I'm completely new to MVC having made the decision to try make the switch from aspx WebForms.
I have created a view using the MVC view creator wizard and selected a strongly typed class and an edit Scaffold template.
I got the following
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Company</legend>
#Html.HiddenFor(model => model.Id)
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.PhoneNumber)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PhoneNumber)
#Html.ValidationMessageFor(model => model.PhoneNumber)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
In the Controller I have the following to get the model details
[System.Web.Http.HttpGet]
public ActionResult Edit(int id)
{
var uow = new BlogUow();
var company = uow.Companies.GetById(id);
return View(company);
}
This works fine but the problem is, I'm stumped on how I actually save the newly entered details.
I relied too much on how the web forms handle post backs.
You must write a post action for your edit in the controller:
[System.Web.Http.HttpPost]
public ActionResult Edit(Companies company)
{
var uow = new BlogUow();
if (ModelState.IsValid)
{
uow.Entry(company).State = EntityState.Modified;
return RedirectToAction("Index");
}
return View(company);
}
note Companies overload
[HttpPost]
public ActionResult Edit(Companies company)
{
var uow = new BlogUow();
if (ModelState.IsValid)
{
Edit here
}
return View(company);
}

ValidationMessageFor for different object

I'm using mvc4, in my view I have a declaration
#model IEnumerable<UserDisplay>
on the same view I want to have a Form with "create" post for different object type name "Review"
how can I use the EditorFor and ValidationMessageFor ? cause model is of different type.
this is not working
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Review</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Info)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Info)
#Html.ValidationMessageFor(model => model.Info)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.FromId)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FromId)
#Html.ValidationMessageFor(model => model.FromId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ToId)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ToId)
#Html.ValidationMessageFor(model => model.ToId)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Create a partial view for that form that uses the #model declaration of the required type then use #Html.Partial("mySubFormView"). Don't mix model types in your views, it makes life too complicated.
You can use a view model containing both objects.
public class MyViewModel
{
public IEnumerable<UserDisplay> { get; set; }
public Review Review { get; set; }
}
Then your model declaration in the view becomes:
#model TheNamespace.For.MyViewModel
Which will allow you to use #Html.EditorFor and #Html.ValidationMessageFor helpers.

Using Fluent NHibernate in MVC to map an object in a Create View

I'm trying to use Fluent NHibernate instead of Entity Framework in the MvcMusicStore example and am having a problem populating the ArtistId and GenreId on creating a new album using the Create View. I think it's something to do with the fact i'm referencing other objects
My Album Map is:
public class AlbumMap:ClassMap<Album>
{
public AlbumMap()
{
Id(x => x.AlbumId);
Map(x => x.AlbumArtUrl);
References(x => x.Artist).Cascade.All().Column("ArtistId");
References(x => x.Genre).Cascade.All().Column("GenreId");
Map(x => x.Price);
Map(x => x.Title);
}
}
The Create method in the controller looks like:
public ActionResult Create()
{
MusicRepository repository = new MusicRepository();
ViewBag.ArtistId = new SelectList(repository.GetArtists(), "ArtistId", "Name");
ViewBag.GenreId = new SelectList(repository.GetGenres(), "GenreId", "Name");
return View();
}
and the part of the Create view which I'm having a problem with is:
<div class="editor-label">
#Html.LabelFor(model => model.Genre, "Genre")
</div>
<div class="editor-field">
#Html.DropDownList("GenreId", String.Empty)
#Html.ValidationMessageFor(model => model.Genre)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Artist, "Artist")
</div>
<div class="editor-field">
#Html.DropDownList("ArtistId", String.Empty)
#Html.ValidationMessageFor(model => model.Artist)
</div>
In the database, after creating a new Album the other fields such as Title and AlbumUrl are filled in but ArtistId and GenreId are set to null.
You can probably tell I'm quite new to this but I have actually solved my problem. I did this by firstly changing the dropdownlist helpers to dropdownlistfor to enable it to save back:
<div class="editor-label">
#Html.LabelFor(model => model.Genre, "Genre")
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.Genre.GenreId, (SelectList)ViewBag.GenreId,"Please select")
#Html.ValidationMessageFor(model => model.Genre.GenreId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Artist, "Artist")
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.Artist.ArtistId, (SelectList)ViewBag.ArtistId,"Please select")
#Html.ValidationMessageFor(model => model.Artist.ArtistId)
</div>
This returned me an album with initialised Artist and Genre properties. The only thing was that they only contained Id properties so I had to use these to get the rest of the properties (using nhibernate) before saving:
[HttpPost]
public ActionResult Create(Album album)
{
try
{
MusicRepository repository = new MusicRepository();
if (ModelState.IsValid)
{
album.Artist = repository.GetArtistById(album.Artist.ArtistId);
album.Genre = repository.GetGenreById(album.Genre.GenreId);
repository.AddAlbum(album);
return RedirectToAction("Index");
}
ViewBag.ArtistId = new SelectList(repository.GetArtists(), "ArtistId", "Name");
ViewBag.GenreId = new SelectList(repository.GetGenres(), "GenreId", "Name");
return View(album);
}

Resources