after looking for an answer in the already existing questions, I am still a little confused as how I should proceed. I am new to the MVC 3 framework, so if I come off sounding like a dope, I appologize!!
Ok, so I created a MVC 3 internet application, created 3 new Users administrator, user1, and user2. I have created a new model, and controller for my "Posts" I am able to add, edit and delete the items. I currently have a column called UserID in my posts table. I would like this to be automagically populated with the current UsersID. I think I would define this in the controller like this:
[HttpPost]
public ActionResult Create(Post post)
{
if (ModelState.IsValid)
{
public int User = System.Web.Security.Membership.GetUser(id);
db.Posts.Add(post);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(post);
}
Inside the model, this is what I currently have:
public class Post
{
public int PostID { get; set; }
public int UserID { get; set; }
public string PostTitle { get; set; }
public int PostType { get; set; }
public string PostBody { get; set; }
public string PostBlogTitle { get; set; }
public string PostBlogURL { get; set; }
public string PostCategory { get; set; }
public string PostSEO { get; set; }
public int PostStatus { get; set; }
}
public class PostDBContext : DbContext
{
public DbSet<Post> Posts { get; set; }
}
I would like to replace public int UserID { get; set; } with my newly defined variable in the controller, but not sure where/how to add it.
Not sure I'm clear on what you're trying to achieve. Are you just trying to assign the current user to the model, save it and then pass it back to the view?
If so you can just do this:
[HttpPost]
public ActionResult Create(Post post)
{
if (ModelState.IsValid)
{
// Note: I'm assuming this actually works/returns an int
public int User = System.Web.Security.Membership.GetUser(id);
post.UserID = User;
db.Posts.Add(post);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(post);
}
Related
I'm building an MVC 3 website. I have a model looking like this:
public class Survey
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime DateStart { get; set; }
public DateTime DateEnd { get; set; }
// Not in view
public DateTime DateCreated { get; set; }
// Not in view
public DateTime DateModified { get; set; }
}
Based on this I also have a View Model to edit the survey information:
public class SurveyEditViewModel
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime DateStart { get; set; }
public DateTime DateEnd { get; set; }
}
When the user finishes editing I would like to persist the changes. Here's my controller post action:
[HttpPost]
public ActionResult Edit(SurveyEditViewModel model)
{
// Map the view model to a domain model using AutoMapper
Survey survey = Mapper.Map<SurveyEditViewModel, Survey>(model);
// Update the changes
_repository.Update(survey);
// Return to the overview page
return RedirectToAction("Index");
}
In my repository (it's a generic one for now) I have the following code:
public void Update(E entity)
{
using (ABCDataContext context = new ABCDataContext())
{
context.Entry(entity).State = System.Data.EntityState.Modified;
context.SaveChanges();
}
}
When this executes I get the following error: "Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries."
I guess this was to be expected. Mapping from the view model to the model doesn't give me a complete Survey object.
I could modify my controller to look like this. And then it works:
[HttpPost]
public ActionResult Edit(SurveyEditViewModel model)
{
// Map the model to a real survey
survey = _repository.Find(model.Id);
survey.Name = model.Name;
survey.Description = model.Description;
survey.DateStart = model.DateStart;
survey.DateEnd = model.DateEnd;
// Update the changes
_repository.Update(survey);
// Return to the overview page
return RedirectToAction("Index");
}
But I was wondering if a better way is available?
[HttpPost]
public ActionResult Edit(SurveyEditViewModel model)
{
// Fetch the domain model to update
var survey = _repository.Find(model.Id);
// Map only the properties that are present in the view model
// and keep the other domain properties intact
Mapper.Map<SurveyEditViewModel, Survey>(model, survey);
// Update the changes
_repository.Update(survey);
// Return to the overview page
return RedirectToAction("Index");
}
I have three related tables. Calendar 1...* CalendarUser *...1 User. When I have edited the CalendarUsers in the edit calendar view I then post the ViewModel back to the controller. Here is my controller code:
[HttpPost]
public ActionResult Edit(int id, CreateCalendarViewModel cvm)
{
long userId = long.Parse(User.Identity.Name);
db.Calendars.Attach(cvm.CurrentCalendar);
cvm.Users= DbExtensions.GetUserList(userId);
if (ModelState.IsValid)
{
////Remove the deselected users
cvm.CurrentCalendar.CalendarUsers.Clear();
//Get the names from the selected users
var selectedUsers = from u in cvm.Users
where cvm.SelectedUsers.Contains(u.Key)
select new KeyValuePair<long, string>(long.Parse(u.Key), u.Value);
foreach (var selectedUser in selectedUsers)
{
User user = db.Users.Find(selectedUser.Key);
//If usr does not exist create a new
if (user == null)
{
db.Users.Add(new User
{
UserId = selectedUser.Key,
Name = selectedUser.Value,
Expires = DateTime.Now,
AccessToken = string.Empty
});
}
//Add the binding to the calendar
cvm.CurrentCalendar.CalendarUsers.Add(new CalendarUser
{
CalendarId = cvm.CurrentCalendar.CalendarId,
UserId = selectedUser.Key
});
}
db.Entry(cvm.CurrentCalendar).State = EntityState.Modified;
db.SaveChanges();
}
return View(cvm);
}
Here are my classes:
public partial class Calendar
{
public Calendar()
{
this.CalendarUsers = new HashSet<CalendarUser>();
}
public int CalendarId { get; set; }
public string CalendarTitle { get; set; }
public string CalendarDescription { get; set; }
public long UserId { get; set; }
public virtual User User { get; set; }
public virtual ICollection<CalendarUser> CalendarUsers { get; set; }
}
public partial class CalendarUser
{
public int CalendarUserId { get; set; }
public int CalendarId { get; set; }
public long UserId { get; set; }
public Nullable<bool> IsAdmin { get; set; }
public virtual Calendar Calendar { get; set; }
public virtual User User { get; set; }
}
public partial class User
{
public User()
{
this.Calendars = new HashSet<Calendar>();
this.CalendarUsers = new HashSet<CalendarUser>();
}
public long UserId { get; set; }
public string Name { get; set; }
public virtual ICollection<Calendar> Calendars { get; set; }
public virtual ICollection<CalendarUser> CalendarUsers { get; set; }
}
For some reason when i save the changes the calendar is being deleted as well? I've searched a bit but noone seem to have the same problem? Am I doing it wrong? Is there a better way to update/remove related entities?
It seems that I forgot to include a hidden field in in the view containing the id of the user and the result was that when I updated the calendar it saved with Id = 0 and thus hid the objects in the view for the specified user. Mental note: Always verify in the database what is really happening.
I also need to look into whats happening when I send objects back and forth between views and controller. Sometimes it seems to manage by itself and sometimes I need to specify all the fields myself.
I have a class, which has 8 props / 8 columns in DB. But on a Edit page, i dont want to show the AddedDate or UserID field, since i dont want user to change it.
public class Voucher
{
public int ID { get; set; }
public string Title { get; set; }
public string SiteName { get; set; }
public string DealURL { get; set; }
public DateTime AddedDate { get; set; }
public DateTime? ExpirationDate { get; set; }
public string VoucherFileURL { get; set; }
public Guid UserID { get; set; }
}
Here is what I have for Edit controller:
// POST: /Voucher/Edit/5
[HttpPost]
public ActionResult Edit(Voucher voucher)
{
if (ModelState.IsValid)
{
string[] excludeProperties = { "AddedDate", "UserID" };
UpdateModel(ModelState, "", null, excludeProperties);
db.Entry(voucher).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(voucher);
}
On Edit page, once i click on submit, i got the following error: System.Data.SqlServerCe.SqlCeException: An overflow occurred while converting to datetime.
Seems like the AddedDate didn't get excluded from the view model and triggered the error.
Would you please let me know how to fix it? Thanks!
public ActionResult Edit([Bind(Exclude = "AddedDate")]Voucher voucher)
no luck either
You are still passing in Voucher which could contain that field in it. I'm not sure what you are trying to accomplish with the UpdateModel here if you are already passing in a Voucher object?
Pass in Voucher, set it to modified and save it. If you want to use whats in the database then you'll have to
Load the object from the database
UpdateModel and exclude the properties
Save your entity.
You could simply use a View Model and post that.
public class Voucher
{
public int ID { get; set; }
public string Title { get; set; }
public string SiteName { get; set; }
public string DealURL { get; set; }
public DateTime? ExpirationDate { get; set; }
public string VoucherFileURL { get; set; }
public Guid UserID { get; set; }
}
and then load up your object from the db":
var voucher = db.Vouchers.Where(o=>o.ID==voucherViewModel.Id);
//manually copy the fields here then save it
//copy
db.SaveChanges();
I have the properties for two entities in a ViewModel. The two entities are both related to one another, so for example, User and Posts. Each User can have multiple Posts, and Many Posts can belong to a single user (one-to-many).
The aim from my ViewModel is to allow the addition of a User and a Post on the same form. So my ViewModel looks something like this:
public class CreateVM
{
[Required, MaxLength(50)]
public string Username { get; set; }
[Required, MaxLength(500), MinLength(50)]
public string PostBody { get; set; }
// etc with some other related properties
}
In my Controller on the Create Method I have something like this:
[HttpPost]
public ActionResult Create(CreateVM vm)
{
if (ModelState.IsValid)
{
User u = new User()
{
Username = vm.Username,
// etc populate properties
};
Post p = new Post()
{
Body = vm.PostBody,
// etc populating properties
};
p.User = u; // Assigning the new user to the post.
XContext.Posts.Add(p);
XContext.SaveChanges();
}
}
It all looks fine when I walk through it through the Debugger, but when I try to view the post, its User relationship is null!
I also tried
u.Posts.Add(p);
UPDATE:
My Post class code is as follows:
public class Post
{
[Key]
public int Id { get; set; }
[Required, MaxLength(500)]
public string Body { get; set; }
public int Likes { get; set; }
[Required]
public bool isApproved { get; set; }
[Required]
public DateTime CreatedOn { get; set; }
[Required]
public User User { get; set; }
}
But that also did not work. What am I doing wrong?
Problem is that EF can not lazy load the User property because you haven't made it virtual.
public class Post
{
[Key]
public int Id { get; set; }
[Required, MaxLength(500)]
public string Body { get; set; }
public int Likes { get; set; }
[Required]
public bool isApproved { get; set; }
[Required]
public DateTime CreatedOn { get; set; }
[Required]
public virtual User User { get; set; }
}
If you know beforehand that you are going to access the User property of the post you should eager load the User related to the post.
context.Posts.Include("User").Where(/* condition*/);
My project has two objects: users and meetings
Every meeting has one user that is the "head" of the meeting and a many users that are simple.
My models are these:
public class Meeting
{
public int MeetingId { get; set; }
public string Title { get; set; }
public virtual User User { get; set; }
public Location From { get; set; }
public Location To { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public class Location
{
public float Lat { get; set; }
public float Long { get; set; }
}
public class User
{
public int UserId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
I created a controller for the meeting model. Now every time that i add another meeting a and in the user field i put an existing userid this user is not inserted and new user is created.
What's wrong?
edit
the create controller
[HttpPost]
public ActionResult Create(Tremp tremp)
{
if (ModelState.IsValid)
{
db.Tremps.Add(tremp);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(tremp);
}
in the form i just enter the id of the user
I'm no expert on EF code first, but your code example did cause some deja vu for me. I think the problem is that you need to configure the relationship between the "head" user and the meeting e.g.
public class Meeting
{
public int MeetingId { get; set; }
public string Title { get; set; }
[ForeignKey("UserId")]
public virtual User User { get; set; }
[Column(name: "UserId")]
public int HeaderUserId { get; set; }
public Location From { get; set; }
public Location To { get; set; }
public virtual ICollection<User> Users { get; set; }
}
If your tremp entity has a reference to an existing user (tremp.User) you must attach this user to the context before you add the tremp. This tells EF that this user is existing in the database and avoids to insert a new user:
[HttpPost]
public ActionResult Create(Tremp tremp)
{
if (ModelState.IsValid)
{
db.Users.Attach(tremp.User);
db.Tremps.Add(tremp);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(tremp);
}