ASP MVC table foreign key configuration - asp.net-mvc

public class Movies
{
[Key]
public int movieID { get; set; }
public String Title { get; set; }
public virtual Genres parentGenre { get; set; }
}
public class Genres
{
public Genres()
{
this.movies = new HashSet<Movies>();
}
[Key]
public int genreId { get; set; }
public String genreName { get; set; }
public ICollection<Movies> movies { get; set; }
}
I can successfully create a DropDownList on my addmovie view page by reading in the Genres table.
But when I try submit the page, it states "The value '10' is invalid." This leads me to believe that I am trying to put an Int (from the dropdownlist value) into an object (from the "Genres parentGenre").
Have I set up the "Genres parentGenre" to "genreId" foreign key relationship correctly to where it should only want a 'number' for the "parentGenre" field, or does it expect more?
added:
controller:
[HttpPost]
public ActionResult Create(Movies movies)
{
if (ModelState.IsValid)
{
db.Movies.Add(movies);
db.SaveChanges();
return RedirectToAction("Index");
}
IEnumerable<SelectListItem> items = db.Genres
.Select(c => new SelectListItem
{
Value = SqlFunctions.StringConvert((double)c.genreId).Trim(),
Text = c.genreName
});
ViewBag.genreId = items;
}
view:
<div class="editor-label">
#Html.LabelFor(model => model.parentGenre.genreName)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.parentGenre,(IEnumerable<SelectListItem>)ViewBag.genreId)
#Html.ValidationMessageFor(model => model.parentGenre)

In lieu of your comments, here's what I'd recommend:
Models:
public class Movie
{
[Key]
public int MovieID { get; set; }
public String Title { get; set; }
public int GenreId { get; set; }
public virtual Genre Genre { get; set; }
}
public class Genre
{
public Genre()
{
this.movies = new HashSet<Movies>();
}
[Key]
public int GenreId { get; set; }
public String Name { get; set; }
public ICollection<Movies> Movies { get; set; }
}
Controller:
[HttpPost]
public ActionResult Create(Movie Movie)
{
if (ModelState.IsValid)
{
db.Movies.Add(Movie);
db.SaveChanges();
return RedirectToAction("Index");
}
IEnumerable<SelectListItem> items = db.Genres
.Select(c => new SelectListItem
{
Value = SqlFunctions.StringConvert((double)c.GenreId).Trim(),
Text = c.Name
});
ViewBag.genreId = items;
}
View:
<div class="editor-label">
#Html.LabelFor(model => model.Genre.Name)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.Genre.Id,(IEnumerable<SelectListItem>)ViewBag.genreId)
#Html.ValidationMessageFor(model => model.Genre)
</div>
If I'm reading what you're doing correctly, that should work. I haven't done much with EF though, so I can't be 100% certain.

Related

Asp.Net MVC dropdownlist not posting value to controller -> database

my development environment is ASP.NET MVC 5 using Entity Framework 6 using a code-first workflow.
My problem: When trying to add a new record to the database, the values from my two dropdownlists are not being included. All the other fields are indeed saving to the database.
I am passing a ViewModel to the view in question:
public class NewItemViewModel
{
public IEnumerable<Category> Categories { get; set; }
public Item Item { get; set; }
public IEnumerable<Donor> Donors { get; set; }
}
The domain models I am using:
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int Quantity { get; set; }
public bool IsActive { get; set; }
public Category Category { get; set; }
public Donor Donor { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Donor
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName { get { return FirstName + " " + LastName; } }
public string Email { get; set; }
}
The relevant controller: This New() action is simply used to pass data to the view for the form to be submitted
public ActionResult New()
{
var itemCategories = _context.ItemCategory.ToList();
var donors = _context.Donors.ToList();
var viewModel = new NewItemViewModel
{
Categories = itemCategories,
Donors = donors
};
return View(viewModel);
}
Here is my actual action that adds the submitted data to the database:
// Create a new item.
[HttpPost]
public ActionResult Create(Item item)
{
_context.Items.Add(item);
_context.SaveChanges();
return RedirectToAction("Index", "Item");
}
And lastly, the view itself (I will minimize the code here):
#using (Html.BeginForm("Create", "Item"))
{
<div class="form-group">
#Html.LabelFor(m => m.Item.Donor)
#Html.DropDownListFor(m => m.Item.Donor, new SelectList(Model.Donors, "Id", "FullName"), "Who donated this item?", new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(m => m.Item.Category)
#Html.DropDownListFor(m => m.Item.Category, new SelectList(Model.Categories, "Id", "Name"), "Select Item Category", new { #class = "form-control" })
</div>
}
To reiterate the problem I am having: The values of the dropdownlist for Category and Donor are not saving to the database, whereas the others (non-navigation properties?) Name, Description, Quantity, etc. is working correctly.
Am I using the ViewModel the right way? I was under the impression that the MVC framework knows how to deal with passing the Item object parameter in the Create() action - mapping what it needs to within the Item entity.
Any help would be much appreciated. Thank you.
In the NewItemViewModel you have not created property to hold the selected values from dropdown
public class NewItemViewModel
{
public IEnumerable<Category> Categories { get; set; }
public int SelectedCategory{get;set;}
public Item Item { get; set; }
public int SelectedDonor{get;set;}
public IEnumerable<Donor> Donors { get; set; }
}
#using (Html.BeginForm("Create", "Item"))
{
<div class="form-group">
#Html.LabelFor(m => m.Item.Donor)
#Html.DropDownListFor(m => m.SelectedDonor, new SelectList(Model.Donors, "Id", "FullName"), "Who donated this item?", new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(m => m.Item.Category)
#Html.DropDownListFor(m => m.SelectedCategory, new SelectList(Model.Categories, "Id", "Name"), "Select Item Category", new { #class = "form-control" })
</div>
}

How do I pass selected items in MVC4 EF5?

I am new to MVC and would appreciate any advice. I have several models/tables that work together. The trouble I am having is with a many-to-many relationship. What I want is to have a listbox that a user can multiselect from and pass those values to save in join table, while saving the primary entry to another table.
My models:
public class Card
{
public virtual int CardID { get; set; }
public virtual string Title { get; set; }
//A bunch of properties...
//Drop Down Lists
public int RarityID { get; set; }
public virtual Rarity Rarity { get; set; }
public int MainTypeID { get; set; }
public virtual MainType MainType { get; set; }
public int CardSetID { get; set; }
public virtual CardSet CardSet { get; set; }
public int SubTypeID { get; set; }
public virtual SubType SubType { get; set; }
public virtual string AdditionalType { get; set; }
public virtual IList<CardAbility> Abilities { get; set; }
public virtual int[] SelectedAbilities { get; set; }
}
public class Ability
{
public virtual int AbilityID { get; set; }
public virtual string Title { get; set; }
public virtual IList<CardAbility> Cards { get; set; }
}
public class CardAbility
{
public int CardAbilityID { get; set; }
public virtual Ability Ability { get; set; }
public int AbilityID { get; set; }
public virtual Card Card { get; set; }
public int CardID { get; set; }
}
My Controller:
public ActionResult Create()
{
ViewBag.RarityID = new SelectList(db.Rarities, "RarityID", "Title");
ViewBag.MainTypeID = new SelectList(db.MainTypes, "MainTypeID", "Title");
ViewBag.CardSetID = new SelectList(db.CardSets, "CardSetID", "Title");
ViewBag.SubTypeID = new SelectList(db.SubTypes, "SubTypeID", "Title");
ViewBag.Abilities = new MultiSelectList(db.Abilities, "AbilityID", "Title");
return View();
}
// POST: /Card/Create
[HttpPost]
public ActionResult Create(Card card)
//[ModelBinder(typeof(CardBinder1))]
{
if (ModelState.IsValid)
{
db.Cards.Add(card);
db.SaveChanges();
foreach (var items in card.SelectedAbilities)
{
var obj = new CardAbility() { AbilityID = items, CardID = card.CardID };
db.CardAbilities.Add(obj);
}
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.RarityID = new SelectList(db.Rarities, "RarityID", "Title", card.RarityID);
ViewBag.MainTypeID = new SelectList(db.MainTypes, "MainTypeID", "Title", card.MainTypeID);
ViewBag.CardSetID = new SelectList(db.CardSets, "CardSetID", "Title", card.CardSetID);
ViewBag.SubTypeID = new SelectList(db.SubTypes, "SubTypeID", "Title", card.SubTypeID);
ViewBag.Abilities = new MultiSelectList(db.Abilities, "AbilityID", "Title");
return View(card);
My Create View:
model MTG.Models.Card
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Card</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Title)
#Html.ValidationMessageFor(model => model.Title)
</div>
<div class="editor-label">
#Html.Label("Abilities")
</div>
<div class="editor-field">
#Html.ListBoxFor(model => model.Abilities, (ViewBag.AbilityID as MultiSelectList))
#Html.ValidationMessageFor(model => model.Abilities)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.RarityID, "Rarity")
</div>
<div class="editor-field">
#Html.DropDownList("RarityID", String.Empty)
#Html.ValidationMessageFor(model => model.RarityID)
</div>
// A lot more fields...
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
My DBContext:
public DbSet<Ability> Abilities { get; set; }
public DbSet<Rarity> Rarities { get; set; }
public DbSet<CardSet> CardSets { get; set; }
public DbSet<MainType> MainTypes { get; set; }
public DbSet<SubType> SubTypes { get; set; }
public DbSet<Card> Cards { get; set; }
public DbSet<CardAbility> CardAbilities { get; set; }
public class AbilitiesToCardsConfiguration : EntityTypeConfiguration<CardAbility>
{
internal AbilitiesToCardsConfiguration()
{
this.HasKey(p => new { p.AbilityID, p.CardID });
this.HasRequired(p => p.Ability)
.WithMany(p => p.Cards)
.HasForeignKey(p => p.AbilityID);
this.HasRequired(p => p.Card)
.WithMany(r => r.Abilities)
.HasForeignKey(p => p.CardID);
}
}
I have been working on this for about 3 days and have done a lot of trial and error from what I have read online. At this point, the create view does display a listbox that is pulling the titles from the Abilities table. When I try to save, I get a validation error "The value "1" is invalid.", where 1 is the ID for that ability. When debugging, I see that the modelstate is invalid and the error is
{System.InvalidOperationException: The parameter conversion from type 'System.String' to type 'MTG.Models.CardAbility' failed because no type converter can convert between these types.
at System.Web.Mvc.ValueProviderResult.ConvertSimpleType(CultureInfo culture, Object value, Type destinationType)
at System.Web.Mvc.ValueProviderResult.UnwrapPossibleArrayType(CultureInfo culture, Object value, Type destinationType)
at System.Web.Mvc.ValueProviderResult.ConvertTo(Type type, CultureInfo culture)
at System.Web.Mvc.DefaultModelBinder.ConvertProviderResult(ModelStateDictionary modelState, String modelStateKey, ValueProviderResult valueProviderResult, Type destinationType)}
I know it doesn't like the types and can't convert, but if I try anything else with the listboxfor helper it won't bring in the data and usually crashes before I even get to see the create page. Sorry this is so long, I just wanted to give all the information I could. :) Thank you for any help.
Generate a listbox for SelectedAbilities instead of Abilities:
#Html.ListBoxFor(model => model.SelectedAbilities , (ViewBag.AbilityID as MultiSelectList))
By the way you need to do the same for RarityID instead of Rarity, MainTypeID instead of MainType and etc.

DropDownList MVC returns null

I've encountered some problems using DropDownList in ASP.NET MVC lately.
I want to save value of selected item to member called Wydzialy.
Sorry for not translating some names, they doesn't matter I think :)
Here is what I have:
View:
<div class="form-group">
#Html.LabelFor(model => model.Wydzial, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(x => x.Wydzial, (List<SelectListItem>)ViewBag.Wydzialy)
</div>
</div>
Model:
public class Student
{
public int Id { get; set; }
public int NumerIndeksu { get; set; }
public string Imie { get; set; }
public string Nazwisko { get; set; }
public int Semestr { get; set; }
public virtual Wydzial Wydzial { get; set; }
}
Controller:
public ActionResult Create()
{
var wydzialy = db.Wydzialy.ToList();
var lista = wydzialy.Select(W => new SelectListItem()
{
Text = W.Nazwa
}).ToList();
ViewBag.Wydzialy = lista;
return View();
}
Your trying to bind the dropdown to a complex object. A <Select> only posts backs a value type (in your case the text of the selected option).
Either bind to a property of Wydzial
#Html.DropDownListFor(x => x.Wydzial.Nazwa, (List<SelectListItem>)ViewBag.Wydzialy)
or preferably use a view model that includes a property to bind to and the SelectList
public class StudentVM
{
public int Id { get; set; }
// Other properties used by the view
public string Wydzial { get; set; }
public SelectList Wydzialy { get; set; }
}
Controller
public ActionResult Create()
{
StudentVM model = new StudentVM();
model.Wydzialy = new SelectList(db.Wydzialy, "Nazwa", "Nazwa")
return View(model );
}
View
#model StudentVM
....
#Html.DropDownListFor(x => x.Wydzial, Model.Wydzialy)
Note you appear to be binding only to the Nazwa property of Wydzial. Typically ou would display a text property but bind to an ID property.

Create ActionResult for save throws error saying The model item passed into the dictionary is of type

Although this error is very common in the forum, but i am not able to understand how to fix it in my project. I am new to MVC framework.
View code:-
#model ClassifiedProject.Models.CreateAdvertVM
<div class="editor-label">#Html.LabelFor(model => model.AdvTitle) <i>(E.g. Old Samsung Galaxy Tab 2)</i></div>
<div class="editor-field">
#Html.EditorFor(model => model.AdvTitle)
#Html.ValidationMessageFor(model => model.AdvTitle)
</div>
<div class="editor-label">#Html.LabelFor(model => model.AdvDescription)</div>
<div class="editor-field">
#Html.TextAreaFor(model => model.AdvDescription)
#Html.ValidationMessageFor(model => model.AdvDescription)
</div>
<div class="editor-label">#Html.Label("Advertisement Category")</div>
<div class="editor-label">
#Html.DropDownListFor(model => model.SelectedCategoryId, Model.Categories, new { #class = "ddlcs" })
#Html.ValidationMessageFor(model => model.SelectedCategoryId)
</div>
<p><input type="submit" value="Save" /></p>
Controller code of Save button actionresult:-
[HttpPost]
public ActionResult Create(TR_ADVERTISEMENT tr_advert)
{
if (ModelState.IsValid)
{
tr_advert.CreatedDate = tr_advert.ModifiedDate = DateTime.Now;
if (tr_advert.IsPriceOnRequest)
{
tr_advert.CurrencyID = 0;
tr_advert.Price = 0;
}
db.ADVERTISEMENT.Add(tr_advert);
db.SaveChanges();
return RedirectToAction("Index");
}
Controller code for the form in render stage:-
// GET: /Advert/Create
public ActionResult Create()
{
var model = new CreateAdvertVM();
ViewBag.Message = "Post New Advertisement.";
////Render Category DDL
var cat = from s in db.CategoryDbSet
where s.IsActive == true
orderby s.CatName
select new { s.CatID, s.CatName };
var catListItems = cat.ToList().Select(c => new SelectListItem
{
Text = c.CatName,
Value = c.CatID.ToString()
}).ToList();
catListItems.Insert(0, new SelectListItem { Text = "[--Select the category--]", Value = "" });
model.Categories = catListItems;
return View(model);
ViewModel inherited from EF class:-
[NotMapped]
public class CreateAdvertVM : TR_ADVERTISEMENT
{
[DisplayName("Category")]
[Required]
public int? SelectedCategoryId { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
}
EF Model:-
public class TR_ADVERTISEMENT
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int AdvID { get; set; }
[Required]
[DisplayName("Sub Category")]
public int SubCatID { get; set; }
public int CurrencyID { get; set; }
[DisplayName("Price on request")]
public bool IsPriceOnRequest { get; set; }
[DisplayName("Posted Date")]
[DisplayFormat (DataFormatString="{0:dd-MM-yyyy}")]
public Nullable<System.DateTime> CreatedDate { get; set; }
public Nullable<System.DateTime> ModifiedDate { get; set; }
}
On the save button click, i have to save the data into the tr_advertisement table using the EF model.
Please suggest the solution to this problem.
It is the model type you are passing into your Create ActionMethod.
public ActionResult Create(TR_ADVERTISEMENT tr_advert)
should be
public ActionResult Create(CreateAdvertVM tr_advert)
I am assuming that if your model is not valid, you are passing it back further down in your action result (which you are not showing), such as
Return View(tr_advert)
But, you are passing the wrong model type at that point for that view.
EDIT
I would also update your view model so that instead of inheriting from the EF class, simply include the EF class as a property.
public class CreateAdvertVM
{
[DisplayName("Category")]
[Required]
public int? SelectedCategoryId { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
public TR_ADVERTISEMENT tr_advert{get;set;}
}
This will make it so that your save code in the Create method can still be used with only minor modifications
[HttpPost]
public ActionResult Create(CreateAdvertVM model)
{
if (ModelState.IsValid)
{
model.tr_advert.CreatedDate = model.tr_advert.ModifiedDate = DateTime.Now;
if (model.tr_advert.IsPriceOnRequest)
{
model.tr_advert.CurrencyID = 0;
model.tr_advert.Price = 0;
}
db.ADVERTISEMENT.Add(model.tr_advert);
db.SaveChanges();
return RedirectToAction("Index");
}

ASP.Net MVC 4 Update value linked to a foreign key column

I'm relatively new to MVC 4 and ASP.net in general. I'm trying to create a "room" with some properties, one of which queries from a list of statuses contained in another model. I have my classes set up as follows:
Room.cs
public class Room
{
[Key]
public Guid RoomId { get; set; }
[Required(ErrorMessage = "A Room Name is required")]
public string Name { get; set; }
public string Description { get; set; }
public virtual Status Status { get; set; }
[DisplayName("Created On")]
public DateTime? Created { get; set; }
[DisplayName("Last Modified")]
public DateTime? Modified { get; set; }
}
Status.cs
public class Status
{
[Key]
public int StatusId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
When I use the default scaffolding for the create action against the room, I am using the following code, which is working flawlessly, and properly applying the status of "New" to the newly created room.
// Post: /Room/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Room room)
{
if (ModelState.IsValid)
{
room.Created = DateTime.Now;
room.Status = db.Statuses.Single(s => s.Name == "New");
room.RoomId = Guid.NewGuid();
db.Rooms.Add(room);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(room);
}
When I attempt the same syntax for assigning room.Status on an edit action, in my case, automatically changing the status from "New" to "Discovery", the status values are never modified in the database. I am tracing the locals right up to the db.SaveChanges(); call, and I can see that the room.Status value is accurately reflecting the definition to the new status, but it's simply not updating on the back end. Here is my update code:
//Room/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Room room)
{
if (ModelState.IsValid)
{
room.Modified = DateTime.Now;
room.Status = db.Statuses.Single(s => s.Name == "Discovery");
db.Entry(room).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(room);
}
I'm at a loss as to how to change this value! My Edit view is as follows:
#model vwr.Cloud.Models.Room
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Room - #Html.ValueFor(model => model.Name)</legend>
#Html.HiddenFor(model => model.RoomId)
#Html.HiddenFor(model => model.Name)
#Html.HiddenFor(model => model.Created)
#Html.HiddenFor(model => model.Status.StatusId)
<div class="editor-label">
Room Status - #Html.ValueFor(model => model.Status.Name)
</div>
<div class="editor-label">
Created Date - #Html.ValueFor(model => model.Created)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Description)
#Html.ValidationMessageFor(model => model.Description)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
It took me WAY too long to figure this out, but I also needed to add a [ForeignKey] entry to my Room class that mapped to the Navigation Property. I can't say I yet understand HOW it works, suffice to say, it does :-).
Final room.cs
public class Room
{
[Key]
public Guid RoomId { get; set; }
[Required(ErrorMessage = "A Room Name is required")]
public string Name { get; set; }
public string Description { get; set; }
[ForeignKey("Status")]
public virtual int StatusId { get; set; }
public virtual Status Status { get; set; }
[DisplayName("Created On")]
public DateTime? Created { get; set; }
[DisplayName("Last Modified")]
public DateTime? Modified { get; set; }
}
public class Room
{
[Key]
public Guid RoomId { get; set; }
[Required(ErrorMessage = "A Room Name is required")]
public string Name { get; set; }
public string Description { get; set; }
[ForeignKey("Status")]
public virtual int StatusId { get; set; }
public virtual Status Status { get; set; }
[DisplayName("Created On")]
public DateTime? Created { get; set; }
[DisplayName("Last Modified")]
public DateTime? Mod

Resources