How to Convert Model to ViewModel in asp.net mvc - asp.net-mvc

Here is my code:
public List<DiscountVM> GetAllDiscounts(long CompanyID)
{
return _context.Discounts.Where(x => x.IsActive == true && x.CompanyID == CompanyID).Select(s => new DiscountVM()
{
DiscountID = s.DiscountID,
LocationID = s.LocationID,
CompanyID = s.CompanyID,
DiscountName = s.DiscountName,
DiscountValue = s.DiscountValue,
DiscountType = s.DiscountType,
ServiceSale = s.ServiceSale,
ProductSale = s.ProductSale,
VoucherSale = s.VoucherSale,
IsActive = s.IsActive,
AddDate = s.AddDate,
AddedByID = s.AddedByID,
UpdateDate = s.UpdateDate,
UpdatedByID = s.UpdatedByID,
}).ToList();
}
I want to convert Model to View model because if i am not converting then i have to fill all the values.
The code is working fine if I fill all the values. I trying to find a way in which I can easily convert the model to view model then there would be no need to fill all the values.

well this can be done some different way but easiest way for you that change you view model a little bit by adding you db model as property of your view model like this
public class DiscountVM
{
public Discounts DiscountsList{ get; set; }
// Other property
}
and return like this
public List<DiscountVM> GetAllDiscounts(long CompanyID)
{
return _context.Discounts.Where(x => x.IsActive == true && x.CompanyID ==CompanyID).Select(s => new DiscountVM()
{
DiscountsList=s
}).ToList();
}

Have you looked into AutoMapper to help you with that?

Related

object reference not set in combobox with two model view razor

I tried to create more than one combobox, but model to view combobox is different. then I tried to combine two models in one class, but I get an error "object reference not set to an instance of an object" when I click on the link to go to that page.
please help me to fix the matter. thank you, sorry if I mess sentence.
This piece from some source code :
controller partial combobox ,
[ValidateInput(false)]
public ActionResult cbPartialCategoryDetail(string group)
{
SalesMonitoringDAC modelSM = new SalesMonitoringDAC();
MPMPRODUCTGROUPLINE item = new MPMPRODUCTGROUPLINE();
item.GROUPID = group;
List<string> mpmDetailCat = modelSM.GetProductGroupDetail(group);
return PartialView("_cbPartialCategoryDetail", mpmDetailCat);
}
and this is code combobox partial
#model DIS_iDealer.Models.SalesMonitoringModel
#Html.DevExpress().ComboBoxFor(m => m.mpmGroupLine.DESCRIPTION, settings =>
{
settings.Name = "Desc_ID_CB";
settings.Properties.IncrementalFilteringMode = IncrementalFilteringMode.Contains;
settings.Properties.DropDownStyle = DropDownStyle.DropDownList;
settings.CallbackRouteValues = new { Controller = "Report", Action = "cbPartialCategoryDetail" };
settings.Properties.CallbackPageSize = 50;
settings.Properties.ValueField = "DESCRIPTION";
settings.Properties.TextField = "DESCRIPTION";
settings.Properties.ValueType = typeof(string);
settings.Width = 100;
settings.Properties.DropDownWidth = 100;
settings.SelectedIndex = 0;
settings.Properties.ClientSideEvents.BeginCallback = "function(s, e) { e.customArgs['GroupId'] = Category_Id_CB.GetValue(); }";
settings.Properties.ClientSideEvents.SelectedIndexChanged = "OnInitDetailCategory";
settings.Properties.ClientSideEvents.Init = "OnInisialDetailCategory";
settings.Properties.ValidationSettings.ErrorTextPosition = ErrorTextPosition.Right;
settings.Properties.ValidationSettings.ErrorDisplayMode = ErrorDisplayMode.ImageWithText;
settings.Properties.ValidationSettings.Display = Display.Dynamic;
settings.Enabled = true;
settings.ShowModelErrors = true;
//}).BindList(ViewBag.DetailCategory).GetHtml()
}).BindList((new DIS_iDealer.DataAccess.SalesMonitoringDAC()).GetProductGroupDetail(Model.mpmGroupLine.GROUPID)).GetHtml()
this is class two combine the two model
namespace DIS_iDealer.Models
{
public class SalesMonitoringModel
{
public MPMPRODUCTGROUPLINE mpmGroupLine { get; set; }
public MPMDataDealer mpmDataDealer { get; set; }
public SalesMonitoringModel(MPMPRODUCTGROUPLINE _mpmGroupLine, MPMDataDealer _mpmDataDealer) {
mpmGroupLine = _mpmGroupLine;
mpmDataDealer = _mpmDataDealer;
}
}
}
Isn't that really strange. In your action method you are returning a List<string> as seen below
List<string> mpmDetailCat = modelSM.GetProductGroupDetail(group);
return PartialView("_cbPartialCategoryDetail", mpmDetailCat);
Whereas in your partial view you are expecting a model of type SalesMonitoringModel and that's the source of this error. I am not sure what you are exactly trying to achieve and so can't help beyond this
#model DIS_iDealer.Models.SalesMonitoringModel

The neat and simple way for multiple models in a view

What can be simplest way for having rendered in a view information from multiple models. I use ViewModel in some scenarios (in particular when models are not related directly), but now I want to made a kind of dashboard for the current user. So apart from AspNetUsers model I have for example several models (e.g. Orders, OperationJournal, Jobs etc.) that in terms of entity have each a foreign key on UserID.
I made a ViewModel such:
namespace JobShop.Models
{
class QuickProfileVM
{
public IEnumerable<Jobs> Jobs { get; set; }
public IEnumerable<AspNetUsers> AspNetUsers { get; set; }
public IEnumerable<CreditJournal> CreditJournal { get; set; }
public IEnumerable<CandidateReview> CandidateReview { get; set; }
}
}
(since the base models that I need, are done by EF they have all about relations between entities) but it seems to me that is not enough. I am not able to view both the current user profile (so one record) and it's details (more than one record and more than one model).
I have try with Partial View, both with own controller or with actions in Dashboard View controller.
As an example an ActionResult that now I play with:
public ActionResult QuickProfile()
{
var QuickProfile = new QuickProfileVM();
var AspNetUsers = new AspNetUsers();
if (User.Identity.IsAuthenticated)
{
var CurrentUser = User.Identity.GetUserId();//UserManager.FindById(User.Identity.GetUserId());
var TheUser = db.AspNetUsers.Where(u => u.Id == CurrentUser)
.Select(u => new
{
ID = u.Id,
Email = u.Email,
PhoneNumber = u.PhoneNumber,
Companyname = u.Companyname,
Address = u.Address,
ZIP = u.ZIP,
City = u.City,
Country = u.Country,
Website = u.Website,
Facebook = u.Facebook,
Twitter = u.Twitter,
GooglePlus = u.GooglePlus,
Dribble = u.Dribble,
BirthDate = u.BirthDate,
Username = u.UserName,
Surrname = u.Surname,
Name = u.Name,
Role = u.Role,
ThumbURL = u.ThumbURL,
CreditBalance = u.CreditBalance
}).Single();
var TheJournal = db.CreditJournal.Where(tj => tj.UseBy == CurrentUser)
.Select(tj => new
{
IdJournal = tj.IdJournal,
Operation = tj.Operation,
CvID = tj.CvID,
JobID = tj.JobID,
CreditConsumed = tj.CreditConsumed,
UseDate = tj.UseDate,
UseBy = tj.UseBy
}).ToList();
//similar for Jobs and CandidateReview
//
var UserId = TheUser.ID;
var username = TheUser.Username;
var role = TheUser.Role;
var InitialCredit = TheUser.CreditBalance;
AspNetUsers.UserName = TheUser.Username;
AspNetUsers.Companyname = TheUser.Companyname;
AspNetUsers.Surname = TheUser.Surrname;
AspNetUsers.Name = TheUser.Name;
AspNetUsers.ThumbURL = TheUser.ThumbURL;
AspNetUsers.CreditBalance = InitialCredit;
//I put this to ilustrates what I have accesible for example
//about CreditJournal: only methods, not properties
QuickProfile.CreditJournal.AsEnumerable();
var id = CurrentUser;
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
AspNetUsers aspNetUsers = db.AspNetUsers.Find(id);
if (aspNetUsers == null)
{
return HttpNotFound();
}
}
return View(AspNetUsers);
//Disbled since at this stage is not usefull
//return View(QuickProfile);
//return View();
}
I suggest you consider using Html.RenderAction in your view. For example, say your main dashboard is this:
#{
ViewBag.Title = "title";
}
<h2>Multiple Models</h2>
#{ Html.RenderAction("GetData", "Foo"); }
You can use Html.RenderAction to call FooController.GetData()
public class FooController : Controller
{
public ActionResult GetData()
{
var viewModel = new FooViewModel();
viewModel.TimeStamp = DateTime.UtcNow;
return View(viewModel);
}
}
So rather than having one viewmodel with lots of other viewmodels attached as properties, you can split up the rendering of the dashboard view.
Overall this should makes things easier for you - I've used this approach in the past and have found it reduces complexity.

List of class properties

I have ASP.NET MVC 4 application with one view model class and about 20 views representing this view model. This views differs only by fields which user can edit. I want to merge all that views to one and define list of properties available to editing in strongly-typed manner. Ideally, I want something like this:
// Action
public ActionResult EditAsEngineer(int id)
{
//...
viewModel.PropertiesToChange = new List<???>()
{
v => v.LotNumber,
v => v.ShippingDate,
v => v.Commentary
};
return View(viewModel);
}
// View
if (#Model.PropertiesToChange.Contains(v => v.LotNumber)
{
#Html.TextBoxFor(m => m.LotNumber)
}
else
{
#Model.LotNumber
}
Is it possible to do something like this? Or is there a better solution?
Thank you.
Why note something like this (its pseudo code)
public class Prop{
string PropertyName {get;set;}
bool PropertyEditable {get;set;}
}
public ActionResult EditAsEngineer(int id)
{
viewModel.PropertiesToChange = new List<Prop>()
{
new Prop{PropertyName = LotNumber, PropertyEditable = true}
};
return View(viewModel);
}
#foreach (var pin Model.PropertiesToChange)
{
if(p.PropertyEditable){
#Html.TextBoxFor(p)
}else{
#Html.DisplayFor(p)
}
}
This will solve HALF of your problem. You will also need to create a IEqualityComparer<Expression> for your code to work (the default is to check for ref-equals).
return from p in typeof(T).GetProperties()
let param = System.Linq.Expressions.Expression.Parameter(typeof(T), "x")
let propExp = System.Linq.Expressions.Expression.Property(param, p)
let cast = System.Linq.Expressions.Expression.Convert(propExp, typeof(object))
let displayAttribute = p.CustomAttributes.OfType<System.ComponentModel.DataAnnotations.DisplayAttribute>()
.Select(x => x.Order).DefaultIfEmpty(int.MaxValue).FirstOrDefault()
orderby displayAttribute
select System.Linq.Expressions.Expression.Lambda<Func<T, object>>(cast, new [] {param});
This will list out ALL the properties for T. You would also probabily want to use Expression<Func<T, object>> as the type for defining your list of properties.
This will allow you to create a generic view over all properties.
Also you will want to wrap this in some kind of a cache, as this code is SLOW.

Passing query data from controller to view

I have been stuck on this problem for too long and would love some help.
On a view people can select two items from two radiobutton lists which returns via a FormMethod.Get to the Index event in HomeController.
These 2 values, 'parts and 'use' are queried to return a result and its passed back to the view via a viewbag. However the viewbag returns a line like { Item = Kona, Price = 400.0000, Quantity = 2 } in the view.
Whereas I want to return each item such as item.Item, Item.Price so I can use them individually.
I have tried everything I can find to no avail.
Anonymous classes items also throw red errors
View
foreach(var item in ViewBag.getstock)
{ //Show it and then make a new line with the <BR/>
#item < br / >
//{ Item = Kona, Price = 400.0000, Quantity = 2 }
}
HomeController
public ActionResult Index()
{
//this returns the entire query string
ViewBag.querystring = Request.QueryString;
//if any keys are in the url from the view
if (Request.QueryString.HasKeys())
{
//extract them out so that you can use them
//key = the name such as Part or Use it goes Key & Value this is passed to a Viewbag
//get(o) is getting the value at place 0, the first value in the url
ViewBag.querystringvalue0 = Request.QueryString.Get(0);
ViewBag.querystringvalue1 = Request.QueryString.Get(1);
}
//if there is any query string
if (Request.QueryString.HasKeys())
{
//pass the data to a couple of variables,
var parts = Request.QueryString.Get(0);
var use = Request.QueryString.Get(1);
//put them in a new query and return the results
ViewBag.getstock = from p in Bikeshopdb.Stocks
where p.PartName == parts && (p.Road == use || p.Mtn == use || p.Hybrid == use) select new
{
p.Item, p.Price, p.Quantity
};
}
return View(Bikeshopdb.Stocks.ToList());
Use a ViewModel class to hold the query results and pass back to the view. For example:
HomeController
public class MatchingStock()
{
public int ID { get; set; }
public string Item { get; set; }
public int Price { get; set; }
public int Quantity { get; set; }
}
public ActionResult Index()
{
//...
var list =
(from p in Bikeshopdb.Stocks
where p.PartName == parts &&
(p.Road == use || p.Mtn == use || p.Hybrid == use)
select new MatchingStock() {
ID = p.ID,
Item = p.Item,
Price = p.Price,
Quantity = p.Quantity}).ToList();
ViewBag.getstock = list;
//...
}
View
#foreach (var item in (List<MatchingStock>)ViewBag.getstock)
{
#item.Item #item.Price #item.Quantity
<br />
}

two models in a view - not working for me

I have created an entity data model from my database. however in certain areas of the application i need to pass two models. thus i create a third model which has as properties the objects of each required model.
In the scenario, i want to use one model just to show some data to the user and the other is to be populated by the user using form elements. therefore, i create a constructor in my custom model to populate it. here's the code:
THE CUSTOM MODEL
public class ordersModel
{
public ordersModel(order or)
{
this.prods = new order_products();
this.new_order = new order();
this.new_order.customer_id = or.customer_id;
this.new_order.my_id = or.my_id;
this.new_order.my_order_id = or.my_order_id;
this.new_order.order_date = or.order_date;
this.new_order.order_status_id = or.order_status_id;
}
public order new_order { get; set; }
public order_products prods { get; set; }
}
IT IS USED IN THE CONTROLLER AS FOLLOWS:
public ActionResult Create()
{
order or = new order();
// Store logged-in user's company id in Session
//or.my_id = Session["my_id"].ToString();
//do something to allow user to select customer, maybe use ajax
or.customer_id = "123";
or.order_amount = 0;
or.my_id = "74973f59-1f6c-4f4c-b013-809fa607cad5";
// display date picker to select date
or.order_date = DateTime.Now.Date;
// fetch statuses from database and show in select list box
or.order_status_id = 1;
return View(or);
}
//
// POST: /Orders/Create
[HttpPost]
public ActionResult Create(order or)
{
using (invoicrEntities db = new invoicrEntities())
{
var temp = db.last_order_number.SingleOrDefault(p => p.my_id == or.my_id);
if (temp != null)
{
or.my_order_id = temp.my_order_id + 1;
if (ModelState.IsValid)
{
ordersModel ord = new ordersModel(or);
db.orders.AddObject(or);
temp.my_order_id = temp.my_order_id + 1;
//TempData["my_order_id"] = or.my_order_id;
db.SaveChanges();
return RedirectToAction("AddProducts", ord);
//return RedirectToAction("AddProducts", new { id = or.my_order_id });
}
return View(or);
}
return RedirectToAction("someErrorPageDueToCreateOrder");
}
}
public ActionResult AddProducts()
{
using (invoicrEntities db = new invoicrEntities())
{
//string my_id = TempData["my_id"].ToString();
//string my_order_id = TempData["my_order_id"].ToString();
string my_id = "74973f59-1f6c-4f4c-b013-809fa607cad5";
int my_order_id = 1;
//Int64 my_order_id = Convert.ToInt64(RouteData.Values["order_id"]);
// Display this list in the view
var prods = db.order_products.Where(p => p.my_id == my_id).Where(p => p.my_order_id == my_order_id).ToList();
var or = db.orders.Where(p => p.my_id == my_id).Where(p => p.my_order_id == my_order_id).ToList();
if (or.Count == 1)
{
//ViewData["name"] = "sameer";
ViewData["products_in_list"] = prods;
ViewData["order"] = or[0];
return View();
}
return RedirectToAction("someErrorPageDueToAddProducts");
}
}
[HttpPost]
public ActionResult AddProducts(order_products prod)
{
prod.my_id = "74973f59-1f6c-4f4c-b013-809fa607cad5";
// find a way to get the my_order_id
prod.my_order_id = 1;
return View();
}
THIS ALL WORKS OUT WELL, UNTIL IN THE "ADDPRODUCTS" VIEW:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<invoicr.Models.ordersModel>" %>
AddProducts
<h2>AddProducts</h2>
<%: Model.new_order.my_id %>
the above statement gives an error
Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
what am i doing wrong here?
You seem to be passing the wrong model when redisplaying your Create view.
Try passing the ord instance which is of type ordersModel and which is what your view is strongly typed to:
public ActionResult Create(order or)
{
using (invoicrEntities db = new invoicrEntities())
{
var temp = db.last_order_number.SingleOrDefault(p => p.my_id == or.my_id);
if (temp != null)
{
or.my_order_id = temp.my_order_id + 1;
ordersModel ord = new ordersModel(or);
if (ModelState.IsValid)
{
db.orders.AddObject(or);
temp.my_order_id = temp.my_order_id + 1;
db.SaveChanges();
return RedirectToAction("AddProducts", ord);
}
return View(ord);
}
return RedirectToAction("someErrorPageDueToCreateOrder");
}
}
UPDATE:
Now that you have shown your AddProducts action you are not passing any model to the view although your view expects an ordersModel instance. So don't just return View();. You need to pass an instance of ordersModel:
if (or.Count == 1)
{
ViewData["products_in_list"] = prods;
ViewData["order"] = or[0];
ordersModel ord = new ordersModel(or[0]);
return View(ord);
}

Resources