How to save changes of courses in EmployeeCourse table - asp.net-mvc

What i Need
I need to save changes in courses in EmployeeCourse table
by remove all course for employee from EmployeeCourse table
then add courses after changes
Problem
when add changes in courses after remove i get error in save changes() function
{"An error occurred while updating the entries.
The INSERT statement conflicted with the FOREIGN KEY constraint
\"FK_EmployeeCourse_Course\". The conflict occurred in database \"mycourse\",
table \"dbo.Course\", column 'Id'.\r\nThe statement has been terminated."}
under submit button edit [httppost]
public ActionResult Edit(EditEmployeeVm model)
{
var emp = db.Employees.FirstOrDefault(f => f.Id == model.Id);
// remove all courses
foreach (EmployeeCourse eec in emp.EmployeeCourses.ToList())
{
var ec = db.EmployeeCourses.Find(eec.Id);
db.EmployeeCourses.Remove(ec);
}
// add courses again
foreach (var couseid in model.CourseIds)
{
db.EmployeeCourses.Add(new EmployeeCourse { CourseId = couseid, EmployeeId = emp.Id });
}
db.SaveChanges();
}
Debug result
debug add as image below
Details
Relation between two tables one to many
EmployeeCourse
Id(primary key) CourseId(forign key) EmployeeId(forign key)
Course table in database
Id(pk) CourseName
I using following view model for edit to get CourseIds
#model StudentCourses.Models.EditEmployeeVm
$(function () {
$(document).on("click", ".remove", function (e) {
e.preventDefault();
$(this).closest(".course-item").remove();
});
$('#AvailableCourses').change(function () {
var val = $(this).val();
var text = $("#AvailableCourses option:selected").text();
var existingCourses = $("input[name='CourseIds']")
.map(function () { return this.value; }).get();
if (existingCourses.indexOf(val) === -1) {
var newItem = $("<div/>").addClass("course-item")
.append(text + ' Remove ');
newItem.append('<input type="text" name="CourseIds" value="' + val + '" />');
$("#items").append(newItem);
}
});
});
</script>
to retrieve courses from database in edit view i used code below
<div>
#using (Html.BeginForm())
{
#Html.HiddenFor(g => g.Id)
#Html.LabelFor(f => f.Name)
#Html.DropDownList("AvailableCourses", Model.Courses, "Select")
<h4>Existing courses</h4>
<div id="items"></div>
foreach (var c in Model.ExistingCourses)
{
<div class="course-item">
#c.Name Remove
<input type="text" name="CourseIds" value="#c.Id" />
</div>
}
}
</div>
model used for that as following
public class EditEmployeeVm
{
public int Id { set; get; }
public List<SelectListItem> Courses { get; set; }
public int[] CourseIds { set; get; }
public List<CourseVm> ExistingCourses { set; get; }
}
public class CourseVm
{
public int Id { set; get; }
public string Name { set; get; }
}
}
update
public ActionResult Edit(int id)
{
var vm = new EditEmployeeVm { Id = id };
var emp = db.Employees.FirstOrDefault(f => f.Id == id);
vm.Name = emp.Name;
vm.ExistingCourses = db.EmployeeCourses
.Where(g => g.EmployeeId == id)
.Select(f => new CourseVm
{
Id = f.Id,
Name = f.Course.CourseName
}).ToList();
vm.CourseIds = vm.ExistingCourses.Select(g => g.Id).ToArray();
vm.Courses = db.Courses.Select(f => new SelectListItem
{
Value = f.Id.ToString(),
Text = f.CourseName
}).ToList();
return View(vm);
}

In your EDIT Get action, You are using the wrong id for CourseVm. It should be the Course Id, but you are setting the EmployeeCourse record/entity Id.
This should fix it.
vm.ExistingCourses = db.EmployeeCourses.Where(g => g.EmployeeId == id)
.Select(f => new CourseVm
{
Id = f.Course.Id,
Name = f.Course.CourseName
}).ToList();

Related

Multiple Checkbox with Model returns null

after I read data from my database, I try to show those datas in Html.Helper checkbox and I do that. But later when I try to get checked values back to the controller, model always returns null. Here's my controller part:
[HttpGet]
public ActionResult NewClient()
{
HizmetModel hizmetModel = new HizmetModel();
hizmetModel.hizmet = db.Hizmet.ToList<Hizmet>();
return View(hizmetModel);
}
[HttpPost]
public ActionResult NewClientPost(string name, string lastname, string telephone, string plate, HizmetModel hizmet)
{
Musteri musteri = new Musteri();
if (!db.Musteri.Where(x => x.plaka == plate).Any())
{
musteri.isim = name;
musteri.soyisim = lastname;
musteri.telefon = telephone;
musteri.plaka = plate;
db.Musteri.Add(musteri);
db.SaveChanges();
}
Islem islem = new Islem();
IslemHizmet islemhizmet = new IslemHizmet();
islem.giristarihi = DateTime.Now;
islem.plaka = plate;
var selectedHizmet = hizmet.hizmet.Where(x => x.isChecked == true).ToList<Hizmet>();
db.Islem.Add(islem);
db.SaveChanges();
var onprocessplate = db.Islem.Where(x => x.plaka == plate).FirstOrDefault();
foreach (var item in selectedHizmet)
{
islemhizmet.islem_id = onprocessplate.islem_id;
islemhizmet.hizmet_id = item.hizmet_id;
db.IslemHizmet.Add(islemhizmet);
db.SaveChanges();
islemhizmet = new IslemHizmet();
}
TempData["Success"] = "Müşteri başarıyla eklendi...";
return RedirectToAction("CurrentClients", "Admin");
}
This is my model for the list:
public class HizmetModel
{
public List<Hizmet> hizmet { get; set; }
}
I use this model in the cshtml file:
#model otoyikama.Models.Model.HizmetModel
And this is the loop for displaying checkboxes
#for (int i = 0; i < Model.hizmet.Count; i++)
{
<li>
<label>#Model.hizmet[i].hizmetisim</label>
#Html.CheckBoxFor(m => m.hizmet[i].isChecked)
#Html.HiddenFor(m => m.hizmet[i].hizmet_id)
#Html.HiddenFor(m => m.hizmet[i].hizmetisim)
</li>
}
I couldn't figure what's the problem here, my get action works fine, I can see all the data from database but I can't pass them back to controller.
As a first think , u need to create a object in your controller parameters such as like List<int> serviceIDs or List<Service> services so you can keep more data than one.
The html part:
#foreach(item in Model.Service)
{
<label>#item.ServiceName</label><br>
<input type="checkbox" name="services" value="#item.ServiceID">
<input type="hidden" name="services" value="#item.ServiceName">
}
The backend part:
[HttpPost]
public ActionResult NewClientPost(string name, string lastname, string telephone, string plate, List<Service> services)
{
}
when u do in that way, u will able to hold more services than to one and i think u can pass them the controller more easly.
when i face with that stuation, im taking those services ID's and calling them on the controller side like bellow;
The html part:
#foreach(item in Model.Service)
{
<label>#item.ServiceName</label><br>
<input type="checkbox" name="serviceIDs" value="#item.ServiceID">
}
The backend part:
[HttpPost]
public ActionResult NewClientPost(string name, string lastname, string telephone, string plate, List<int> serviceIDs)
{
List<Service> services= new List<Service>();
foreach(var item in serviceIDs)
{
var service=db.Service.Where(x => x.ServiceID == item).Any()
if(service.Count!=0)
{
services.Add(service);
}
}
}

Placeholder on a #Html.Dropdownlist that is not selectable

How do i put a placeholder on my #Html.Dropdownlist that is not selectable.
I implemented chosen-jquery on my dropdown.
My code is as per below:
#Html.DropDownList("Id", new SelectList(new Ahib.Membership.UserFacade().GetAllUsers(), "Id", "Username"), "-select a system owner-", new { #class="chosen1-select" })
Currently my dropdownlist has a placeholder but the "-select a system owner-" becomes a selectable value which i dont want. How do solve this issue?
You can convert your list to the selectitem list and apply your disabled attribute from the controller itself.
like this
assuming your model is like this
class user
{
public int Id { get; set; }
public string Username { get; set; }
}
Convert your list to List<SelectListItem> like this, note here I am disabling the select a system owner entry.
public ActionResult Index()
{
List<user> users = new List<user>();
users.Add(new user { Id = 1, Username = "test1" });
users.Add(new user { Id = 2, Username = "test2" });
List<SelectListItem> list = new List<SelectListItem>();
list.Add(new SelectListItem { Text = "-select a system owner-", Value = "0", Disabled = true });
foreach (var item in users)
{
list.Add(new SelectListItem
{
Text = item.Username,
Value = item.Id.ToString()
});
}
ViewBag.listItems = list;
return View();
}
and in view use it like this
#Html.DropDownList("test", ViewBag.listItems as IEnumerable<SelectListItem>);
Result:

How to populate dropdown list for specific user?

I have three dropdown list:
#Html.DropDownListFor(m => m.Edit.SelectCountryId, Model.Edit.Countries, "Please select", new { id = "CountryID", #class = "form-control", #onchange = "LoadRegions();" })
#Html.DropDownListFor(m => m.Edit.SelectRegionId,Model.Edit.Region, "Please select", new { id = "RegionID", #class = "form-control", #onchange = "LoadCities();" })
#Html.DropDownListFor(m => m.Edit.SelectCityId, Model.Edit.City, "Please select", new { id = "CityID", #class = "form-control" })
I populate second one depending on first one and third depending on second...but when i want to display those dropdown lists for some specific user im able to display just countries
My model:
public int SelectCountryId { get; set; }
public int SelectRegionId { get; set; }
public int SelectCityId {get; set;}
public System.Web.Mvc.SelectList City { get; set; }
public System.Web.Mvc.SelectList Region{ get; set; }
public System.Web.Mvc.SelectList Country{ get; set; }
My controller:
model.Edit.SelectCountryId = user.ContactInformation.First().City.Region.Country.Id;
model.Edit.SelectRegionId = user.ContactInformation.First().City.Region.Id;
model.Edit.SelectCityId = user.ContactInformation.First().City.Id;
I get values on controller but i cant get display them in view
EDIT:
My scripts:
var region = $('#RegionID');
var urlCountries = "/Account/GetRegions";
$.getJSON(urlCountries, { countryId: $('#CountryID').val() }, function (response) {
// clear and add default (null) option
region.empty().append($('<option></option>').val('').text('Please select'));
for (var i = 0; i < response.length; i++) {
region.append($('<option></option>').val(response[i].Id).text(response[i].Name));
}
});
var city = $('#CityID');
var url = "/Account/GetCities"; // use the helper (dont hard code)
$.getJSON(url, { regionId: $('#RegionID').val() }, function (response) {
// clear and add default (null) option
city.empty().append($('<option></option>').val('').text('Please select'));
for (var i = 0; i < response.length; i++) {
city.append($('<option></option>').val(response[i].Id).text(response[i].Name));
}
});
My methods for GetCity() and GetRegions()
public IEnumerable<IRegion> GetRegions(int countryId)
{
Model.Administration.Region[] modelRegions = Model.Administration.Region.FindAll(DetachedCriteria.For<Model.Administration.Region>().Add(Restrictions.Eq("Country.Id", countryId)));
return modelRegions.Select(Region.ConvertFromModel).Cast<IRegion>().ToList();
}
public IEnumerable<ICity> GetCities(int regionId)
{
CityLimited[] modelCities = CityLimited.FindAll(DetachedCriteria.For<CityLimited>().Add(Restrictions.Eq("Region.Id", regionId)));
return modelCities.Select(City.ConvertFromModel).Cast<ICity>().ToList();
}
You need to pass an additional value indicating the selected option in the json data your returning to the view. Your GetRegions() method should look like
public JsonResult GetRegions(int countryId) // return a JsonResult
{
Model.Administration.Region[] modelRegions = Model.Administration.Region.FindAll(DetachedCriteria.For<Model.Administration.Region>().Add(Restrictions.Eq("Country.Id", countryId)));
var options = modelRegions.Select(Region.ConvertFromModel).Cast<IRegion>().ToList();
var selection = 1; // set the value of the selected option here - must match the `ID` property of one of one of the `IRegion` your returning
return Json(new { options = options, selection = selection }, JsonRequestBehavior.AllowGet);
}
Side note: Its not clear what modelRegions.Select(Region.ConvertFromModel).Cast<IRegion>().ToList(); returns but if IRegion contains more that just the ID and Name properties you need for the view, consider creating a collection of anonymous objects so you don't send unnecessary data across the wire
Then the corresponding script should be
var url = '#Url.Action("GetRegions", "Account")'; // use the helper (dont hard code)
var regions = $('#RegionID'); // cache the element
$('#CountryID').change(function() {
$.getJSON(url, { id: $(this).val() }, function(response) {
// clear and add default (null) option
regions.empty().append($('<option></option>').val('').text('Please select'));
$.each(response.options, function(index, item) {
cities.append($('<option></option>').val(item.Value).text(item.Text));
});
regions.val(response.selection); // set the selected value
});
});
and remove the #onchange = "LoadRegions(); from you markup
Ditto for the GetCities() controller method and the corresponding script

Understanding how strongly typed html helper works

Framework: ASP.NET MVC 3
Tools: VS 2012
Hi guys,
I'm new to ASP.NET mvc, I have been using strongly typed html helper for some time,I don't understand them completely but know that it can provide type checking and keeps name according to property name,after using it for many times I faced this error constantly and dont seem to have any hint why its occuring tried several google searches but none helped me.
Error:
The name 'm' does not exist in the current context
Code:
#Html.LabelFor(m => m.OrginalCont.Title)
But this line of code works perfectly fine.
#Html.TextBox("origTitle", Model.OrginalCont.Title, new { #readonly = "", #class = "text-rounded", style = "width:425px" })
Can someone tell me whats going on here.I have used the same m => m.Name syntax several times in view but they are all working fine.
Update:
Alright I will try to post more code,but as the code may get too long I will try to keep it short and will post code which is related to the problem.
View
#model TS.MOP.Interface.Models.ProjectTranslationModel
<div class="form-item">
#Html.LabelFor(model => model.OrginalCont.Title)
<div class="editor-field">
#Html.TextBox("origTitle", Model.OrginalCont.Title, new { #readonly = "", #class = "text-rounded", style = "width:425px" })
</div>
</div>
Model
public class ProjectTranslationModel
{
public int ProjectId { get; set; }
[Required(ErrorMessageResourceType = typeof(Names), ErrorMessageResourceName = "Required_ErrorMessage")]
[DataType(DataType.Text)]
[Display(ResourceType = typeof(Names), Description = "TranslateLangs_Description", Name = "TranslateLangs_Title")]
public List<SelectListItem> TranslatableLangSelect { get; set; }
public TranslatableLanguageEditor TranslatableLangEditor { get; set; }
public OriginalContent OrginalCont { get; set; }
}
Controller
[Authorize]
public ActionResult TranslationEdit(int? id)
{
if (id.HasValue && User.IsInRole("ContentTranslator"))
{
var model = new ProjectTranslationModel();
model.ProjectId = id.Value;
var ContentTypeId = 2;//Project Page
Guid _currentUserId = Guid.Parse(Membership.GetUser(User.Identity.Name).ProviderUserKey.ToString());
var translatorSettings = db.TranslatorSettings.Where(x => x.UserId == _currentUserId).ToList();
model.TranslatableLangEditor = new TranslatableLanguageEditor();
var list = new List<SelectListItem>();
//Original Text
var originalContent = db.Projects.Where(x => x.Id == id.Value)
.Select(d => new OriginalContent { Title = d.Title, Content = d.Description, ContentCultureId = d.ProjectType.ContentCultureId }).FirstOrDefault();
model.OrginalCont = originalContent;
foreach (var item in translatorSettings)
{
//Select List
var li = new SelectListItem();
if (item.ContentCultureId != originalContent.ContentCultureId)//Dont add the Original Content CultureId to the dropDown
{
li.Value = item.ContentCultureId.ToString();
li.Text = item.ContentCulture.Description;
list.Add(li);
}
}
model.TranslatableLangSelect = list;
return View(model);
}
else
{
return View("Index");
}
}

MVC checkboxes & FormCollection

On a mass-edit form page I display about 50 objects that have some boolean properties as well. The controller receives a FormCollection with all values from the edit page.
public void _EditAll(FormCollection c)
{
int i = 0;
if (ModelState.IsValid)
{
var arrId = c.GetValues("channel.ID");
var arrName = c.GetValues("channel.displayedName");
var arrCheckbox = c.GetValues("channel.isActive");
for (i = 0; i < arrId.Count(); i++)
{
Channel chan = db.Channels.Find(Convert.ToInt32(arrId[i]));
chan.displayedName = arrName[i];
chan.isActive = Convert.ToBoolean(arrCheckbox[i]);
db.Entry(chan).State = EntityState.Modified;
}
db.SaveChanges();
}
}
Now, for checkboxes, MVC creates hidden inputs on the form (otherwise "false" could not be posted back). In the controller, when receiving the FormCollection, this leads to the case that I receive an array of say
50 IDs,
50 names and ..
71 or so values for the checkboxes,
since the hidden checkbox has the same name as the visible one.
What's a good way to handle that and get the proper value of the checkbox?
Sample for editing array of entities that have boolean field.
Entity:
public class Entity
{
public int Id { get; set; }
public bool State { get; set; }
}
Controller:
public ActionResult Index()
{
Entity[] model = new Entity[]
{
new Entity() {Id = 1, State = true},
new Entity() {Id = 2, State = false},
new Entity() {Id = 3, State = true}
};
return View(model);
}
[HttpPost]
public ActionResult Index(Entity[] entities)
{
// here you can see populated model
throw new NotImplementedException();
}
View:
#model Entity[]
#{
using (Html.BeginForm())
{
for (int i = 0; i < Model.Count(); i++ )
{
#Html.Hidden("entities[" + i + "].Id", Model[i].Id)
#Html.CheckBox("entities[" + i + "].State", Model[i].State)
}
<input type="submit"/>
}
}
The only tricky thing is html elements naming.
More info about binding arrays.
I'm converting all arrays containing checkbox-values:
"false" => "false", if not preceded by "true"

Resources