I'm trying to add data to a Many-To-Many relationship.
Here's my controller
[HttpPost]
public ActionResult AddSkillsPost()
{
int Teacher_ID = Convert.ToInt32(Session["Teacher_ID"]);
var SkillsArray = Request.Form["chk_group[]"];
if(SkillsArray != null)
{
foreach(var skill in SkillsArray)
{
int Skill_ID = Convert.ToInt32(skill);
var SkillToBeModified = (from s in db.Skills
where s.ID == Skill_ID
select new Skill { ID = s.ID, SkillName = s.SkillName, Teachers = s.Teachers });
var Teacher = (from t in db.Teachers
where t.ID == Teacher_ID
select new Teacher { ID = t.ID, FirstName = t.FirstName, LastName = t.LastName,
Email = t.Email, Campus = t.Campus, Skills = t.Skills });
SkillToBeModified.Teachers.Add(Teacher);
db.Entry(SkillToBeModified).State = EntityState.Modified;
db.SaveChanges();
}
}
return RedirectToAction("MyProfile");
}
So I'm trying to add a teacher to a certain skill. However, I'm having a problem with this line
SkillToBeModified.Teachers.Add(Teacher);
I get the error
'IQueryable' does not contain a definition for 'Teachers' and
no extension method 'Teachers' accepting a first argument of type
'IQueryable' could be found (are you missing a using directive
or an assembly reference?)
I'm assuming this is a syntax mistake (something with the query?), but I can't figure out the correct way to write it.
Here's my model for Skills
[Table("Skills")]
public class Skill
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[Required]
public string SkillName { get; set; }
public virtual List<Teacher> Teachers { get; set; }
public Skill()
{
this.Teachers = new List<Teacher>();
}
}
and here's how my DB looks like
Looking forward to any reply's
EDIT: the form,
<form name="addSkillsForm" action="AddSkillsPost" method="post">
#foreach (var skill in Model.Skills)
{
<input type="checkbox" name="chk_group[]" value="#skill.ID" />#skill.SkillName< br />
}
<input type="submit" value="Update Skills" />
</form>
I'm using a check box form where users can check multiple items, maybe I'm not handeling them coorectly in my POST?
If your DB looks like the picture, you should be able to just do this.
[HttpPost]
public ActionResult AddSkillsPost()
{
int teacher_ID = Convert.ToInt32(Session["Teacher_ID"]);
var SkillsArray = Request.Form["chk_group[]"];
if (SkillsArray != null)
{
foreach (var skill in SkillsArray.Split(','))
{
int skill_ID = Convert.ToInt32(skill);
db.TeacherSkills.Add(new TeacherSkill() { Teacher_ID = teacher_ID, Skill_ID = skill_ID });
db.SaveChanges();
}
}
return RedirectToAction("MyProfile");
}
however if you're adding teacher to a skill then you'd do this.
[HttpPost]
public ActionResult AddSkillsPost()
{
var teacher_ID = Convert.ToInt32(Session["Teacher_ID"]);
var SkillsArray = Request.Form["chk_group[]"];
if (SkillsArray != null)
{
var teacher = db.Teachers.Find(teacher_ID);
foreach (var skill in SkillsArray.Split(','))
{
var skill_ID = Convert.ToInt32(skill);
var skillToBeModified = db.Skills.Find(skill_ID);
skillToBeModified.Teachers.Add(teacher);
db.Entry(skillToBeModified).State = EntityState.Modified;
db.SaveChanges();
}
}
return RedirectToAction("MyProfile");
}
Related
I'm new in mvc . i have this diagram part of my data base diagram
I want to show to orders user , status order and products order.and i test many ways but not successful.
in view model:
public class OrderListViewModel
{
public List<Order> orders { get; set; }
}
controller:
BOL.User CurrentUser = _user.user.GetUser(User.Identity.Name);
int UserId = CurrentUser.ID;
var listorders = _order.UserOrders(UserId) ;
List<OrderListViewModel> orderVM = new List<OrderListViewModel>();
orderVM.Add (new OrderListViewModel { orders=listorders.ToList()
}
);
return View(orderVM);
in view:
#model IEnumerable<OrderListViewModel>
#foreach (var item in Model)
{
Html.Display(item.orders.Select(x=>x.Status.StatusName).FirstOrDefault());
foreach (var fact in item.orders.ToList())
{
Html.Display(fact.Factors.);
}
<br />
Html.Display("****");
}
and i don't know how to show products in each order??
I am trying to implement a search panel with several checkbox to filter a table data, but i have a problem. I cant retain value of input checked after submit.
How can I solve?
My model :
public class OrdineView
{
public int anno { get; set; }
public Int32 nrOrdine { get; set; }
public string centro { get; set; }
[DataType(DataType.Date), DisplayFormat(DataFormatString = "{0:d}")]
public DateTime? data { get; set; }
public String codice { get; set; }
public String ragsoc { get; set; }
[DisplayFormat(DataFormatString = "{0:C}")]
public Nullable<double> importo;
}
I have a Search model:
public class OrdiniSearchModel
{
public int? anno {get;set;}
public String[] Distinzione {get;set;}
}
public class OrdiniBusinessLogic
{
private NORTHWNDEntities1 db;
public OrdiniBusinessLogic()
{
db = new NORTHWNDEntities1();
}
public IQueryable<OrdineView> GetOrdini(OrdiniSearchModel ordiniSearch)
{
var queryOrdineView = (from ordine in db.ORDINI
join cliente in db.CLIENTI on ordine.Codcli equals cliente.Codana
select new OrdineView
{
anno = ordine.Anno,
nrOrdine = ordine.Numord,
centro = ordine.Codcen,
data = ordine.Datord,
codice = ordine.Codcli,
ragsoc = cliente.Ragso1,
importo = ordine.Totord
}).ToList().AsQueryable();
var model = queryOrdineView;
if (ordiniSearch.anno != null)
{
model = model.Where(o => o.anno == ordiniSearch.anno);
}
if (ordiniSearch.Distinzione != null && ordiniSearch.distinzione.Count() > 0)
{
List<string> distinzioniSelezionate = new List<string>();
foreach (var item in ordiniSearch.Distinzione)
{
distinzioniSelezionate.Add(item);
}
model = model.Where(o => distinzioniSelezionate.Contains(o.distinzione));
}
return model;
}
}
My Controller:
public ActionResult Index(OrdiniSearchModel searchModel, int? pageNumber )
{
ViewBag.Anno = db.ORDINI.Select(o => new { o.Anno }).Distinct().OrderByDescending(o => o.Anno).Select(o => o.Anno);
var searchLogic = new OrdiniBusinessLogic();
var model = searchLogic.GetOrdini(searchModel);
return View(model.OrderBy(i => i.codice).ToPagedList(pageNumber ?? 1, 10));
}
In my view I have
<input name="Distinzione" type="checkbox" value="001">001
<input name="Distinzione" type="checkbox" value="002">002
...and so on
After submit I get data correctly but lose checked state.
UPDATE: Based on the comments, I updated the view and adde more code.
If you mean that the checkboxes don't stay checked after the page is refreshed. It's because you don't tell them which should be checked. There is one possible solution for you. Create a simple helper method right in the view where you need the checkboxes. This method just checks the array of values and if it finds the value there, it will render a checkbox with checked state.
View.cshtml
#model OrdinePagedList
#MyCheckbox("001")
#MyCheckbox("002")
#helper MyCheckbox(string value)
{
if (Model.Distinzione.Contains(value))
{
<input type="checkbox" name="Distinzione" value="#value" checked="checked"/>
}
else
{
<input type="checkbox" name="Distinzione" value="#value" />
}
#value
}
I suggest to create a new view model class:
public class OrdinePagedList
{
public IEnumerable<OrdiniView> Pages { get; set; }
public IEnumerable<string> Distinzione { get; set;
}
And update either your business logic so that it returns this new class
// from
public IQueryable<OrdineView> GetOrdini(OrdiniSearchModel ordiniSearch)
// to
public OrdinePagedList GetOrdini(OrdiniSearchModel ordiniSearch)
or update the controller:
public ActionResult Index(OrdiniSearchModel searchModel, int? pageNumber )
{
ViewBag.Anno = db.ORDINI.Select(o => new { o.Anno }).Distinct().OrderByDescending(o => o.Anno).Select(o => o.Anno);
var searchLogic = new OrdiniBusinessLogic();
var pages = searchLogic.GetOrdini(searchModel);
OrdinePagedList model = new OrdiniPagedList {
Pages = pages.OrderBy(i => i.codice).ToPagedList(pageNumber ?? 1, 10),
Distinzione = searchModel.Distinzione
}
return View(model);
}
or if you don't want (or can't) create the new view model (but I strongly recommend to do so). You can use ViewBag to pass the additinal collection of checked values:
public ActionResult Index(OrdiniSearchModel searchModel, int? pageNumber)
{
ViewBag.Distinzione = searchModel.Distinzione;
// original code
}
and then you'll just have to update the helper method. For the sake of simplicity I don't check if the ViewBag.Distinzione exists. But you should.
#helper MyCheckbox(string value)
{
if (ViewBag.Distinzione.Contains(value))
{
<input type="checkbox" name="Distinzione" value="#value" checked="checked"/>
}
else
{
<input type="checkbox" name="Distinzione" value="#value" />
}
#value
}
In short. You need to make sure that the data (collection of checked values), you get in controller, are being sent back to the view.
List<string> distinzioniSelezionate = new List<string>();
if (searchModel.distinzione != null && searchModel.distinzione.Count() > 0)
{
foreach (var item in searchModel.distinzione)
{
distinzioniSelezionate.Add(item);
}
}
OrdinePagedList model = new OrdinePagedList
{
Pages = pages.OrderBy(i => i.Codice).ToPagedList(pageNumber ?? 1, 10),
Distinzione = distinzioniSelezionate
};
I had to modify the ActionResult because Distinzione is not empty
Im having some trouble when I try to delete a record from a table. I get the error:
The number of primary key values passed must match number of primary key values defined on the entity.
The table has a composite primary key. They are cabinCrewId and flightId.
Controller:
public ActionResult Delete(string name)
{
using (A1Context db = new A1Context())
{
var id = from person in db.person
from flightcabincrew in db.flightcabincrew
from cabincrew in db.cabincrew
where person.name == name
where person.id == cabincrew.person
where cabincrew.person == flightcabincrew.cabinCrewId
select new { flightcabincrew.cabinCrewId, flightcabincrew.flightId };
FlightCabinCrew fcc = db.flightcabincrew.Find(id);
if (fcc == null)
{
return HttpNotFound();
}
else
{
return View(fcc);
}
}
}
Post:
[HttpPost]
public ActionResult Delete(FlightCabinCrew fcc)
{
using (A1Context db = new A1Context())
{
db.Entry(fcc).State = System.Data.EntityState.Deleted;
db.SaveChanges();
}
return View();
}
and part of the view concerned:
#model IEnumerable<Assignment2.Models.FlightCrewGrid>
#{
WebGrid grid = new WebGrid(Model);
}
<h2>#ViewBag.Title</h2>
#grid.GetHtml(columns: grid.Columns(
grid.Column("PersonName", "Crew Member"),
grid.Column("FlightDay", "Flight Day"),
grid.Column("FromAirport", "From"),
grid.Column("ToAirport", "To"),
grid.Column("Model", "Model"),
grid.Column("startDate", "Start Date"),
grid.Column(header: "Delete", format: (item) => Html.ActionLink("Delete", "Delete", new { id=item.PersonName})))
Thanks in advance for any guidance.
Maybe you didn't declare a primary key for the entity. You do this by marking the primary key column with the [Key] attribute.
[Key]
public int cabinCrewId { get; set; }
[Key]
public int flightId { get; set; }
public ActionResult Demodelete(int id)
{
Employee emptbl = new Employee();
emptbl.EmpId = id;
dbc.Entry(emptbl).State = EntityState.Deleted;
dbc.SaveChanges();
return View();
}
My Action
[Authorize(Roles = "Admin")]
public ActionResult Index()
{
using (var ctx = new _dbContext())
{
return View(ctx.UserProfiles.OrderBy(x => x.UserId).ToList());
}
}
I want to display roles with UserId and UserName how can i do that??
Update:
View Model
public class AccountIndexViewModel
{
public int UserId { get; set; }
public string UserName { get; set; }
public string Roles { get; set; }
}
View
#using GoldCalculator.Models
#model IEnumerable<AccountIndexViewModel>
#foreach (var user in Model)
{
<tr>
<td>#user.UserId</td>
<td>#user.UserName</td>
<td>#user.Roles</td>
<td> #Html.ActionLink("X", "Delete", new { id = #user.UserName }, new { #class = "deletebtn"})</td>
</tr>
}
The output is System.String[]
Assuming you have enabled roles in your application and that you have already created some roles:
using WebMatrix.WebData;
///blah blah blah...
///inside some action:
var roles = (SimpleRoleProvider)Roles.Provider;
var allRoles = roles.GetAllRoles();
Getting role for specific user:
var userRoles = roles.GetRolesForUser("admin#user.com");
Answering you new question, try this:
var model = ctx.UserProfiles.OrderBy(x => x.UserId);
var newModel = from ab in model
select new
{
UserName = ab.UserName,
UserId = ab.UserId,
Role = roles.GetRolesForUser(ab.UserName)
};
You are assigning value to variable that already has been declared and apparently data types don't match.
I'm kind of new to razor MVC, and I'm wondering how can I read the values I return in the view?
My code is like this:
public ActionResult Subject(int Category)
{
var db = new KnowledgeDBEntities();
var category = db.categories.Single(c => c.category_id == Category).name;
var items = from i in db.category_items
where i.category_id == Category
select new { ID = i.category_id, Name = i.name };
var entries = from e in db.item_entry
where items.Any(item => item.ID == e.category_item_id)
select new { ID = e.category_item_id, e.title };
db.Dispose();
var model = new { Name = category, Items = items, Entries = entries };
return View(model);
}
Basically, I return an anonymous type, what code do I have to write to read the values of the anonymous type in my view?
And if this is not possible, what would be the appropriate alternative?
Basically, I return an anonymous type
Nope. Ain't gonna work. Anonymous types are emitted as internal by the compiler and since ASP.NET compiles your views into separate assemblies at runtime they cannot access those anonymous types which live in the assembly that has defined them.
In a properly designed ASP.NET MVC application you work with view models. So you start by defining some:
public class MyViewModel
{
public string CategoryName { get; set; }
public IEnumerable<ItemViewModel> Items { get; set; }
public IEnumerable<EntryViewModel> Entries { get; set; }
}
public class ItemViewModel
{
public int ID { get; set; }
public string Name { get; set; }
}
public class EntryViewModel
{
public int ID { get; set; }
public string Title { get; set; }
}
and then you adapt your controller action to pass this view model to the view:
public ActionResult Subject(int Category)
{
using (var db = new KnowledgeDBEntities())
{
var category = db.categories.Single(c => c.category_id == Category).name;
var items =
from i in db.category_items
where i.category_id == Category
select new ItemViewModel
{
ID = i.category_id,
Name = i.name
};
var entries =
from e in db.item_entry
where items.Any(item => item.ID == e.category_item_id)
select new EntryViewModel
{
ID = e.category_item_id,
Title = e.title
};
var model = new MyViewModel
{
CategoryName = category,
Items = items.ToList(), // be eager
Entries = entries.ToList() // be eager
};
return View(model);
}
}
and finally you strongly type your view to the view model you have defined:
#model MyViewModel
#Model.Name
<h2>Items:</h2>
#foreach (var item in Model.Items)
{
<div>#item.Name</div>
}
<h2>Entries:</h2>
#foreach (var entry in Model.Entries)
{
<div>#entry.Title</div>
}
By the way to ease the mapping between your domain models and view models I would recommend you checking out AutoMapper.
Oh, and since writing foreach loops in a view is kinda ugly and not reusable I would recommend you using display/editor templates which would basically make you view look like this:
#model MyViewModel
#Model.Name
<h2>Items:</h2>
#Html.DisplayFor(x => x.Items)
<h2>Entries:</h2>
#Html.DisplayFor(x => x.Entries)
and then you would define the respective display templates which will be automatically rendered for each element of the respective collections:
~/Views/Shared/DisplayTemplates/ItemViewModel:
#model ItemViewModel
<div>#item.Name</div>
and ~/Views/Shared/DisplayTemplates/EntryViewModel:
#model EntryViewModel
<div>#item.Title</div>