2

How to use a linq expression to use a ViewModel to get data from from one of it's domain models? When I try to get the inv_mast_uid that is associated to the item_id the user enters, I only get a 0 and not a unique integer like 10345. I do get all other necessary data from the ViewModel.

Here is an imaging showing my three tables: enter image description here

Here is my attempt to create a ViewModel to be used to add new alternate codes to items:

public class AlternateCodeViewModel
{


    [Key]
    [Column(Order = 0)]
    public int inv_mast_uid { get; set; }

    [Key]
    [Column(Order = 1)]
    [StringLength(50)]
    [Display(Name = "Alternate Code")]
    public string Alternate_Code_Item_ID { get; set; }

    [Key]
    [Column(Order = 2)]
    public int Alternate_Code_Brand_ID { get; set; }

    [Required]
    [StringLength(1)]
    [Display(Name = "Exact Flag")]
    public string Exact_Flag { get; set; }

    [Required]
    [StringLength(1)]
    [Display(Name = "Delete Flag")]
    public string Delete_Flag { get; set; }

    public string item_id { get; set; }


    public IEnumerable<web2_item_brands> web2_item_brands { get; set; }

    [ForeignKey("inv_mast_uid")]
    public inv_mast inv_mast { get; set; }

    public AlternateCodeViewModel()
    {
        Delete_Flag = "N";
        Exact_Flag = "Y";
    }
}

Here is my controller method:

[HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult AddAltCode(AlternateCodeViewModel avm)
    {
        if (ModelState.IsValid)
        {

            var newCode = new web2_item_alternate_code
            {
                inv_mast_uid = avm.inv_mast_uid,
                Alternate_Code_Item_ID = avm.Alternate_Code_Item_ID,
                Alternate_Code_Brand_ID = avm.Alternate_Code_Brand_ID,
                Delete_Flag = avm.Delete_Flag,
                Exact_Flag = avm.Exact_Flag
            };

            db.web2_item_alternate_code.Add(newCode);
            db.SaveChanges();
            return RedirectToAction("AltCodeIndex");
        }
        return View();
    }

If it helps here is an image showing my newCode object and it's missing inv_mast_uid property:

enter image description here

EDIT: As suggested, the following additional information has been added

My controller that initializes the view:

ublic ActionResult AddAltCode()
    {    
        ViewBag.brandsdd = new SelectList(db.web2_item_brands.OrderBy(x => x.brand_name), "item_brand_uid", "brand_name");
        return View();
    }

My view:

@using System.Web.Mvc.Html
@using System.Linq;
@model Non_P21_Quote_System_v1._0.ViewModels.AlternateCodeViewModel

@{
    ViewBag.Title = "AddAltCode";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Add Alternate Code</h2>


@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">

    <hr />
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })


    <div class="form-group">
        @Html.LabelFor(model => model.item_id, "Item ID", htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.item_id, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.item_id, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.web2_item_brands, "Brand Name", htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.DropDownList("Alternate_code_brand_id", new SelectList(ViewBag.brandsdd, "Value", "Text") , htmlAttributes: new { @class = "form-control" })
                @*@Html.ValidationMessageFor(model => model.web2_item_brands, "", new { @class = "text-danger" })*@
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Alternate_Code_Item_ID, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Alternate_Code_Item_ID, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Alternate_Code_Item_ID, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Add" class="btn btn-default" />
        </div>
    </div>
</div>

}

An image of my view: enter image description here

1
  • 1
    Please move your solution to an answer of its own, thank you. Commented May 23, 2018 at 14:39

2 Answers 2

1

As I see from your code, you couldn't add "inv_mast_uid" and "inv_mast inv_mast" as integer properties. You need add "inv_mst" and "web2_item_brands" as objects to "web2_alternate_code" and save them separately after populating. This is the same when you wand to read related object and you need call "include".

So the best approach is add those two objects in "web2_alternate_code" and instantiating them with "web2_alternate_code" constructor. After that you could add any data to those object on [HttpPost].

Sign up to request clarification or add additional context in comments.

3 Comments

I did have both inv_mast and web2_item_brands as part of my web2_alternate_code model as navigation properties. ex: public inv_mast inv_mast {get;set;}. I thought using a ViewModel would recognize this. Anyways I tried to instantiate a "web2_alternate_code" object in my Get method to be passed to the view to be used, but I am getting a "Cannot implicitly convert type IQueryable error. Here is my constructor: web2_item_alternate_code web2_item_alternate_code = db.web2_item_alternate_code.Include(w => w.inv_mast).Include(w=>w.web2_item_brands); I must be reading your suggestion incorrectly.
change to : public virtual inv_mast inv_mast { get; set; }; in constructor chang to: this.inv_mast = new HashSet<inv_mast>();
It works! I am very appreciative not only for helping me but for also teaching me something new. I didn't follow your directions exactly, but once I understood your logic I was able to get it to work. I am going to update my original post to show your solution so that others can use this. Thanks again.
0

If this is the result of a create operation as it appears to be the model will always return whatever you put in the model.

When you create the model to send to the create view, you must set the property inv_mast_uid at the time of creation.

In addition, the property must be included in the create view even if it is not going to be edited with a Html.HiddenFor<>. Otherwise, whatever goes into the model at the time it is sent to the view will be lost on the return.

The request parameter list will include only those properties you have explicitly indicated in the view like any html form.

The controller interface takes the form fields and tries to match them to the fields in the class indicated. It won't try to match them if the field does not exist on the create view page.

Perhaps including the code that initializes the information sent to the view would help in this case, and a copy of the view itself.

I would also remove the get/set from the IEnumerable in your model so that it will be treated as a field and not a property. It probably doesn't make any difference with Entity Framework, but the get/set properties should reflect only what is actually in the database unless you intend to try to serialize the list.

2 Comments

So is it not possible to let the user decide what item will have the new alternate code associated with in one view? I originally did have it where the user goes to one view to select the item and then has to go to another view to set an alternate code to it, but I just figured there has to be a way to do all of that with one view. To have the controller find the needed inv_mast_uid based on the item_id the view returns.
I really meant that you need to include the source code for the view, not the view itself.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.