ViewModel save selected value from dropdownlist - c#

I have a dropdownlist - difficult. This is a dropdonwlinst where the user can select a value(easy, hard) but the value is not saved to the database, if I select a value. The strange thing I also have Country list, and that value is saved to the database.And If I put the values by hand in the database - for difficult the values are shown in the view
ModelVIew:
public RouteViewModel()
{
Countries = new List<SelectListItem>();
DifficultGrades = new List<SelectListItem>();
}
public int Id { get; set; }
[Required(ErrorMessage = "You need to give it a name")]
public string Name { get; set; }
public int SelectedValue { get; set; }
public int SelectedId { get; set; }
public IEnumerable<SelectListItem> Countries { get; set; }
public IEnumerable<SelectListItem> DifficultGrades { get; set; }
}
public class Difficult
{
[Key]
public int DifficultId { get; set; }
public string DifficultName { get; set; }
public virtual ICollection<Route> Routes { get; set; }
}
public class Route
{
[Key]
public int routeID { get; set; }
public string Name { get; set; }
public int? UserProfileID { get; set; }
public int? CountryID { get; set; }
public int? DifficultGradeID { get; set; }
public virtual UserProfile userProfile { get; set; }
public virtual Country country { get; set; }
public virtual Difficult difficult { get; set; }
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(RouteViewModel routeViewModel )
{
try
{
if (ModelState.IsValid)
{
var route = new Route();
UpdateRoute(route, routeViewModel);
db.Routes.Add(route);
db.SaveChangesAsync();
return RedirectToAction("Index");
}
}
catch (RetryLimitExceededException /* dex */)
{
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
ViewBag.Id = new SelectList(db.countries, "Id", "country_name", routeViewModel.Id);
ViewBag.DifficultId = new SelectList(db.difficulties, "DifficultId", "DifficultName", routeViewModel.Id);
return View(new RouteViewModel());
}
and the update method:
public void UpdateRoute(Route route, RouteViewModel routeViewModel )
{
route.routeID = routeViewModel.Id;
route.Name = routeViewModel.Name;
route.CountryID = routeViewModel.Id;
route.DifficultGradeID = routeViewModel.Id;
// climb.country.country_name = ModelViewClimb.Name;
}
Thank you

Related

C# MVC context.SaveChanges() do not persist data in database

I´ve tried everything, read several questions here, but my code is still not working, and I can´t figure out what I´m doing wrong. The field 'liberado' in database doesn´t change to '1' after the code runned, and I get no errors. Thanks a lot.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Release(int id)
{
Publicacao publicacao = db.Publicacao.Find(id);
//Publicacao publicacao = db.Publicacao.Where(a => a.idpublicacao == id).First();
if (publicacao == null)
{
return RedirectToAction("Index");
}
db.Publicacao.Attach(publicacao);
db.Entry(publicacao).State = EntityState.Modified;
publicacao.liberado = 1;
db.SaveChanges();
return RedirectToAction("Index");
}
The model
public partial class Publicacao
{
public int idpublicacao { get; set; }
public string titulo { get; set; }
public string texto { get; set; }
public string imagem { get; set; }
public System.DateTime data { get; set; }
public int categoria { get; set; }
public byte[] arqimagem { get; set; }
public string descimagem { get; set; }
public Nullable<int> usuario { get; set; }
public int liberado { get; set; }
public virtual categoria categoria1 { get; set; }
public virtual Users Users { get; set; }
}

Need to compare value from other table

I have 3 classes in my model
Model
public class Student
{
public int id { get; set; }
[Required]
[DisplayName("Student Name")]
public string Name { get; set; }
[Required]
public int RollNO { get; set; }
public DateTime EnrollmentDate { get; set; }
public ICollection<Record> Records { get; set; }
}
public class Record
{
public int Id { get; set; }
public int StudentId { get; set; }
public int SubjectId { get; set; }
[Required]
public int Marks { get; set; }
public string Result { get; set; }
public virtual Student Students { get; set; }
public virtual Subject Subjects { get; set; }
}
public class Subject
{
public int id { get; set; }
[Required]
public string Title { get; set; }
[Required]
[DisplayName("Minimum Marks")]
public int MinMarks { get; set; }
[Required]
[DisplayName("Max Marks")]
public int MaxMarks { get; set; }
public ICollection<Record> Records { get; set; }
}
In subject table i will be creating each subject and setting its minimum and maximum marks required to pass...now in record table (Create Page) i want to compare the selected subject minimum marks with Record.Marks and if its less the minimum marks get Fail in Record.Result and if its greater then maximum marks get Pass in Record.Result...and i also want to compare the Result.Marks property with Subject.MaxMarks and if its greater then Subject.MaxMarks the user should get error in any form possible...
this is my controller
Controller
public ActionResult Create([Bind(Include = "Id,StudentId,SubjectId,Marks,Result")] Record record,Subject subject)
{
var selectedSubject = db.Subjects.Where(sub => subject.id == record.SubjectId).FirstOrDefault();
if (record.Marks < selectedSubject.MinMarks)
{
record.Result = "Fail";
}
else
record.Result = "Pass";
if (ModelState.IsValid)
{
db.Records.Add(record);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.StudentId = new SelectList(db.Students, "id", "Name", record.StudentId);
ViewBag.SubjectId = new SelectList(db.Subjects, "id", "Title", record.SubjectId);
return View(record);
}
Assuming your view has the input element to select/enter the subject id and the element's name attribute value is SubjectId and it is inside the form
Just add an else if to check max mark as well. You do not need the second parameter in your action method. Just remove it.
var selectedSubject = db.Subjects.FirstOrDefault(a=> a.id == record.SubjectId);
if(selectedSubject!=null)
{
if (record.Marks < selectedSubject.MinMarks)
{
record.Result = "Fail";
}
else if (record.Marks > selectedSubject.MaxMarks)
{
record.Result = "Error";
}
else
{
record.Result = "Pass";
}
}
else
{
ModelState.AddModeError(string.empty,"Subject not found");
}
//to do : Reload dropdown data and return the view

How do I post a one-to-many relationship?

Pretty new to ASP.NET and programming. I have two models, two API controllers, two repositories. How do I post the data to the second model while attaching it to the first (I'm guessing by ID.) Do I possibly need a View Model? Also reading a little about unit of work. Maybe neither are necessary? Below is some code. Thanks!
Record.cs
namespace Train.Models {
public class Record {
public int Id { get; set; }
public int Quantity { get; set; }
public DateTime DateCreated { get; set; }
public bool IsActive { get; set; }
public string UserId { get; set; }
public virtual ICollection<Cars> Cars { get; set; }
}
}
Cars.cs
namespace Train.Models {
public class Cars {
public int Id { get; set; }
public string EmptyOrLoaded { get; set; }
public string CarType { get; set; }
//Hopper, flatbed, tank, gondola, etc.
public string ShippedBy { get; set; }
//UP(Union Pacific) or BNSF
public string RailcarNumber { get; set; }
//public virtual ApplicationUser ApplicationUser { get; set; }
public string UserId { get; set; }
public string RecordId { get; set; }
public virtual Record Record { get; set; }
}
}
Record Repository
public void SaveRecord(Record recordToSave) {
if (recordToSave.Id == 0) {
recordToSave.DateCreated = DateTime.Now;
_db.Record.Add(recordToSave);
_db.SaveChanges();
} else {
var original = this._db.Record.Find(recordToSave.Id);
original.Quantity = recordToSave.Quantity;
original.IsActive = true;
_db.SaveChanges();
}
}
EFRepository (Cars)
public void SaveCar(Cars carToSave) {
if (carToSave.Id == 0) {
_db.Cars.Add(carToSave);
_db.SaveChanges();
} else {
var original = this.Find(carToSave.Id);
original.EmptyOrLoaded = carToSave.EmptyOrLoaded;
original.CarType = carToSave.CarType;
original.ShippedBy = carToSave.ShippedBy;
original.RailcarNumber = carToSave.RailcarNumber;
_db.SaveChanges();
}
}

Form is not binding to correct object

I have similar objects (I'm using Model and ViewModels, where ViewModels has same properties as Model object).
When I'm editing one item, I put editors for viewmodel, and the controller that handles the update/edit, he receives the ViewModel:
[HttpPost]
public ActionResult Edit(DocumentViewModel model) {
Mapper.CreateMap < DocumentViewModel, BE.Document > ();
BE.Document instanceOfDestination = Mapper.Map < BE.Document > (model);
Container < BE.Document > container = BL.DocumentBL.UpdateDocument(instanceOfDestination);
if (!container.HasErrors) {
SetInfo("Saved!");
} else {
SetError(container.ErrorMessage);
}
return RedirectToAction("Index");
}
The problem is that this method is never reached because model binder constructs BE.Document instead of DocumentViewModel.
Here are the values sent by browser:
__RequestVerificationToken:xxx-dontcare
id:36
name:test flash files
documentType.id:5
unit.id:2
reference:FLASH0016
isActive:true
isActive:false
recyclingSpan:1
selectedTopics:1
selectedTopics:2
trainer.id:615952
selectedInstallations:1
selectedInstallations:2
selectedProfessions:3
selectedProfessions:4
selectedProfessions:6
Here is the Controller that return VM to make the edit page:
[HttpGet]
public ActionResult Edit(int id) {
var container = BL.DocumentBL.GetAllDocument(new BE.Document() {
id = id
});
if (!container.HasErrors) {
Mapper.CreateMap < BE.Document, DocumentViewModel > ();
DocumentViewModel instanceOfDestination = Mapper.Map < DocumentViewModel > (container.Value);
// fill values for dropdowns and co
instanceOfDestination.FillPredefinedValuesForUser(GetAdminOrVisibilityUnits());
return View(instanceOfDestination);
} else {
SetError(container.ErrorMessage);
return RedirectToAction("Index");
}
}
And there are model and viewmodels for document:
DocumentViewModel:
public int id { get; set; }
[Required]
public string name { get; set; }
[Required]
public string reference { get; set; }
[Required]
[Range(0, 100)]
public int recyclingSpan { get; set; }
[Required]
public bool isActive { get; set; }
[DocumentTypeValidator("DocType is required")] // custom validator
public DocumentType documentType { get; set; }
public PersonnelAM trainer { get; set; }
public List<DocumentVersion> versions { get; set; }
public List<Installation> installations { get; set; }
public List<Profession> professions { get; set; }
public List<Topic> topics { get; set; }
public Unit unit { get; set; }
// not used for edit or create
public PersonnelAM createdBy { get; set; }
public DateTime createdOn { get; set; }
public PersonnelAM editedBy { get; set; }
public DateTime editedOn { get; set; }
// to fill dropdowns
public IEnumerable<SelectListItem> documentTypeSelect { get; set; }
public IEnumerable<SelectListItem> personnelSelect { get; set; }
public IEnumerable<SelectListItem> installationsSelect { get; set; }
public IEnumerable<SelectListItem> professionsSelect { get; set; }
public IEnumerable<SelectListItem> topicTypeSelect { get; set; }
public IEnumerable<SelectListItem> unitSelect { get; set; }
// for multi-selects - uses FillListsFromIds to fill Lists from Ids
public int[] selectedProfessions { get; set; }
public int[] selectedInstallations { get; set; }
public int[] selectedTopics { get; set; }
// For file upload
[MinLengthAttribute(1)]
public HttpPostedFileBase[] files { get; set; }
// for file get
public List<string> filesList { get; set; }
BE.Document
public int id { get; set; }
public string name { get; set; }
public string reference { get; set; }
public int recyclingSpan { get; set; }
public bool isActive { get; set; }
public DocumentType documentType { get; set; }
public PersonnelAM trainer { get; set; }
public List<string> filesList { get; set; }
public List<Installation> installations { get; set; }
public List<DocumentVersion> versions { get; set; }
public List<Profession> professions { get; set; }
public List<Topic> topics { get; set; }
public Unit unit { get; set; }
public PersonnelAM createdBy { get; set; }
public DateTime createdOn { get; set; }
public PersonnelAM editedBy { get; set; }
public DateTime editedOn { get; set; }
Thanks to help me :-)
EDIT :
Here is the full Get/id Controller
[HttpGet]
public ActionResult Edit(int id)
{
if (User.IsInRole("Admin") || User.IsInRole("Moderator") || SessionManager.matricule.IsDocumentCreator(id))
{
var container = BL.DocumentBL.GetAllDocument(new BE.Document() { id = id });
if (!container.HasErrors)
{
Mapper.CreateMap<BE.Document, DocumentViewModel>();
DocumentViewModel instanceOfDestination = Mapper.Map<DocumentViewModel>(container.Value);
// fill values for dropdowns and co
instanceOfDestination.FillPredefinedValuesForUser(GetAdminOrVisibilityUnits());
return View(instanceOfDestination);
}
else
{
SetError(container.ErrorMessage);
return RedirectToAction("Index");
}
}
else
{
SetError("Vous n'avez pas le droit d'accéder à l'édition de ce document.");
return RedirectToAction("Index");
}
}
EDIT 2:
[HttpPost]
public ActionResult Edit(DocumentViewModel model)
{
if (User.IsInRole("Admin") || User.IsInRole("Moderator") || SessionManager.matricule.IsDocumentCreator(model.id))
{
Mapper.CreateMap<DocumentViewModel, BE.Document>();
BE.Document instanceOfDestination = Mapper.Map<BE.Document>(model);
Container<BE.Document> container = BL.DocumentBL.UpdateDocument(instanceOfDestination, new PersonnelAM() { id = SessionManager.matricule });
if (!container.HasErrors)
{
SetInfo("Modifications suavegardées");
}
else
{
model.FillPredefinedValuesForUser(GetAdminOrVisibilityUnits());
SetError(container.ErrorMessage);
return View(instanceOfDestination);
}
}
return RedirectToAction("Index");
}
Your view model is binding correctly, but in your POST method, this line of code
return View(instanceOfDestination);
is returning an instance of Document (as defined by BE.Document instanceOfDestination = Mapper.Map<BE.Document>(model);, not an instance of DocumentViewModel which is resulting in an exception
The model passed in the dictionary is of type BE.Document but this dictionary requires a model of type DocumentViewModel
Change it to
return View(model);
so that the correct type is passed back to the view.
Please make sure you bind the viewmodel to your view (your cshtml file), not your model, on top of your View file (for instance edit.cshtml) :
#model your.namespace.DocumentViewModel
instead of
#model your.namespace.BE.Document
But, why you use viewmodel if the viewmodel is identical to your model? why not just use your model instead

Binding data of Domain model type to ViewModel type

I'm having a hard time trying to figure out how to bind data from the database to ViewModel. Basically, I have a domain model which I find has too much properties and which I'd like to reduce so logically I've chosen ViewModel to do so.
Domain model (automatically created from the database):
public partial class Ticket
{
public Ticket()
{
this.Daily = new HashSet<Daily>();
this.Ticket1 = new HashSet<Ticket>();
}
public int idTicket { get; set; }
public Nullable<int> idNadredeniTicket { get; set; }
public short RedniBroj { get; set; }
public int idFirma { get; set; }
public Nullable<int> idKontakt { get; set; }
public Nullable<int> idManager { get; set; }
public string Tip { get; set; }
public string Status { get; set; }
public Nullable<System.DateTime> DatumPrijave { get; set; }
public string VrstaPrijave { get; set; }
public string Prioritet { get; set; }
public Nullable<System.DateTime> DatumDo { get; set; }
public string Opis { get; set; }
public string Biljeske { get; set; }
public Nullable<bool> Zatvoren { get; set; }
public Nullable<bool> IzdanRacun { get; set; }
public Nullable<System.DateTime> DatumZatvaranja { get; set; }
public Nullable<int> idAsset { get; set; }
public virtual ICollection<Daily> Daily { get; set; }
public virtual Firma Firma { get; set; }
public virtual Kontakt Kontakt { get; set; }
public virtual Kontakt Kontakt1 { get; set; }
public virtual ICollection<Ticket> Ticket1 { get; set; }
public virtual Ticket Ticket2 { get; set; }
}
ViewModel:
public class OpenTickets
{
public int idTicket { get; set; }
public Nullable<int> idNadredeniTicket { get; set; }
public short RedniBroj { get; set; }
public int idFirma { get; set; }
public Nullable<int> idKontakt { get; set; }
public Nullable<int> idManager { get; set; }
public string Tip { get; set; }
public string Status { get; set; }
public Nullable<System.DateTime> DatumPrijave { get; set; }
public string VrstaPrijave { get; set; }
public string Prioritet { get; set; }
public string Opis { get; set; }
public string Biljeske { get; set; }
public string BrojTicketa
{
get
{
return idNadredeniTicket.ToString() + "-" + RedniBroj.ToString();
}
}
public string NazivTicketa
{
get
{
return BrojTicketa + " - " + Opis;
}
}
public string DetaljiTicketa
{
get
{
return Opis + "\r\n" + Biljeske;
}
}
}
What I'd like to accomplish is to bind data from the database via query to the ViewModel but, understandingly, I get errors regarding different types of objects passed to the View. I'm posting controller and view for the reference.
Controller
public ActionResult OpenTickets()
{
var openTickets = db.Ticket
.Where(t => t.idFirma == 1)
.Where(t => t.Zatvoren == false);
return View(openTickets.ToList());
}
View (some code is intentionally ommited for brevity)
#model IEnumerable<IDE3_CRM.ViewModels.OpenTickets>
<table>
#foreach (var item in Model)
{
<tr>
<td>#Html.DisplayFor(modelItem => item.Biljeske)</td>
<td>#Html.DisplayFor(modelItem => item.Opis)</td>
</tr>
}
</table>
I recommend wrapping your db calls in a Repository. In here, you can transform your database objects into view models. For example:
public ActionResult OpenTickets()
{
var openTickets = ticketRepo.GetOpenTickets();
return View(openTickets);
}
// Implementation of ITicketRepo
public IEnumerable<OpenTickets> GetOpenTickets()
{
return db.Ticket
.Where(t => t.idFirma == 1 && t.Zatvoren == false)
.Select(do => new OpenTickets
{
// Fill in view model properties from database object
});
}
Hrvach,
You can limit the data fields in the view itself and I think that maybe more efficient. That being said here is another approach you can take:
Create a list of type OpenTickets
Select the tickets you want
Loop over the selected tickets and add a new openTicket with the
properites you want to keep to the list of openTickets
return the list of open tickets
public ActionResult OpenTickets()
{
List<OpenTickets> openTicketList = new List<OpenTickets>();//create a list of openTickets
var Tickets = db.Ticket//select the tickets that you want
.Where(t => t.idFirma == 1)
.Where(t => t.Zatvoren == false);
foreach (var ticket in Tickets)//Loop over the tickets and create an openTicket out of each ticket then add the openTick to the openTicketList
{
OpenTickets openTicket = new OpenTickets();//create new OpenTickets object
openTicket.propery1 = ticket.propery1;//set each property of the openTicket equal to the property of the Ticket that you want to keep
openTicket.propery2 = ticket.propery2;
openTicket.propery3 = ticket.propery3;
openTicket.propery4 = ticket.propery4;
openTicketList.Add(openTicket);//add new OpenTickets object to the list
}
return View(openTicketList);
}
I hope this helps...Best wishes
Bill

Categories