Nested entity not being saved - c#

I have the following method that saves an EmailTemplate. Based on the ID of a dropdown it populates the EmailAccount as the foreign entity property.
public ActionResult Edit([Bind(Include = "EmailAccountId, EmailTemplate")] EmailTemplateViewModel emailTemplateViewModel)
{
if (ModelState.IsValid)
{
if (emailTemplateViewModel.EmailAccountId > 0)
{
emailTemplateViewModel.EmailTemplate.EmailAccount = db.EmailAccounts.Find(emailTemplateViewModel.EmailAccountId);
}
db.Entry(emailTemplateViewModel.EmailTemplate).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(emailTemplateViewModel);
}
Everything in the EmailTemplate saves fine apart from EmailAccount. In debugger I can see that the property is populated before db.SaveChanges() is called.
I am setting the entity state to EntityState.Modified but it's not picking up the foreign property.
I tried adding:
db.Entry(emailTemplateViewModel.EmailTemplate.EmailAccount).State = EntityState.Modified;
But this didn't work. How do I tell EntityFramework that it needs to save the nested entity?
Edit:
As requested
public class EmailTemplateViewModel
{
public List<EmailAccount> EmailAccounts { get; set; }
public EmailTemplate EmailTemplate { get; set; }
[Display(Name = "Email Account")]
public int EmailAccountId { get; set; }
public IEnumerable<SelectListItem> EmailAccountsList
{
get
{
var allEmails = EmailAccounts.Select(e => new SelectListItem { Value = e.ID.ToString(), Text = e.Email });
return DefaultEmailAccountList.Concat(allEmails);
}
}
public IEnumerable<SelectListItem> DefaultEmailAccountList
{
get
{
return Enumerable.Repeat(new SelectListItem
{
Value = "-1",
Text = "Select Email Account"
}, count: 1);
}
}
}
public class EmailTemplate
{
public int ID { get; set; }
[StringLength(50)]
[Index(IsUnique = true)]
public string Identifier { get; set; }
public int Interval { get; set; }
public string TitleTemplate { get; set; }
[DataType(DataType.MultilineText)]
public string BodyTemplate { get; set; }
public virtual EmailAccount EmailAccount { get; set; }
}

I was modifying before I attached so the change wasn't tracked.
This works
if (ModelState.IsValid)
{
db.Entry(emailTemplateViewModel.EmailTemplate).State = EntityState.Modified;
if (emailTemplateViewModel.EmailAccountId > 0)
{
emailTemplateViewModel.EmailTemplate.EmailAccount = db.EmailAccounts.Find(emailTemplateViewModel.EmailAccountId);
}
db.SaveChanges();
return RedirectToAction("Index");
}
return View(emailTemplateViewModel);

Related

how i update multiple table using viewmodel in Asp.net mvc

Employee Model
public class Employee
{
[Key]
public int EmployeeID { get; set; }
public string Name { get; set; }
public virtual Department Departments { get; set; }
public int DepartmentID { get; set; }
}
Department Model
public class Department
{
public int DepartmentID { get; set; }
public string DepartmentName { get; set; }
}
View Model for Department and Employee
public class EDViewModel
{
public int ID { get; set; }
public int EmployeeID { get; set; }
public string Name { get; set; }
public Department Departments { get; set; }
public int DepartmentID { get; set; }
public string DepartmentName { get; set; }
}
Now i want to update both tables with single view.
Controller
public ActionResult Edit(int?id)
{
// write some code for update both table at once time
}
PostMethod
[HttpPost]
public ActionResult Edit(EDViewModel Emodel)
{
var user = db.Employees.Where(c => c.Employee_Id == Emodel.Employee_Id).FirstOrDefault();
user.UserName = Emodel.UserName;
user.ProfilePicture = Emodel.ProfilePicture;
db.Entry(user).State = EntityState.Modified;
db.Entry(user).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Home");
}
But in this method only Update Employee record not department
After many searching finally i get a solid solution
hope you like or improve this.
Controller
public ActionResult Edit(int? id)
{
MYDb db = new MYDb();
var user = db.Employees.Where(c => c.Employee_Id == Emodel.Employee_Id).FirstOrDefault();
if (user != null)
{
var vm = new EDViewModel { Employee_id = user.Employee_id, departmentName = user.departmentName };
if (user.department != null)
{
user.Departmet_id = vm.Departments.Departmet_id;
user.DepartmentName = vm.Departments.DepartmentName;
user.Employee_id = vm.employee_id;
user.employeeName = vm.employeeName;
}
return View(user);
}
return Content("Invalid Id");
}
[HttpPost]
public ActionResult Edit(EDViewModel Emodel)
{
var user = db.Employees.Where(c => c.Employee_Id == Emodel.Employee_Id).FirstOrDefault();
user.EmployeeId = Emodel.EmployeeId;
user.EmployeeName= Emodel.EmployeeName;
user.DepartmentName= Emodel.Departmt.DepartmentName;
// Just remove this line
// db.Entry(user).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Home");
}
it worked for me
just remove this
db.Entry(user).State = EntityState.Modified;
if we not remove this entityvalidation occur

Model.get returned Null MVC C#

Upon my post ActionResult Edit, I am receiving an error. System.Web.Mvc.WebViewPage<TModel>.Model.get returned null
My controller:
[HttpPost]
public ActionResult Edit(editRequestViewModel _editRequestViewModel, int id)
{
try
{
if (ModelState.IsValid)
{
using (var db = new HelpDeskContext())
{
db.Entry(_editRequestViewModel.userRequest).State = System.Data.Entity.EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Digest",new { id = _editRequestViewModel.userRequest.ID });
}
}
else
return View();
}
catch (Exception ex)
{
return View("Error", new HandleErrorInfo(ex, "Change", "Browse"));
}
}
My View includes this for the models field to bind:
#Html.DropDownListFor(model => model.userRequest.forApplication, Model.Applications, "Select Application", new { #class = "form-control" })
My Model has the field as nullable int?:
public int? forApplication { get; set; }
It seems to update the other fields in the model with this field just fine on POST. When the request is first created and saved to the DB, it saves fine in that field when its null. It seems to me that nullable should be OK as a value when its posting (Edit ActionResult)?
EDIT: This is my GET Method that populates the View Model which is passed in to the POST.
public ActionResult Edit(int id)
{
try
{
if (ModelState.IsValid)
{
using (var db = new HelpDeskContext())
{
var query = (from m in db.Requests
where m.ID == id
select new editRequestViewModel()
{
Applications = (from r in db.Applications
select new SelectListItem(){
Text = r.Name,
Value = r.ID.ToString()
}).ToList(),
closeReasons = (from r in db.CloseReasons
select new SelectListItem()
{
Text = r.Name,
Value = r.ID.ToString()
}).ToList(),
userRequest = m
}).FirstOrDefault();
return View(query);
}
}
else
return View();
}
catch (Exception ex)
{
return View("Error", new HandleErrorInfo(ex, "Change", "Browse"));
}
}
And my View has #model HelpDeskSolution.ViewModels.editRequestViewModel
EDIT 2: ViewModel and Model
namespace HelpDeskSolution.Models
{
public class Request
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity), Key()]
public int ID { get; set; }
[Required]
[StringLength(99, MinimumLength = 3)]
public string Title { get; set; }
[StringLength(1000, MinimumLength = 1)]
[Required]
public string Description { get; set; }
[Required]
[Display(Name = "Submit Date")]
public DateTime SubmitDate { get; set; }
public DateTime? CloseDate { get; set; }
[Required]
[StringLength(30)]
public string Author { get; set; }
[Required]
[StringLength(30)]
public string AuthDept { get; set; }
[StringLength(30)]
[Display(Prompt = "Text at top of Epicor Screen...(Optional)")]
public string Module { get; set; }
public int Urgency { get; set; }
[StringLength(30)]
public string Type { get; set; }
public int Status { get; set; }
[StringLength(30)]
[Display(Name = "Request For")]
public string RequestFor { get; set; }
[Required]
public bool Closed { get; set; }
[StringLength(30)]
[Display(Name = "Assign To")]
public string AssignedTo { get; set; }
[Display(Name = "Application")]
public int? forApplication { get; set; }
public int? closeReason { get; set; }
public string ClosedBy { get; set; }
[Display(Name = "ID")]
public int? duplicateOf { get; set; }
}
}
Model:
namespace HelpDeskSolution.ViewModels
{
public class editRequestViewModel
{
public Request userRequest { get; set; }
public List<SelectListItem> Applications { get; set; }
public List<SelectListItem> closeReasons { get; set; }
}
}
Ended up solving this with the direction of #StephenMuecke. The reason I was getting the exception is because upon the return View() in the else portion of the post action, it was attempting to return the view without Applications list, as Stephen said. However that led me to realize that there was first a problem with the Model State, hence why it was even going to the else in the first place. I had another field that was being passed null when it wasnt a nullable type.
I simply changed the type to int? and added a migration and the Action result is A'Okay now.

How to edit multiple tables in MVC using ViewModel pattern

I am trying to perform CURD operation in MVC web application in a webgrid but the problem is I have multiple tables but don't know how to perform EDIT operation by using multiple tables.
Invoice table
public Invoice()
{
this.LineItems = new HashSet<LineItem>();
}
public int Customer_ID { get; set; }
public string Customer_name { get; set; }
public string Customer_Address { get; set; }
public virtual ICollection<LineItem> LineItems { get; set; }
Product Table
public Produc()
{
this.LineItems = new HashSet<LineItem>();
}
public int Product_ID { get; set; }
public string Product_name { get; set; }
public int Unit_Price { get; set; }
public virtual ICollection<LineItem> LineItems { get; set; }
LineItems Table
public partial class LineItem
{
public int Customer_ID { get; set; }
public int LineItems_ID { get; set; }
public int Product_ID { get; set; }
public int Quantity { get; set; }
public int Total { get; set; }
public virtual Invoice Invoice { get; set; }
public virtual Produc Produc { get; set; }
}
ViewModel
public class ViewModel
{
public string Customer_name { get; set; }
public string Customer_Address { get; set; }
public int Quantity { get; set; }
public int Total { get; set; }
public string Product_name { get; set; }
public int Unit_Price { get; set; }
}
here is a class which will perform CURD operation for me
public class Class1
{
SalesOrderEntities entities = new SalesOrderEntities();
public bool SaveStudent(ViewModel viewModel)
{
try
{
var Invoice = new Invoice()
{
Customer_name = viewModel.Customer_name,
Customer_Address = viewModel.Customer_Address
};
var LineItem = new LineItem()
{
Quantity = viewModel.Quantity,
Total = viewModel.Total
};
var Produc = new Produc()
{
Product_name=viewModel.Product_name,
Unit_Price=viewModel.Unit_Price
};
return true;
}
catch
{
return false;
}
}
public bool UpdateStudent()
{
try
{
}
catch (Exception)
{
throw;
}
}
Now, here i have problem i don't know how to perform edit functionality.
Updating using Entity Framework can be fairly straight-forward as it supports change-tracking by default. Change tracking will let EF automatically manage any changes that occur to your entities once they are pulled, so that when you call SaveChanges(), these same changes will be made at the database-level.
Example Adding New Entities
Since you already have your data context, when you are creating your new entities, you'll just need to ensure that you add them to the context properly and save the changes after that is done :
// Add each of your new entities to their appropriate table in the context and then save
// your changes
entities.Invoices.Add(new Invoice(){
Customer_name = viewModel.Customer_name,
Customer_Address = viewModel.Customer_Address
});
entities.LineItems.Add(new LineItem(){
Quantity = viewModel.Quantity,
Total = viewModel.Total
});
entities.Producs.Add(new Produc(){
Product_name = viewModel.Product_name,
Unit_Price = viewModel.Unit_Price
});
// Now save your changes
entities.SaveChanges();
Example Updating Existing Entities
Updating will essentially work the same way, however you will want to have access to the identifier so that you can query the existing entity, make your changes and save them :
public ActionResult UpdateStudent(int studentId)
{
using(var entities = new SalesOrderEntities())
{
// Get your student
var student = entities.Students.FirstOrDefault(s => s.StudentID == studentId);
if(student == null)
{
// Student wasn't found
return HttpNotFound();
}
// Create a view with the existing student data
return View(student);
}
}
[HttpPost]
public bool UpdateStudent(UpdateStudentViewModel viewModel)
{
try
{
using(var entities = new SalesOrderEntities())
{
// Retrieve your existing student (or other entities)
var existingStudent = entities.Students.FirstOrDefault(s => s.StudentID == viewModel.StudentID);
// Now that you have your entity, update the appropriate properties
existingStudent.Property = viewModel.Property;
// Then finally save your changes
entities.SaveChanges();
}
}
catch(Exception ex)
{
// Something went wrong updating the user
}
}

Saving multi-level entity

I have a 3 level entity and I am having some trouble saving it.
public partial class Event
{
public Event()
{
Recurrences = new HashSet<Recurrence>();
}
public int Id { get; set; }
public string Title { get; set; }
public ICollection<Recurrence> Recurrences { get; set; }
}
public partial class Recurrence
{
public Recurrence()
{
AspNetUsers = new HashSet<AspNetUser>();
}
public int Id { get; set; }
public int EventId { get; set; }
public string Venue { get; set; }
public ICollection<AspNetUser> AspNetUsers { get; set; }
}
public partial class AspNetUser
{
public AspNetUser()
{
Recurrences = new HashSet<Recurrence>();
}
public string Id { get; set; }
public string UserName { get; set; }
public ICollection<Recurrence> Recurrences { get; set; }
}
The Post controller for the Event Class looks like this:
// POST: api/Events
[ResponseType(typeof(Event))]
public async Task<IHttpActionResult> PostEvent(EventDTO #event)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var newEvent = new Event();
newEvent.Title = #event.Title;
newEvent.EventTypeId = #event.EventTypeId;
var recurrence = new Recurrence();
recurrence.Venue = #event.Venue;
var users = db.AspNetUsers.Where(u => #event.UserId.Contains(u.Id));
foreach (var u in users)
recurrence.AspNetUsers.Add(u);
newEvent.Recurrences.Add(recurrence);
db.Events.Add(newEvent);
await db.SaveChangesAsync();
return CreatedAtRoute("DefaultApi", new { id = newEvent.Id }, newEvent);
}
When I call the PostEvent method with an Event like DTO i get the http error code 500.
first, how can i add exception handling to capture the specific error and secondly, what I'm I doing wrong here?
Any help is deeply appreciated.
Thanks.

Many to Many Relationship on MVC5

So I'm in the middle of a project where I need to have a Many-to-Many relationship between Teams and Members.
One team can have many users (from aspnetusers) and a user can have 0 or more teams.
But at the moment, One team can have many users, but one user can only have 1 team, whenever I try to add a user on a new team, that user is removed from team he's already in.
I've reached this point thanks to http://cpratt.co/associating-related-items-in-a-collection-via-a-listbox/
My Team Model:
public class EquipaModel
{
[Key]
public int EquipaID { get; set; }
[Required]
[Display (Name="Nome")]
public string EquipaNome { get; set; }
[Required]
[Display (Name="Descrição")]
public string EquipaDescricao { get; set; }
[Display(Name = "Team Manager")]
public string TeamManagerId { get; set; }
public virtual ApplicationUser TeamManager { get; set; }
public virtual ICollection<ApplicationUser> Membros { get; set; }
}
My extended user model
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity>
GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
var userIdentity = await manager
.CreateIdentityAsync(this,
DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
}
public virtual Utilizador Utilizador { get; set; }
}
[Table("Utilizadores")]
public class Utilizador
{
public int Id { get; set; }
public string PrimeiroNome { get; set; }
public string Apelido { get; set; }
public int Pontuacao { get; set; }
public int PaisID { get; set; }
public virtual PaisModel Pais { get; set; }
//public IEnumerable<LinguasProgModel> Linguagens { get; set; }
}
My Team ViewModel
public class EquipasViewModel
{
[Required]
public string EquipaNome { get; set; }
public string EquipaDescricao { get; set; }
public string TeamManagerId { get; set; }
public virtual ApplicationUser TeamManager { get; set; }
[Required]
public List<string> MembrosID { get; set; }
public IEnumerable<SelectListItem> MembrosEscolhidos { get; set; }
}
My Create on EquipaController (TeamController)
public ActionResult Create()
{
ViewBag.TeamManagerId = new SelectList(db.Users, "Id", "Email");
var model = new EquipasViewModel();
PopulateMembrosEscolhidos(model);
return View(model);
}
[HttpPost]
public ActionResult Create(EquipasViewModel model)
{
if (ModelState.IsValid)
{
var equipa = new EquipaModel
{
EquipaNome = model.EquipaNome,
EquipaDescricao = model.EquipaDescricao,
TeamManagerId = model.TeamManagerId,
Membros = db.Users.Where(m => model.MembrosID.Contains(m.Id)).ToList()
};
db.Equipas.Add(equipa);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.TeamManagerId = new SelectList(db.Users, "Id", "Email", model.TeamManagerId);
PopulateMembrosEscolhidos(model);
return View(model);
}
and finally the Edit on my team controller
public ActionResult Edit(string id)
{
ViewBag.TeamManagerId = new SelectList(db.Users, "Id", "Email");
var equipa = db.Equipas.FirstOrDefault(e => e.EquipaNome == id);
if (equipa == null)
{
return new HttpNotFoundResult();
}
var model = new EquipasViewModel
{
EquipaNome = equipa.EquipaNome,
EquipaDescricao = equipa.EquipaDescricao,
MembrosID = equipa.Membros.Select(m => m.Id).ToList()
};
PopulateMembrosEscolhidos(model);
return View(model);
}
[HttpPost]
public ActionResult Edit(string id, EquipasViewModel model)
{
var equipa = db.Equipas.FirstOrDefault(e => e.EquipaNome == id);
if (equipa == null)
{
return new HttpNotFoundResult();
}
if (ModelState.IsValid)
{
equipa.EquipaNome = model.EquipaNome;
equipa.EquipaDescricao = model.EquipaDescricao;
equipa.Membros.Where(m => !model.MembrosID.Contains(m.Id))
.ToList()
.ForEach(m => equipa.Membros.Remove(m));
var MembrosNaEquipa = equipa.Membros.Select(m => m.Id);
var NovosMembros = model.MembrosID.Except(MembrosNaEquipa);
db.Users.Where(m => NovosMembros.Contains(m.Id))
.ToList()
.ForEach(m => equipa.Membros.Add(m));
db.Entry(equipa).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
PopulateMembrosEscolhidos(model);
return View(model);
}
At some point, I'm going to remove the selectlist and replace it for a textbox where the user inputs user names to add to the memberlist of the team - but at the moment i'm just trying to figure out how to save the many-to-many relationship.
Edit
I had that feeling that it was something simple, but just couldn't get there. I started using that solution, but came across an error that to be honest, I've never seen before.
Multiplicity constraint violated. The role 'ApplicationUser_Equipas_Source' of the relationship 'Codings.Models.ApplicationUser_Equipas' has multiplicity 1 or 0..1.
It happens on line "db.Equipas.Add(equipa);" of Create.
It's probably my mistake, since I tried to add a team to the users simply by
var MembrosEscolhidos = db.Users.Where(m => model.MembrosID.Contains(m.Id)).ToList();
foreach (var item in MembrosEscolhidos)
{
item.Equipas.Add(equipa);
}
I think one easy fix would be to reference your EquipaModel as a collection in your users table.
e.g.
public virtual ICollection<EquipaModel> Equipas { get; set; }
like you reference your users in your EquipaModel
e.g.
public class EquipaModel
{
...
public virtual ICollection<ApplicationUser> Membros { get; set; }
}
Then your users can have many "Equipas" or teams.

Categories

Resources