0

I know that the question was asked and answered many times, but unfortunately no one of the answers helped me.

I have tree POCO models, which are Pharmacy, Address and Company gathered together into a ViewModel PharmacyVM:

public class PharmacyVM
{
    public Pharmacy pharmacyProp { get; set; }
    public Address addressProp { get; set; }
    public Company companyProp { get; set; }
    public int CityId { get; set; }

    public PharmacyVM()
    {
        pharmacyProp = new Pharmacy();
        addressProp = new Address();
        companyProp = new Company();
    }
}

Don't laugh at the properties names; at the start, they had been normal (Address, Company and Pharmacy) I changed them according to one of the lots of answers in here, but... it didn't help :(

In the Get action of the Create method I'm trying to manually create the PharmacyVM object and pass it to the view:

public ActionResult Create()
{
    ViewBag.CityId = new SelectList(db.Cities, "Id", "Name");
    ViewBag.CompanyId = new SelectList(db.Companies, "Id", "Name");
    ViewBag.AddressId = new SelectList(db.Addresses, "Id", "Name");
    ViewBag.CityId = new SelectList(db.Cities, "Id", "Name");
    ViewBag.RegionId = new SelectList(db.Regions, "Id", "Name");
    ViewBag.DistrictId = new SelectList(db.Districts, "Id", "Name");
    ViewBag.MicrodistrictId = new SelectList(db.Microdistricts, "Id", "Name");
    ViewBag.StreetId = new SelectList(db.Streets, "Id", "Name");
    ViewBag.VillageId = new SelectList(db.Villages, "Id", "Name");
    var pharmacyVM = new PharmacyVM();
    return View(pharmacyVM);
}

There is a standard Razor code in the view:

@model MEDONET.Models.PharmacyVM
@{
    ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm("Create", "Pharmacies", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.AntiForgeryToken()
    <div class="form-horizontal">
        <h4>pharmacyProp</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })

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

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

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

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

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

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

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

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

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

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

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

        <div class="form-group">
            @Html.LabelFor(model => model.pharmacyProp.LargeImage, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                <input type="file" name="LargeImageFile" required />
            </div>
        </div>



        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}
<div> @Html.ActionLink("Back to List", "Index")</div>
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

And then in the Post action of the Create method, I'm trying to create b and c variables:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(PharmacyVM model, HttpPostedFileBase LargeImageFile)
{
    if (ModelState.IsValid)
    {
        string LargeImageFileName = Path.GetFileNameWithoutExtension(LargeImageFile.FileName);
        string LargeImageExtansion = Path.GetExtension(LargeImageFile.FileName);

        LargeImageFileName = LargeImageFileName + DateTime.Now.ToString("yymmssfff") + LargeImageExtansion;
        LargeImageFileName = Path.Combine(Server.MapPath("~/Images/Pharmacy/Banners/"), LargeImageFileName);
        int b = model.CityId;

        int c = model.addressProp.RegionId.Value;
        //Address address = new Address()
        //{
        //    Id = 12,//db.Addresses.AsEnumerable().Last().Id + 1,
        //    RegionId = PharmacyVM.Address.RegionId,
        //    DistrictId = PharmacyVM.Address.DistrictId,
        //    CityId = PharmacyVM.Address.CityId,
        //    MicrodistrictId = PharmacyVM.Address.MicrodistrictId,
        //    StreetId = PharmacyVM.Address.StreetId,
        //    VillageId = PharmacyVM.Address.VillageId,
        //    Building = PharmacyVM.Address.Building,
        //    Cab = PharmacyVM.Address.Cab
        //};
        //Address address = new Address
        //{
        //    Id = 12,//db.Addresses.AsEnumerable().Last().Id + 1,
        //    RegionId = 1,
        //    DistrictId = 1,
        //    CityId = 1,
        //    MicrodistrictId = 1,
        //    StreetId = 1,
        //    VillageId = 1,
        //    Building = "1",
        //    Cab = "1"
        //};
        //db.Addresses.Add(address);
        db.SaveChanges();
        var pharmacy = new Pharmacy
        {
            Name = model.pharmacyProp.Name,
            //AddressId = address.Id,
            IsGov = model.pharmacyProp.IsGov,
            CompanyId = model.pharmacyProp.CompanyId,
            LargeImage = "~/Images/Pharmacy/Banners/" + LargeImageFileName
        };
        LargeImageFile.SaveAs(LargeImageFileName);
        db.Pharmacies.Add(pharmacy);
        db.SaveChanges();
        ModelState.Clear();
        return RedirectToAction("Index");
    }

}

Unlike first variable b, the second one c is gonna be null because the addressProp property is null.

So why is it so strange? How can I use ViewModel without duplicating original model's fields?

Vaibhav Bhavsar
  • 432
  • 4
  • 12
  • 1
    There is so much bad code here it hard to know where to begin. View model **DO NOT** contain data models. They contain the properties of various models you need in the view. And when using a view model you will **NEVER** use `ViewBag` (your view model will contain `IEnumerable` properties for your dropdownlists). And you are not creating any form controls related to your `addressProp` model because your naming then `VillageId` and your `PharmacyVM` model does not contain a property named `VillageId` (but your `addressProp` model does) –  Nov 21 '17 at 02:23
  • Suggest your start by looking at the code in [this Q/A](https://stackoverflow.com/questions/34366305/the-viewdata-item-that-has-the-key-xxx-is-of-type-system-int32-but-must-be-o) to understand how to correctly define your view model and generate a dropdownlist in a view –  Nov 21 '17 at 02:24
  • Could you give me a little example? I just wanna use the three fields represent three POCO classes in my view model. – Azizjan Hamidovich Ayupov Nov 21 '17 at 11:03
  • The link I gave you contains an example. Your view model will contain properties (say) `int? CompanyId` and `IEnumerable CompanyList` and then you replace `@Html.DropDownList("CompanyId", null, ...)` with `@Html.DropDownListFor(m => m.CompanyId, Model.CompanyList, ...)`. And it will contain (say) `int? Microdistrict` and `IEnumerable MicrodistrictList` and you will replace `@Html.DropDownList("MicrodistrictId", null, ... )` with `@Html.DropDownListFor(m => m.Microdistrict, Model.IEnumerable, ...)` and ditto for all the other properties –  Nov 21 '17 at 11:13
  • It will also contain a property `HttpPostedFileBase LargeImageFile` and in the view `@Html.TextBoxFor(m => m.LargeImageFile, new { type = "file" })` for strongly binding to the file input –  Nov 21 '17 at 11:15
  • Also refer [What is ViewModel in MVC?](https://stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc) –  Nov 21 '17 at 11:16
  • But can't I just use the three properties from POCO class without duplicating their original properties? – Azizjan Hamidovich Ayupov Nov 21 '17 at 11:44
  • You could if your happy to write bad code that will cause your endless other problems. –  Nov 21 '17 at 11:45
  • Hm... Ok. Thank you very much! – Azizjan Hamidovich Ayupov Nov 21 '17 at 12:09

1 Answers1

0

why are you use

int b= model.addressProp.RegionId.Value

instead of

int b=model.addressProp.RegionId

Even for your good cording the best and good way is remove all View bag and Add all View bag properties to PharmacyVM Class Dont use two properties for view binding

Example

 public class PharmacyVM
    {
        public Pharmacy pharmacyProp { get; set; }
        public Address addressProp { get; set; }
        public Company companyProp { get; set; }
        public int CityId { get; set; }

        public SelectList CityIdList { get; set; }     

        public PharmacyVM()
        {
            pharmacyProp = new Pharmacy();
            addressProp = new Address();
            companyProp = new Company();
            CityIdList =new SelectList(db.Cities, "Id", "Name");
        }
    }

    public ActionResult Create()
        { 
            var pharmacyVM = new PharmacyVM();
            return View(pharmacyVM);
        }

@model PharmacyVM
@using (Html.BeginForm())
{
    @Html.HiddenFor(m => m.CityId )

    <div class="editor-label">
        @Html.LabelFor(m => m.Name)
    </div>
    <div class="editor-field">
        @Html.EditorFor(m => m.Name)
        @Html.ValidationMessageFor(m => m.Name)
    </div> 

    <button type="submit">Create</button>
}

       [HttpPost]
        public ActionResult Create(PharmacyVM model)
        {
            int c = model.addressProp
            return View(viewModel);
        }

More Information

Floxy
  • 117
  • 2
  • 10
  • My all properties (addressProp, pharmacyProp and companyProp) are empty (null). Could you please give me a little example – Azizjan Hamidovich Ayupov Nov 21 '17 at 04:48
  • i changed my Answer – Floxy Nov 21 '17 at 05:10
  • Thank you. But it is not what I am expecting. I just wanna use pharmacyProp, addressProp,companyProp. Field CityId is actually located in the Address class. Since they are empty I just have tried to create the field in the ViewModel. But I do not think it is a good idea to duplicate all the fields from original classes. – Azizjan Hamidovich Ayupov Nov 21 '17 at 11:00