I just want to get some clarity about link table for a many-to-many relationship in a ASP.NET MVC project. When the Controller and the Views are created, it seems like there are not any code for read and write to the link table!? The only thing that is autogenrated is the table OrderEmployee.
If I have understood it right, for each order I create, I also need to add the ID of the Employee who handled it in the OrderEmployee table? And when I want to list the Oders and want to know each Employee who handled that Order, I need to read from the OrderEmployee table? I can't find any tutorials about how to read and write to and from a link table.
Do I have to add this read and write code on my own in the controller? Preciate if I can get some clarity about this!
public class Order
{
public int ID { get; set; }
public string Name { get; set; }
public int? ManufacturerID { get; set; }
public virtual Manufacturer Manufacturer { get; set; }
public virtual ICollection<Employee> Employees { get; set; }
}
public class Employee
{
public int ID { get; set; }
public string Name { get; set; }
public int EmployeeNumber { get; set; }
public virtual ICollection<Timeunit> Timeunits { get; set; }
public virtual ICollection<Order> Orders { get; set; }
}
For reading and writing in a many to many relationship is not really difficult but hard to get it right in the beginning.
You don't have to add anything in your models, they are right.
Writing
I'll show you with an example of how to add a single order to an employee with a dropdown list. The concept for add multiple orders to employees is nearly the same, you'll find a link at the bottom with a tutorial.
First of all you should create view models like this :
public class CreateEmployeeViewModel
{
public int ID { get; set; }
public string Name { get; set; }
public int EmployeeNumber { get; set; }
public int SelectedOrderID { get; set; }
public SelectList OrdersList { get; set; }
}
Then in your EmployeesControler :
// GET: Employees/Create
public ActionResult Create()
{
/* Add this */
CreateEmployeeViewModel model = new CreateEmployeeViewModel();
model.OrdersList = new SelectList(db.Orders.ToList(), "ID", "Name");
return View(model);
}
The first parameter will be the list of objects in which you want to select something (an Order in this case). The second parameter is the name of the propertie of your Order you want to pass to the view model (as SelectOrderID) and finally the third parameter is the value you want to display in the dropdownlist.
And in your Create.cshtml replace the first line with this :
#model TestStackOverflow.Models.CreateEmployeeViewModel
Next add the dropdown list in the Html.BeginForm :
<div class="form-group">
#Html.LabelFor(model => model.OrdersList, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.SelectedOrderID, Model.OrdersList, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.SelectedOrderID, "", new { #class = "text-danger" })
</div>
</div>
Now you should have this in the create view.
Then go back to your EmployeesControler and find the POST method for create and replace it with this :
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CreateEmployeeViewModel model)
{
if (ModelState.IsValid)
{
Employee employee = new Employee()
{
Name = model.Name,
ID = model.ID,
EmployeeNumber = model.EmployeeNumber,
Orders = new List<Order>()
};
employee.Orders.Add(db.Orders.Where(x => x.ID == model.SelectedOrderID).FirstOrDefault());
db.Employees.Add(employee);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
It will create a new Employee based on the view model values and add an order to this Employee. Now if you check your OrderEmployees table you should see that a new entry is created when you're adding an Employee.
Reading
Reading the values is really simpler than writing.
If you want to read all the employees that are handling an order, just do it like this (I took Index.cshtml from the Orders to demonstrate it)
Add this at the top of your file:
#using YourNameSpace.Models
And now a little further modify the file. It should look like this:
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.ManufacturerID)
</td>
<td>
#foreach (Employee e in item.Employees)
{
#e.Name <br />
}
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
#Html.ActionLink("Details", "Details", new { id=item.ID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.ID })
</td>
</tr>
}
Here you can find a tutorial on how to use SelectList to handle one to many relationships and many to many relationships in your views.
Hope this answer will help you.
Related
I have created an enum in my mode.
public enum Color
{
Green,
Black,
Red,
Silver,
Yellow,
White,
Grey,
}
I used thus enum in my main class.
public class MotorDetails
{
public int Id { get; set; }
public string Name { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public string Year { get; set; }
public string Kilometers { get; set; }
public Color Color { get; set; }
}
I then seed data like
context.MotorDetails.AddOrUpdate(x => x.Id, new MotorDetails()
{
Name = "Accord",
Make = "Honda",
Model = "Accord",
Year = r.Next(1980,2016).ToString(),
Kilometers = r.Next(50000, 200000).ToString(),
Color = (Color)r.Next(1,7),
}
So,in database any value b/w 1,7 is saved for color. Which is fine.
Now i am return this data to my view from controller
public List<MotorDetails> getByMake(string make, int minPrice, int maxPrice)
{
List<MotorDetails> motor = db.MotorDetails.Where(x => x.Make == make && x.Price >= minPrice && x.Price <= maxPrice).ToList();
return motor;
}
Problem:
It returns an integer for color to my view and hence number is showing on view.
I want to show color name for given number.
I am using angularJs and here is my code.
<div>
<table class="table">
<tr>
<th>Name</th>
<th>Make</th>
<th>Model</th>
<th>Year</th>
<th>Kilometers</th>
<th>Price</th>
<th>Color</th>
</tr>
<tr ng-repeat="m in motors">
<td>{{m.Name}}</td>
<td>{{m.Make}}</td>
<td>{{m.Model}}</td>
<td>{{m.Year}}</td>
<td>{{m.Kilometers}}</td>
<td>{{m.Price}}</td>
<td>{{m.Color}}</td>
</tr>
</table>
</div>
JSON.NET (the default json serializer for ASP.NET) has an attribute for this [JsonConverter(typeof(StringEnumConverter))]
So
public class MotorDetails
{
public int Id { get; set; }
public string Name { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public string Year { get; set; }
public string Kilometers { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
public Color Color { get; set; }
}
Will serialize the Color as the string value.
I handle this by having a similar object on the client that represents the enum on the server.
Something like:
vm.lookups.colors = [];
vm.lookups.colors.push({ id: 1, value: 'Green' });
vm.lookups.colors.push({ id: 2, value: 'Black' });
// etc.
Then in my view I will render a select and bing the ng-model of the select to the value from the server:
<select ng-options="color.id as color.value for color in vm.lookups.colors"
ng-model="m.Color" disabled>
</select>
An alternative to adding the [JsonConverter(typeof(StringEnumConverter))] attribute on your model property is to add a formatter in your WebApiConfig:
config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new StringEnumConverter());
Not sure if this is still of interest. I solved this problem differently:
1) Load json data just as before. Serialize enums as Integers, not as strings.
2) Load list of enums as pairs of {Id, Name} from an ApiController. The Name properties are filled with language-specific strings.
3) Lookup the localized Name for each enum Id in the list by a simple javascript method call to your AngularJS controller. (Alternatively you could use a filter here, but thats up to you)
4) Hookup the $rootScope.$On('translateChangeSuccess',...) event to reload the localized enums if the language has been changed.
Let me know if this was not clear enough and/or you need a code example.
This is my first post,I am just getting my feet wet with mvc3.I have a form with 3 models in a view and I am trying to submit the form yet the 3 fields that I have come out to null once submitted in the database; this is the form. How the models are created : The main one is countries which is the one I have a problem submitting because it comes out to null
public class countries
{
public string china { get; set; }
public string japan { get; set; }
public string thailand { get; set; }
}
// I know put multiple models inside allmyplanets
public class allmyplanets
{
public IEnumerable<politcal> rankworld { get; set; }
public countries asia { get; set; }
public president names { get; set; }
}
This is how the view looks, the form is only for countries the one im trying to submit
John.Models.allmyplanets
#using (Ajax.BeginForm("planet", "earth", null, new AjaxOptions
{
UpdateTargetId = "submitted",
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST"
}))
{
#Html.TextAreaFor(x => x.asia.china)
#Html.TextAreaFor(x => x.asia.japan)
#Html.TextAreaFor(x => x.asia.thailand)
<br />
<input type="submit" name="myform" id="submitform" value="Submit Form" />
}
Thats the simple form with 3 fields now on submit I tried to capture the value and it does form a new row in the database but all 3 fields come out to null this is how i try to capture it...
public PartialViewResult planet(countries submit,string asia_china, string asia_japan, string asia_thailand)
{
submit.china = asia_china;
submit.japan = asia_japan;
submit.thailand = asia_thailand;
db.countries.Add(submit);
db.SaveChanges();
}
what can be wrong with the code that causes everything to be null? I put the under-dash because razor naming convention turns all ID's with multiple multiples to under-dashes to separate such as id="asia_china". How can this be solved?
[HttpPost]
public PartialViewResult planet(allmyplanets allplanet)
{
countries country=new countries();
allplanet.asia=country;
//save the data
}
Hey This is my model that i joint 3 tables in it.
public Student Student { get; set; }
public Simester Semester { get; set; }
public Lesson Lesson { get; set; }
And this is my Controller:
[HttpGet]
public ActionResult UnitSelection()
{
var students = context.Students;
ViewBag.Students = new SelectList(students, "Id", "FullName");
var semesters = context.Simesters;
ViewBag.Semesters = new SelectList(semesters, "Id", "Title");
var lessons = context.Lessons;
ViewBag.Lessons = new SelectList(lessons, "Id", "Title");
return View();
}
[HttpPost]
public ActionResult UnitSelection(UnitSelectionViewModel model)
{
StudnetLesson snl = new StudnetLesson();
snl.LessonId = model.Lesson.Id;
snl.StudentId = model.Student.Id;
snl.SimesterId = model.Semester.Id;
context.StudnetLessons.Add(snl);
context.SaveChanges();
return RedirectToAction("Success");
}
I want to show a checkbox list in my view in foreach loop.
I want to show Lessons in checkbox list(its string)
public Lesson Lesson { get; set; }
I tested many codes and It does not work any tips?
#using (Html.BeginForm("UnitSelection", "Home", FormMethod.Post))
{
<text>Student Name: </text>
#Html.DropDownListFor(x => x.Student.Id, (SelectList)ViewBag.Students, "Choose a student")
<br />
<text>Semester: </text>
#Html.DropDownListFor(x => x.Semester.Id, (SelectList)ViewBag.Semesters, "Choose your semester")
<br />
<text>Lesson: </text>
foreach (var lessons in (SelectList) ViewBag.Lessons)
{
}
}
add the checkboxes property to your UnitSelectionViewModel
public List<string> lessonsList {get;set;}
then bind it in view
foreach (var lessons in (SelectList) ViewBag.Lessons)
{
<input type="checkbox" name="lessonsList" value ="#lessons.Id" />
}
then in action
UnitSelectionViewModel.lessonsList // here must be id of selectd lessons
answer on comment.
Id in my script just only for example. Use your name of this field.
for checkboxFor example look here
I have been searching around for a bit now. I have tried a couple solutions involving catching the OptimisticConcurrency and adding:
"#Html.HiddenFor(model => model.OrganizationID)"
to my delete page. My index (list), create, and edit pages work like a charm. However, when I go to delete a row it gives me the error below:
DbUpdateConcurrencyException
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 have followed a tutorial to build a Database First application. Currently, I am just bringing in data from my Organizations table until I can get it working smoothly. My organization model looks like this (which was auto-generated from "Add Code Generation Item"):
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace VAGTC.Models
{
using System;
using System.Collections.Generic;
public partial class Organization
{
public Organization()
{
this.Contact_Title = new HashSet<Contact_Title>();
this.Organization_Address = new HashSet<Organization_Address>();
this.Organization_Business_Type = new HashSet<Organization_Business_Type>();
this.Organization_Country = new HashSet<Organization_Country>();
this.Organization_Email = new HashSet<Organization_Email>();
this.Organization_Membership = new HashSet<Organization_Membership>();
this.Organization_Notes = new HashSet<Organization_Notes>();
this.Organization_Phone = new HashSet<Organization_Phone>();
this.Organization_Website = new HashSet<Organization_Website>();
this.Contacts = new HashSet<Contact>();
this.Organization_Industry_Code = new HashSet<Organization_Industry_Code>();
}
public int OrganizationID { get; set; }
public string Name { get; set; }
public virtual ICollection<Contact_Title> Contact_Title { get; set; }
public virtual ICollection<Organization_Address> Organization_Address { get; set; }
public virtual ICollection<Organization_Business_Type> Organization_Business_Type { get; set; }
public virtual ICollection<Organization_Country> Organization_Country { get; set; }
public virtual ICollection<Organization_Email> Organization_Email { get; set; }
public virtual ICollection<Organization_Membership> Organization_Membership { get; set; }
public virtual ICollection<Organization_Notes> Organization_Notes { get; set; }
public virtual ICollection<Organization_Phone> Organization_Phone { get; set; }
public virtual ICollection<Organization_Website> Organization_Website { get; set; }
public virtual ICollection<Contact> Contacts { get; set; }
public virtual ICollection<Organization_Industry_Code> Organization_Industry_Code { get; set; }
}
}
This is the Delete ActionResult in my Organization controller:
//
// GET: /Organization/Delete/5
public ActionResult Delete(int id)
{
using (var db = new VAGTCEntities())
{
return View(db.Organizations.Find(id));
}
}
//
// POST: /Organization/Delete/5
[HttpPost]
public ActionResult Delete(int id, Organization organization)
{
try
{
// TODO: Add delete logic here
using (var db = new VAGTCEntities())
{
db.Entry(organization).State = System.Data.EntityState.Deleted;
db.SaveChanges();
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
and on my Index page it declares the primary key:
#Html.ActionLink("Delete", "Delete", new { id=item.OrganizationID })
Out of curiosity I decided to try adding
"#Html.HiddenFor(model => model.OrganizationID)"
to the bottom, under BeginForm, instead of at the top of the page in fieldset and under legend tags:
#using (Html.BeginForm()) {
<p>
#Html.HiddenFor(model => model.OrganizationID)
<input type="submit" value="Delete" /> |
#Html.ActionLink("Back to List", "Index")
</p>
}
Low and behold - it worked.
I still want to post this! Perhaps someone else will find it and it will help them.
Although I don't know 100% why it is - could someone shed some light on the matter?
when you use the from helper
#using (Html.BeginForm()) {
it spits the following output
<form>
</form>
if you want the hidden field to be posted you need to get it inside the form otherwise it will not be posted, that was the reason the OrganizationID was 0 when you put the hidden field outside the form ...
I am beginning in this issue MVC 2 I hope you can help me. I created a basic model
public class RegisterModel
{
public string Name { get; set; }
public int idCountry { get; set; }
public string Country { get; set; }
}
And I have in the controller the following
public ActionResult Register()
ViewData["country"] = new SelectList(db.PAIS.ToList(), "ID_PAIS", "DESC_PAIS");
return View();
}
My view
<div class="editor-field">
<%= Html.DropDownList("country")%>
</div>
but when I want save on the data base show me a error
[HttpPost]
public ActionResult Register(RegisterModel model)
{
USUARIO usuario = new USUARIO()
{
name = model.name,
city = model.city // show me a error
}
}
Could you please tell me how to save in the data base from this parameters from dropdownlist in my aplication.
Please take a look at this question. I think it may help answer your question.