Every time I add a new App It creates a new AppCategory. I am seriously screwing this up somehow
code first entity framework objects
public class AppCategory
{
public int ID { get; set; }
public string Name { get; set; }
public ICollection<App> apps { get; set; }
}
public class App
{
public int ID { get; set; }
public string Name { get; set; }
public AppCategory Category { get; set; }
}
Editor Template (I would love to just make just one Foreign Key EditorTemplate)
#inherits System.Web.Mvc.WebViewPage
#Html.DropDownList("Category", LIG2010RedesignMVC3.Models.Repo.GetAppCategoriesSelect())
and of course the repository
public static IEnumerable<SelectListItem> GetAppCategoriesSelect()
{
return (from p in GetAppCategories()
select new SelectListItem
{
Text = p.Name,
Value = p.ID.ToString(),
});
}
public static ICollection<AppCategory> GetAppCategories()
{
var context = new LIGDataContext();
return context.AppCategories.ToList();
}
Every time I add a new App It creates a new AppCategory I am seriously screwing this up somehow
Adding more debug info
#inherits System.Web.Mvc.WebViewPage
#Html.DropDownList("", LIG2010RedesignMVC3.Models.Repo.GetAppCategoriesSelect())
gives me a validation message on the post
Parameters application/x-www-form-urlencoded
Category 1
Name 8
Validation error The value '1' is invalid.
This makes sense because Category should be an object not an integer.
Controller Code as asked for
pretty sure this isnt the problem as it came from MVCScaffold
[HttpPost]
public ActionResult Create(App d)
{
if (ModelState.IsValid)
{
context.Apps.Add(d);
context.SaveChanges();
return RedirectToAction("Index");
}
return View();
}
My model was incorrectly set up ... virtual ICollection and just the foreign key id for the sub and everything worked... changes below
Model
public class AppCategory
{
public int ID { get; set; }
public string Name { get; set; }
public **virtual** ICollection<App> Apps { get; set; }
}
public class App
{
public int ID { get; set; }
********************************************
[UIHint("AppCategory")]
public int AppCategoryID { get; set; }
********************************************
public string Name { get; set; }
}
public class LIGDataContext : DbContext
{
public DbSet<AppCategory> AppCategories { get; set; }
public DbSet<App> Apps { get; set; }
}
/Views/Shared/EditorTemplates/AppCategory.cshtml
#inherits System.Web.Mvc.WebViewPage
#Html.DropDownList("", LIG2010RedesignMVC3.Models.Repo.GetAppCategoriesSelect())
AppController
[HttpPost]
public ActionResult Create(App d)
{
if (ModelState.IsValid)
{
this.repository.Add(d);
this.repository.Save();
return RedirectToAction("Index");
}
return View();
}
If you bind your dropDownList to Category.Id, you'll at least get the selected value into that filed, but nothing else in your Category Object.
The model binder cannot create the AppCategory object from the form collection in your Create action because the form only has an ID for that object (the other properties of AppCategory are not there).
The quickest solution would be setting the Category property of your App object manually, like this :
[HttpPost]
public ActionResult Create(App d) {
int categoryId = 0;
if (!int.TryParse(Request.Form["Category"] ?? String.Empty, out categoryId) {
// the posted category ID is not valid
ModelState.AddModelError("Category",
"Please select a valid app category.")
} else {
// I'm assuming there's a method to get an AppCategory by ID.
AppCategory c = context.GetAppCategory(categoryID);
if (c == null) {
// couldn't find the AppCategory with the given ID.
ModelState.AddModelError("Category",
"The selected app category does not exist.")
} else {
// set the category of the new App.
d.Category = c;
}
}
if (ModelState.IsValid)
{
context.Apps.Add(d);
context.SaveChanges();
return RedirectToAction("Index");
}
return View();
}
Related
I need help with Entity Framework.
Controller:
public ActionResult Create([Bind(Prefix = "visit")] visit visit, [Bind(Prefix = "drugsEdition")] IEnumerable<drugsEdition> drugsEdition, [Bind(Prefix = "accessoryEdition")] IEnumerable<accessoryEdition> accessoryEdition, [Bind(Prefix = "servicesEdition")] IEnumerable<servicesEdition> servicesEdition)
{
Models.VisitDetails visitDetails = new Models.VisitDetails();
visitDetails.visit = visit;
if (ModelState.IsValid)
{
db.visit.Add(visit);
if (drugsEdition != null)
{
foreach (var item in drugsEdition)
{
item.idVisit = visit.id;
db.drugsEdition.Add(item);
}
}
if (accessoryEdition != null)
{
foreach (var item in accessoryEdition)
{
item.idVisit = visit.id;
db.accessoryEdition.Add(item);
}
}
if (servicesEdition != null)
{
foreach (var item in servicesEdition)
{
item.idVisit = visit.id;
db.servicesEdition.Add(item);
}
}
db.SaveChanges();
return RedirectToAction("Details", new { id = visit.id });
}
return View(visitDetails);
}
Model:
[Table("servicesEdition")]
public partial class servicesEdition
{
public int id { get; set; }
public int idService { get; set; }
public int idVisit { get; set; }
public double priceSell { get; set; }
[ForeignKey("idService")]
public virtual services services { get; set; }
}
In this code, I added a new visit to the database, and I want get the visit's id after the code line db.visit.Add (visit). When I add new drugsEdition and new accessoryEdition, this code is correct and added good idVisit, but when I addedservicesEdition idVisit = 0. Why 'servicesEdition' doesn't get good idVisit ?
If you add a virtual navigational property of type Visit, EF will get the corresponding visit id and fill that in when it saves a servicesEdition object on your SaveChanges method call.
I would also renaming the foreign key property to VisitId so that the referential integrity works by convention (naming convention) and you do not need to explicitly use the ForeignKey attribute. I would also recommend you to use PascalCasing when writing C# classes( not necessarily needed for your code to work)
public partial class ServicesEdition
{
public int id { get; set; }
public int idService { get; set; }
public int VisitId { get; set; }
public virtual Visit Visit { get; set; }
public double priceSell { get; set; }
[ForeignKey("idService")]
public virtual services services { get; set; }
}
If you do not want to alter the ServicesEdition entity definition like i described above, another option is to call the SaveChanges() method after you add the Visit entity and then you can access the Id property of that.
db.visit.Add(visit);
db.SaveChanges();
var visitId = db.Id;
//Now you can use visitId to save other entities
The issue is db.visit.Add(visit); does not generate id until hit db.SaveChanges();
You could add db.SaveChanges(); after db.visit.Add(visit);.
Or you will save as a graph like Shyju explained.
I Have the following class in a model:
public partial class OrganizationUnit
{
public string code{ get; set; }
public int OrganizationCod { get; set; }
public string name { get; set; }
public string ParentUnitCode{ get; set; }
public int level{ get; set; }
public string author{ get; set; }
public System.DateTime CreateDtStmp{ get; set; }
public int Status { get; set; }
public decimal weighing { get; set; }
[ForeignKey("status")]
public virtual Status UnitStatus { get; set; }
public virtual Organization Organization { get; set; }
public virtual ICollection<OrganizationUnit> OrganizationUnit1{ get; set; }
[ForeignKey("ParentUnitCode")]
public virtual OrganizationUnit OrganizationUnit2{ get; set; }
public OrganizationUnit ()
{
CreateDtStmp= DateTime.Now;
author = HttpContext.Current.User.Identity.Name.Substring(4,HttpContext.Current.User.Identity.Name.Length - 4);
}
}
Before inserting a new record I need to validate sum(weighing) can not exceed 100 including the attempted new record, considering only the records with the same ParentUnit.
Can this be done in the model or should it be done in the controller?
this is the saving controller part (basically is what is autogenerated by VS),consider that the view will send the corresponding parameter to the method:
private SAIM_IPM_DVContext db = new SAIM_IPM_DVContext();
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(OrganizationUnit organizationunit)
{
if (ModelState.IsValid)
{
db.OrganizationUnit.Add(organizationunit);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(organizationunit);
}
If OrganizationUnit1 is the collection of all other units with the same ParentUnit, you can perform the check in the ViewModel by implementing IValidatableObject:
using System.ComponentModel.DataAnnotations;
public partial class OrganizationUnit : IValidatableObject {
/* properties etc... */
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
if (OrganizationUnit1.Sum(o => o.weighing) + this.weighing > 100.0) {
yield return new ValidationResult(
"Sum of weightings would exceed 100.",
new[] { "weighing" });
}
}
}
Note that this assumes that the weighing is posted back for all units in the OrganizationUnit1 collection (e.g. as hidden fields) so it is accessible when this check is performed by the MVC pipeline (this is done before your POST action will be hit).
If this check fails, ModelState.IsValid will be false in the controller.
If you have no access to the other units in the Viewmodel, you will have to fetch them from the DB in the controller and perform the check there.
After a while and tries I came up with this solution works perfect, however I am not sure is the best practice. This is on the controller class
public ActionResult Create(OrganizationUnit organizationunit)
{
decimal weighingsum= 0;
foreach (var val in db.OrganizationUnit.Where(t => t.ParentUnitCode== organizationunit.ParentUnitCode))
{
weighingsum+= val.weighing ;
}
weighingsum+= organizationunit.weighing ;
if (weighingsum > 100)
{
ModelState.AddModelError("", "Weighing sum can not exceed 100 for a Parent Unit");
}
else
{
if (ModelState.IsValid)
{
db.OrganizationUnit.Add(organizationunit);
db.SaveChanges();
return RedirectToAction("Index");
}
}
return View(organizationunit);
}
should anyone comes up with a better solution, please do share I'll appreciate it.
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 have been struggling with this for some time. I have a model and an edit view model so I can allow the user to both see the image that was uploaded before and upload a replacement. Everything works fine until I get to the db.Entry portion. The error is:
The entity type EditCardViewModel is not part of the model for the current context.
If I try to add EditCardViewModel to the DbContext, it wants a key and a table, which isn't going to happen. The ViewModel is just a way to pass data. How do I tell it to use the Cards context when saving from this ViewModel?
Controller Edit Get:
public ActionResult Edit(int id = 0)
{
Card card = db.Cards.Find(id);
ViewData["Abilities"] = card.CardAbilities.Select(a => a.AbilityID);
if (card == null)
{
return HttpNotFound();
}
var editview = new EditCardViewModel(card);
{
}
return View(editview);
}
Controller Edit Post:
[HttpPost]
public ActionResult Edit(EditCardViewModel card)
{
if (ModelState.IsValid)
{
if(card.ImageUpload != null)
{
string savedFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Images");
savedFileName = Path.Combine(savedFileName, Path.GetFileName(card.ImageUpload.FileName));
card.ImageUpload.SaveAs(savedFileName);
card.Cards.ImageUrl = "\\Images\\" + Path.GetFileName(card.ImageUpload.FileName);
}
db.Entry(card).State = EntityState.Modified; //ERROR - Entity Type is not part of context
db.SaveChanges();
Edit ViewModel:
public class EditCardViewModel
{
public Card Cards { get; set; }
public HttpPostedFileBase ImageUpload { get; set; }
public IEnumerable<SelectListItem> Abilities { get; set; }
public int[] SelectedAbilities { get; set; }
public IEnumerable<SelectListItem> Rarities { get; set; }
public int SelectedRarities { get; set; }
public IEnumerable<SelectListItem> MainTypes { get; set; }
public int SelectedMainTypes { get; set; }
public IEnumerable<SelectListItem> SubTypes { get; set; }
public int SelectedSubTypes { get; set; }
public IEnumerable<SelectList> CardSets { get; set; }
public int SelectedCardSets { get; set; }
public Rarity Rarity { get; set; }
public MainType MainType { get; set; }
public SubType SubType { get; set; }
public CardSet CardSet { get; set; }
public EditCardViewModel() { } //NEEDED OR PARAMETERLESS CONSTRUCTOR ERROR
public EditCardViewModel(Card card) //NEEDED OR CANNOT PASS CARD MODEL
{
Cards = card;
}
}
The problem is that your view model is not recognised by Entity Framework - it has no idea that EditCardViewModel is meant to be a representation of a Card. It's a bit unclear from your view model exactly what you are doing with it but you either need to create a new Card object and use that:
var newCard = new Card
{
Id = card.Id //for example
};
Or possibly use the Cards property of your view model as that is of the correct type.
I have written ASP.NET MVC Code for CRUD but while Updating,Deleting and Details the page is throwing the error as value can not be null.my code is as follows:
public ActionResult Edit(int id=0)
{
var alb=db.Albums.FirstOrDefault(x=>x.AlbumId==id);
return View(alb);
}
public ActionResult Detail(int id=0)
{
var alb=db.Albums.Find(id);
return View(alb);
}
public ActionResult Delete(int id=0)
{
var album = db.Albums.Find(id);
return View(album);
}
and my Model is
public class Album
{
public int AlbumId { get; set; }
public int GenreId { get; set; }
public int ArtistId { get; set; }
public string AlbumTitle { get; set; }
public String Price { get; set; }
public String AlbumArtUrl { get; set; }
public Genre Genre { get; set; }
public Artist Artist { get; set; }
}
This is because the variable alb and album is showing me the null value its not getting any ID.
so suggest me on this.
This is because the variable alb and album is showing me the null
value its not getting any ID
If there is no record in your database then you should handle it gracefully in code. You should have something like:
var alb=db.Albums.FirstOrDefault(x=>x.AlbumId==id);
if (alb==null) {
// TempData, simplest way to give you an example
TempData["error_msg"] = "the record does not exists";
return RedirectToAction("index", "error");
}
return View(alb);
in your ErrorController
public ActionResult Index() {
ViewBag.ErrorMsg = TempData["error_msg"];
return View();
}
in the view (Index.cshtml) for your error controller
<h1>You have been, or trying to be, a naughty boy</h1>
<p>#ViewBag.ErrorMsg</p>
This is not the most elegant solution though but good enough to get you started. I think the most important part of my answer is not the code I gave you but the suggestion to handle that kind of situation (null values / missing or invalid records) in code.