Click here to Skip to main content
15,883,745 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I am new to MVC and would appreciate any advice. I have several models/tables that work together which I made because EF wasn't cooperating. 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 an another table, while saving the primary entry.

My models:


C#
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:

C#
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:

C#
@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:

C#
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
C#
{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.
Posted
Comments
Mostafa Asaduzzaman 11-Jul-15 1:31am    
Why these are with virtual keyword?
public virtual int AbilityID { get; set; }
public virtual string Title { get; set; }

are they not primitive data type?

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900