I have two viewmodels. One displays employee information and the other displays information about any emergency contacts added to the employee (1-to-Many).
I am managing to display their information separately, but for some reason when I try to combine them in one view things go wrong.
At first I thought the best approach to containing all of that information in one view would be to just create 1 ViewModel and add all of the required fields. But then when I added emergency contact fields which are the "many" part of the relationship, I wasn't sure how to go about iterating through them inside same returned model (1-to-many). Because of that I tried to attempt creating a combined view using Tuple<>. Sadly, this didn't go to well either. Any help greatly appreciated.
Model Class: PersonInfoViewModel
public class PersonInfoViewModel
{
public int PersonId { get; set; }
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Display(Name = "Surname")]
public string LastName { get; set; }
}
Model Class: EmergencyContactViewModel
public class EmergencyContactViewModel
{
public int EmergencyContactId { get; set; }
[Display(Name = "First Name")]
public string EmergencyContactFirstName { get; set; }
[Display(Name = "Surname")]
public string EmergencyContactLastName { get; set; }
}
Model Class: CombinedView
public class CombinedView
{
public Person PersonC { get; set; }
public List<EmergencyContact> EmergencyContactsList { get; set; }
}
Controller Action: CombinedView
public ActionResult CombinedView(int id)
{
var person = _context.People.Find(id);
ViewBag.PersonId = _context.People.Find(id);
if (person != null)
{
List<EmergencyContactViewModel> ec = new List<EmergencyContactViewModel>(id);
PersonInfoViewModel pi = new PersonInfoViewModel();
return View(Tuple.Create(pi, ec));
}
return View();
}
Controller Action: PersonInfo
public async Task<ActionResult> PersonInfoViewModel(int? id)
{
var person = await db.People.FindAsync(id);// pull record from DB by id
if (person != null)
return View(new PersonInfoViewModel()
{
FirstName = person.FirstName,
LastName = person.LastName
});
return View();
}
Controller Action: EmergencyContactViewModel
public ActionResult EmergencyContactViewModel(int? id)
{
List<EmergencyContact> emergecyContactsList = db.EmergencyContacts.ToList();
List<EmergencyContactViewModel> personVmList = emergecyContactsList.Select(x =>
new EmergencyContactViewModel
{
EmergencyContactId = x.EmergencyContactId,
EmergencyContactLastName = x.EmergencyContactLastName,
EmergencyContactFirstName = x.EmergencyContactFirstName,
}).ToList();
return View(personVmList);
}
So yeah, the answer was quite simple. As Stephen has mentioned above, all I had to do was return an instance of CombinedView. In case someone else is stuck like me, this might help you:
public ActionResult CombinedView(int id)
{
var person = _context.People.Find(id);
ViewBag.PersonId = _context.People.Find(id);
if (person != null)
{
return View(new CombinedView()
{
PersonC = person,
EmergencyContactsList = new List<EmergencyContact>(person.EmergencyContacts)
});
}
return View();
}
Also, in the CombinedView:
#model [appname].Models.CombinedView
Additionally, it's worth noting I've tried to do repeat the same steps, but this time with the actual ViewModels as mentioned in the title of this question, but so far have failed.
public ActionResult CombinedView2(int id)
{
var person = _context.People.Find(id);
if (person != null)
{
return View(new CombinedView2()
{
PersonInfo = new PersonInfoViewModel(),
EmergencyContactList = new List<EmergencyContactViewModel>()
});
}
return View();
}
Related
I'm trying to use a ViewModel in my ASP.NET MVC project, but whenever I use it, I get a null reference error for some reason. The latest situation where I have this problem, is here (it works fine when I use the Model itself, but when I use the ViewModel, I get that error):
My Model:
public string FirstName { get; set; }
public string LastName { get; set; }
public string Gender { get; set; }
public string MaritalStatuse { get; set; }
public DateTime DateOfBirth { get; set; }
My ViewModel:
public class PersonFormViewModel
{
public Person Person { get; set; }
public string Title
{
get
{
if (Person != null && Person.Id != 0)
return "Edit";
return "New";
}
}
}
My Controler:
public ActionResult Edit(int id)
{
var person = _context.Persons.FirstOrDefault(p => p.Id == id);
var viewModel = new PersonFormViewModel
{
Person =
{
FirstName = person.FirstName,
LastName = person.LastName,
Gender = person.Gender,
DateOfBirth = person.DateOfBirth,
MaritalStatuse = person.MaritalStatuse
}
};
return View(viewModel);
}
When running this code, the "viewModel" in the Controller is null, even though the "person" is not. Can anyone please help me with this? (I am new to ASP.NET, as you might've guessed).
I think Person needs to be instantiated before assigning values to it.
public ActionResult Edit(int id)
{
var person = _context.Persons.FirstOrDefault(p => p.Id == id);
var viewModel = new PersonFormViewModel
{
Person = new Person
{
FirstName = person.FirstName,
LastName = person.LastName,
Gender = person.Gender,
DateOfBirth = person.DateOfBirth,
MaritalStatuse = person.MaritalStatuse
}
};
return View(viewModel);
}
Trying to add/Edit related data properties of applicationUser so notes can be recorded for users
ApplicationUser.cs
public class ApplicationUser : IdentityUser
{
public virtual ICollection<UserNote> UserNotes { get; set; }
[Required]
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Required]
[Display(Name = "Last Name")]
public string LastName { get; set; }
}
UserNote.cs
public class UserNote
{
[Key]
public int UserNoteId { get; set; }
public string Message { get; set; }
public string ApplicationUserID { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
}
Controller
[HttpPost, ActionName("Edit")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EditPost(string id, ApplicationUser applicationUser)
{
if (ModelState.IsValid)
{
var userFromDb = _db.ApplicationUser
.Include(n => n.UserNotes)
.Include(r => r.UserRoles)
.AsNoTracking().FirstOrDefault(m => m.Id == id);
UserNote note = _db.UserNote.Single(x => x.UserNoteId == 1);
userFromDb.LastName = applicationUser.LastName;
userFromDb.FirstName = applicationUser.FirstName;
//Error accessing related data properties
userFromDb.UserNotes.Message = applicationUser.UserNotes.Message;
await _db.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(applicationUser);
}
I received 'ICollection' does not contain a definition for 'Message' and no accessible extension method 'Message' accepting a first argument of type 'ICollection'
UserNotes is a collection hence you need to access a certain index before getting its Message property.
// Use .Count to check if the list contains any number.
if(applicationUser.UserNotes.Count != 0){
// .FirstOrDefault() will return the first object in that list, if there is none, it would return null.
userFromDb.UserNotes.FirstOrDefault().Message = applicationUser.UserNotes.FirstOrDefault().Message;
}else{
// this is just to let you know if it's empty just in case if you don't debug
return Content("Your collection is empty.");
}
You could also use .IndexOf() or .Where() with your list if you're looking for a specific record.
It's not entirely clear to me with what you're trying, if you're adding a new note or you're editing an existing note. Let me know further in the comments if this doesn't work for you.
Try to edit the related data properties of applicationUser as follows :
[HttpPost, ActionName("Edit")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EditPost(string id, ApplicationUser applicationUser)
{
if (ModelState.IsValid)
{
var userFromDb = _context.ApplicationUser
.Include(n => n.UserNotes)
.AsNoTracking().FirstOrDefault(m => m.Id == id);
//UserNote note = _context.UserNote.Single(x => x.UserNoteId == 1);
userFromDb.LastName = applicationUser.LastName;
userFromDb.FirstName = applicationUser.FirstName;
foreach (var usernote in applicationUser.UserNotes.ToList())
{
if (userFromDb.UserNotes.Any(un => un.UserNoteId == usernote.UserNoteId))
{
userFromDb.UserNotes.Find(un => un.UserNoteId == usernote.UserNoteId).Message = usernote.Message;
}
}
_context.Update(userFromDb);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(applicationUser);
}
Well im doing a application where i have a model like this
public class Saldo
{
public Saldo()
{
Expenses = new List<Expese>();
Incomes = new List<Income>();
}
public int SaldoId { get; set; }
public List<Expense> Despesas { get; set; }
public List<Income> Rendimentos { get; set; }
public string ApplicationUserId { get; set; }
}
what i want to do is add a single expense to the list but it is not working, when i output on the console the count it is always null
in the controller im doing this:
public ActionResult Create([Bind(Include = "ExpenseId,TipoDespesaId,DespesaDescricao,DespesaValor,TipoPagamentoId,Data,Comentario")] Expense expense)
{
var userId = User.Identity.GetUserId();
if (ModelState.IsValid)
{
var balance = db.Balance.Where(d => d.ApplicationUserId == userId).FirstOrDefault();
expense.ApplicationUserId = userId;
if (balance == null)
{
Balance s = new Balance();
s.Expense.Add(expense);
s.ApplicationUserId = userId;
db.Balance.Add(s);
}
else
{
Balance.Expense.Add(expense);
}
db.Expense.Add(expense);
db.SaveChanges();
return RedirectToAction("Index");
}
The expense comes from the form and is passed to the Action
I created a new instance of Balance it worked adding the ApplicationUserId but the expense on the list didnt work, can someone explain me why it happen?
Ps: Sorry for my bad english
Perhaps it's just lost in the translation, but your model doesn't make sense. You have a list of Expense called "Despesas" but in the constructor you call it "Expenses" Whatever that list is called is what you need to add your expense object to. Instead of
s.Expense.Add(expense);
it would be
s.Despesas.Add(expense);
I am looking for selecting a list from my table based on another table. I need to retrieve system names that are part of a particular system family. i have already added foreign keys. I created a ViewModel containing both these classes but it throws a null pointer exception. I am new to MVC and I am not sure where I am wrong.
Model Class : Systems
public class Systems
{
public int SystemsID { get; set; }
public string SystemName { get; set; }
public DateTime CreatedOn { get; set;}
public string CreatedBy { get; set; }
public int SystemFamilyID { get; set; }
public virtual SystemFamily SystemFamily { get; set; }
}
Class SystemFamily
public class SystemFamily
{
public int SystemFamilyID { get; set;}
public int SystemsID {get;set;}
public string FamilyName { get; set; }
public DateTime DateCreated { get; set; }
public string CreatedBy { get; set; }
public virtual ICollection<Systems> Systems { get; set; }
}
ViewSystem is a method in my SystemFamilyController.
public ActionResult ViewSystem(int? id)
{
var viewmodel = new Sys_SysFam();
ViewBag.SystemFamilyID = id.Value;
//if (id != null)
//{
// ViewBag.SystemFamilyID = id.Value;
// viewmodel.Systems = viewmodel.SystemFamily.Where(
// i => i.SystemFamilyID == id.Value).Single().Systems;
//}
return View(viewmodel);
}
the view :
#model SystemFam_System.ViewModel.Sys_SysFam
#{
ViewBag.Title = "ViewSystem";
}
<h2>ViewSystem</h2>
<p>#ViewBag.SystemFamilyID</p>
<table>
#foreach (var item in Model.Systems)
{
string selectedRow = "";
if (item.SystemFamilyID == ViewBag.SystemFamilyID)
{
//{
// selectedRow = "success";
//}
<tr class="#selectedRow">
<td>
#item.SystemName
</td>
<td>
#item.SystemsID
</td>
<td>
#item.SystemFamily
</td>
</tr>
}
}
</table>
I get null pointer Exception. I want to view the system that belongs to a particular family in view system.
Thanks in advance!!
Vini
Edit :
public class Sys_SysFam
{
public IEnumerable<Systems> Systems { get; set; }
public SystemFamily SystemFamily { get; set; }
}
Ok i have checked Sys_SysFam class too. As per your current code it will always throw null reference exception becasue in your controller code you are using:
public ActionResult ViewSystem(int? id)
{
var viewmodel = new Sys_SysFam();
ViewBag.SystemFamilyID = id.Value;
//if (id != null)
//{
// ViewBag.SystemFamilyID = id.Value;
// viewmodel.Systems = viewmodel.SystemFamily.Where(
// i => i.SystemFamilyID == id.Value).Single().Systems;
//}
return View(viewmodel);
}
here you are creating an object of Sys_SysFam as viewmodel and as your if part is commented so you are returning same viewmodel in which viewmodel.Systems will always be null. Here i did not see any request to database for getting the data from db but i think your data in viewmodel will come from database and if i uncomment your if condition then too you are not sending any request to database you are using same viewmodel object created above.
viewmodel.Systems = viewmodel.SystemFamily.Where(
i => i.SystemFamilyID == id.Value).Single().Systems;
in right side you are using viewmodel.SystemFamily with where condition but as viewmodel.SystemFamily is null it will always throw exception. Your solution should be something like this:
public ActionResult ViewSystem(int? id)
{
DataContext context = new DataContext();
var viewmodel = new Sys_SysFam();
ViewBag.SystemFamilyID = id.Value;
if (id != null)
{
ViewBag.SystemFamilyID = id.Value;
var sysFamily = context.SystemFamily.Include(x => x.Systems).FirstOrDefault(x => x.SystemFamilyID == id.Value);
if (sysFamily != null)
{
viewmodel.Systems = sysFamily.Systems;
}
}
return View(viewmodel);
}
here first i am creating object of DataContext which is my main context to access the database using entity framework. so first i will get the system family based on passed id from database and if system family is not null then i will set the data of systems in viewmodel. Include method will bring data for Systems based on system family from database.
Also improve your Sys_SysFam class to initialize systems so that it will not throw exception in your view when there is no data in viewmodel.Systems like this:
public class Sys_SysFam
{
public Sys_SysFam()
{
this.Systems = new List<Systems>();
}
public SystemFamily SystemFamily { get; set; }
public IEnumerable<Systems> Systems { get; set; }
}
Hope this will help you.
Remove SystemsID property from SystemFamily class because it is not used for ICollection virtual property. so your SystemFamily class should be like this:
public class SystemFamily
{
public int SystemFamilyID { get; set;}
public string FamilyName { get; set; }
public DateTime DateCreated { get; set; }
public string CreatedBy { get; set; }
public virtual ICollection<Systems> Systems { get; set; }
}
A friend of mine could find me a way. But it doesnt use any ViewModel. I would like to know how it need to be done with ViewModel as well..
public ActionResult ViewSystem(int? id)
{
var model = from item in db.Systems
orderby item.SystemsID
where item.SystemFamilyID == id
select item;
return View(model);
}
I am using MVC-Viewmodel with repository pattern with EF on my project.
I have 3 tables, Question, CoreValue, SubjectType.
SubjectType and CoreValue are many to many associated with Question and these two tables are not suppose to get any new values, but users can create questions so Question table will get new data when a user creates it. I use two dropdownlists for CoreValue and SubjectType so that the user can choose a CoreValue and a SubjectType when they create a Question.
Here is my HTTPGET controller action:
// GET: /Admin/Create
public ActionResult Create()
{
CoreValueRepository Crep = new CoreValueRepository();
SubjectTypeRepository Srep = new SubjectTypeRepository();
CreateViewModel model = new CreateViewModel();
List<SubjectType> subjectypes = Srep.getall();
List<CoreValue> corevalues = Crep.getall();
model.SubjectTypes = new SelectList(subjectypes, "SID", "Sname");
model.CoreValues = new SelectList(corevalues, "CID", "Cname");
return View(model);
}
And here is my Viewmodel:
public class CreateViewModel
{
public string QuestionText { get; set; }
public string Sname { get; set; }
public string Cname { get; set; }
public SelectList SubjectTypes { get; set; }
public SelectList CoreValues { get; set; }
}
I use Repository for CRUD operations and viewmodels for handling data in UI.
Now I have to code the HTTPPOST Action Create in my controller for inserting Question data to my database, and the questions need to be tagged with CoreValue ID and SubjectType ID. So I was thinkin about to start coding the HTTPOST action Create, and I was wondering if someone could help me out with this.
Thanks in advance!
Best Regards!
This is how i would handle it :
In your ViewModel, replace :
public class CreateViewModel {
public string QuestionText { get; set; }
public string Sname { get; set; }
public string Cname { get; set; }
public int SubjectTypesID { get; set; }
public int CoreValuesID { get; set; }
}
In your HTTPGET put your list in Viewbags :
public ActionResult Create()
{
CoreValueRepository Crep = new CoreValueRepository();
SubjectTypeRepository Srep = new SubjectTypeRepository();
CreateViewModel model = new CreateViewModel();
ViewBag.SubjectTypes = Srep.getall();
ViewBag.CoreValues = Crep.getall();
return View(model);
}
To use the viewbag in your view you can use this :
#Html.DropDownList("SubjectTypesID ", new SelectList(ViewBag.SubjectTypes as System.Collections.IEnumerable, "SID", "Sname", Model.SubjectTypesID ))
#Html.DropDownList("CoreValuesID ", new SelectList(ViewBag.CoreValues as System.Collections.IEnumerable, "CID", "Cname", Model.CoreValuesID ))
Your HTTPOST :
[HTTPOST]
public ActionResult Create(CreateViewModel model)
{
//Now with your model you have the Id of CoreValue and SubjectType
//You could do
if (ModelState.IsValid)
{
QuestionRep.Add(model);
return RedirectToAction("Index");
}
return View(model);
}
Hope this can help you :)
Edit :
in my repository I do :
public void Add(Model.Models.LabExam.Examen entity)
{
using (var context = new PDSIDataContext())
{
var exam = BindModelExamenToRepExamen(entity);
context.Examen.InsertOnSubmit(exam);
context.SubmitChanges();
}
}
Binding methods (Repository.Examen represents my table, Repository is my project where I have a .dbml to represent my DB):
private static Repository.Examen BindModelExamenToRepExamen(Model.Models.LabExam.Examen modelExamen)
{
return new Repository.Examen
{
ID_Examen = modelExamen.ID,
ID_Examen_Type = modelExamen.ID_Examen_Type,
Date_Prescription = modelExamen.Date_Prescription,
Realise_Le = modelExamen.Realise_Le,
Statut = modelExamen.Statut,
Fait = modelExamen.Fait,
ID_Examen_Sous_Type = modelExamen.ID_Examen_Sous_Type,
ID_Examen_Sous_Sous_Type = modelExamen.ID_Examen_Sous_Sous_Type,
ID_Patient = modelExamen.ID_Patient,
Commentaires = modelExamen.Commentaires
};
}