0
votes

I am simply trying to bind a @Html.DropDownListFor to my view model and any time I go to add the new Product, I get the error:

"The parameter conversion from type 'System.String' to type 'SuperStockpile.Core.Models.Brand' failed because no type converter can convert between these types."

Base Entity

public abstract class BaseEntity
{
    public string Id { get; set; }
    [Display(Name = "Created At")]
    public DateTimeOffset CreatedAt { get; set; }

    public BaseEntity()
    {
        Id = Guid.NewGuid().ToString();
        CreatedAt = DateTime.Now;
    }
}

Brand Model

public class Brand : BaseEntity
{
    public string Name { get; set; }
}

View Model

public class ProductFormViewModel
{
    public Product Product { get; set; }
    public IEnumerable<Brand> Brands { get; set; }
}

Inventory Controller

public class InventoryController : Controller
{
    private readonly IRepository<Product> _productContext;
    private readonly IRepository<Brand> _brandContext;
    private readonly IRepository<Source> _sourceContext;
    public InventoryController(IRepository<Product> productContext, IRepository<Brand> brandContext, 
        IRepository<Source> sourceContext)
    {
        _productContext = productContext;
        _sourceContext = sourceContext;
        _brandContext = brandContext;
    }
    // GET: Inventory
    public ActionResult Index()
    {
        List<Product> Products = _productContext.Collection().ToList();
        return View(Products);
    }

    public ActionResult Create()
    {
        ProductFormViewModel product = new ProductFormViewModel
        {
            Product = new Product(),
            Brands = _brandContext.Collection().ToList(),
            Sources = _sourceContext.Collection().ToList()
        };
        return View(product);
    }
    [HttpPost]
    public ActionResult Create(ProductFormViewModel vm)
    {
        if (!ModelState.IsValid)
            return View("Create", vm);
        else
        {
            Product product = new Product
            {
                Brand = vm.Product.Brand,
                BrandId = vm.Product.BrandId,
                Comments = vm.Product.Comments,
                Cost = vm.Product.Cost,
                DiscountPercent = vm.Product.DiscountPercent,
                ItemCode = vm.Product.ItemCode,
                Source = vm.Product.Source,
                SourceId = vm.Product.SourceId,
                SKU = vm.Product.SKU,
                UPC = vm.Product.UPC
            };

            _productContext.Insert(product);
            _productContext.Commit();
            return RedirectToAction("Index");
        }
    }
}

View

@model SuperStockpile.Core.ViewModels.ProductFormViewModel

@{
    ViewBag.Title = "Create";
}

<h2>Add New Product</h2>


@using (Html.BeginForm("Create","Inventory")) 
{
    @Html.AntiForgeryToken()
    
<div class="form-horizontal">
    <hr />
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
    <div class="form-group">
        @Html.LabelFor(model => model.Product.SKU)
        @Html.EditorFor(model => model.Product.SKU, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.Product.SKU)
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Product.UPC)
        @Html.EditorFor(model => model.Product.UPC, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.Product.UPC)
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Product.ItemCode)
        @Html.EditorFor(model => model.Product.ItemCode, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.Product.ItemCode)
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Product.Cost)
        @Html.EditorFor(model => model.Product.Cost, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.Product.Cost)
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Product.DiscountPercent)
        @Html.EditorFor(model => model.Product.DiscountPercent, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.Product.DiscountPercent)
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Product.Comments)
        @Html.EditorFor(model => model.Product.Comments, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.Product.Comments)
    </div>
    <div class="form-group">
        @Html.LabelFor(model => model.Product.BrandId)
        @Html.DropDownListFor(model => model.Product.Brand, new SelectList(Model.Brands, "Id", "Name"),"Select Brand", new { @class = "form-control" })
        @Html.ValidationMessageFor(model => model.Product.BrandId)
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Save" class="btn btn-default" />
        </div>
    </div>
</div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

I am not sure how to properly bind the drop down list to my view models Brand property. Any help or explanation on why this is happening would be great!

Thank you for looking.

1

1 Answers

1
votes

Don't bind to Brand class as a whole, bind just to Brand.Id, later in controller get remaining details for Brand before saving to database.

@Html.DropDownListFor(model => model.Product.Brand.Id, new SelectList(Model.Brands, "Id", "Name"),"Select Brand", new { @class = "form-control" })