I start studying asp.net MVC and I am confused about sending data to VIEW. I have one class Dispatch:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Logistic.Models
{
public class Dispatch
{
public int DispatchId { get; set; }
public int TrackingId { get; set; }
public int CustomerId { get; set; }
public int RecipientId { get; set; }
public int CityId { get; set; }
public DateTime Delivered { get; set; }
public string Notes { get; set; }
}
}
Another class City:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Logistic.Models
{
public class City
{
public int CityId { get; set; }
public string Name { get; set; }
}
}
A class Client:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Logistic.Models
{
public class Client
{
public int ClientId { get; set; }
public string Name { get; set; }
}
}
From my class Dispatch, CustomerId and RecipientId will be related to the class Client; CityId related to City.
I create my context class:
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Linq;
using System.Web;
namespace Logistic.Models
{
public class LogisticContext : DbContext
{
public DbSet<Dispatch> Dispatches { get; set; }
public DbSet<Client> Clients { get; set; }
public DbSet<Driver> Drivers { get; set; }
public DbSet<City> Cities { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
}
And here is my Controller:
using Logistic.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Logistic.Controllers
{
public class HomeController : Controller
{
private LogisticContext db = new LogisticContext();
public ActionResult Dispatch()
{
var dispatches = db.Dispatches.ToList();
return View(dispatches);
}
}
}
The problem is that in my View class I do not know how to display the Customer Name, Recipient Name, and City Name. I only can display the CustomerId, RecipientId, and CityId.
View:
#model IEnumerable<Logistic.Models.Dispatch>
#{
ViewBag.Title = "Dispatch";
}
<h2>Dispatch</h2>
#foreach(var item in Model)
{
<h2></h2>
}
Thanks
If you have relationships in place...
If you already have defined relationships between these properties, you can generally use the Include() method to pull related entities in as seen below :
// Pull all of the dispatches and their related cities
var dispatchesWithCities = db.Dispatches.Include("Cities")
.ToList();
If you do this and have the proper relationships, you would then be able to iterate through and access the item.City.Name, however it doesn't look like that is the case in your current scenario.
Without relationships...
If you don't have these "hard" relationships in place, you can still perform a few database queries to pull the properties you need and construct a ViewModel, but it wouldn't be pretty with so many results :
public class DispatchViewModel
{
public Dispatch Dispatch { get; set; }
public City City { get; set; }
public Client Client { get; set; }
public Driver Driver { get; set; }
}
And then use each of your individual Dispatch objects and map them to their related properties :
// Build your Dispatches with related information
var dispatchModels = db.Dispatches.AsEnumerable()
.Select(d => new DispatchViewModel()
{
Dispatch = d,
City = db.Cities.FirstOrDefault(c => c.CityId == d.CityId),
Client = db.Clients.FirstOrDefault(c => c.ClientId == d.CustomerId),
...
});
At this point you can simply iterate through the collection and output them by referencing the iterator in the loop :
#foreach(var item in Model)
{
<h2>#item.Dispatch.DispatchId</h2>
<ul>
<li>
<b>City</b>: #item.City.Name
<!-- Other stuff here -->
</li>
</ul>
}
You can use view model approach to send data from mutliple views to controller. Here is an example:
http://rachelappel.com/use-viewmodels-to-manage-data-amp-organize-code-in-asp-net-mvc-applications/
Related
Here is my model and View info to capture a single value in a Razor page into a variable.
I get this error when trying to use this IEnumerable, but before with without IEnumerable this works without any errors.
Here is my program that works fine without IEnumerable, but how do you access all the tables that have relations together this way?:
GlobalCommandCenter
View showing Model connection using IEnumerable:
#model IEnumerable<OperationsCommandCenter.Models.CommandCenterModel>
Error in View that I am getting with IEnumberable in Razor Page:
Model:
using ClassLibraryDAL.DAL;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace OperationsCommandCenter.Models
{
public class CommandCenterModel
{
public List<DimLocation> LocationDatas { get; set; }
public List<DimLocation> DimLocations { get; set; }
public List<DimProductInventory> DimProducts { get; set; }
public List<SelectListItem> Country { get; set; }
public List<SelectListItem> Continent { get; set; }
public List<SelectListItem> Product { get; set; }
public List<SelectListItem> FactInventory { get; set; }
public List<SelectListItem> query { get; set; }
public string SectionCity { get; set; }
}
}
Perhaps I am misunderstanding how a ViewModel works. A ViewModel is used to display custom data to the user without having to use the full Model. So you would use only the database fields that you want displayed. I have a ViewModel that looks like this
using PagedList;
using Resolutions.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Web;
namespace Resolutions.ViewModels
{
public class SearchPagingViewModels
{
public int ObjectID { get; set; } //Database Primary Key
[DisplayName("Resolution Year")]
public string ResolutionYear { get; set; } //Year of the Resolution
[DisplayName("Resolution Number")]
public string ResolutionNumber { get; set; } //Number of the Resolution
[DisplayName("Resolution Text")]
public string ResolutionText { get; set; } //OCR'd text for the Resolution
[DisplayName("Resolution Date")]
public Nullable<System.DateTime> ResolutionDate { get; set; } //Date of the Resolution
public int? PageNumber { get; set; }
public bool? IsResYearChecked { get; set; }
public bool? IsResNumChecked { get; set; }
public bool? IsKeywordChecked { get; set; }
public string SearchKeyword { get; set; }
}
}
I want to store the value of a checkbox from the client side into my object and use the boolean to be able to filter and page through the results. However, if I use my current ViewModel I get 25 checkboxes when I try to access the object's boolean; As I can only seem to access the value of the checkbox within a foreach loop that I am using to display each item. I am currently pulling information from a database and then storing the database results into a list of the ViewModel.
This is my controller:
using PagedList;
using Resolutions.Models;
using Resolutions.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Resolutions.Controllers
{
public class SearchPagingController : Controller
{
private DocumentManagementEntities db = new DocumentManagementEntities();
// GET: SearchPaging
public ViewResult Index(int? page, bool? resnum)
{
var temp = resnum;
int pageSize = 25;
int pageNumber = (page ?? 1);
List<SearchPagingViewModels> searchList = new List<SearchPagingViewModels>();
var allResolutions = from c in db.AllResolutions select c;
allResolutions = allResolutions.OrderBy(c => c.ResolutionYear).ThenBy(c => c.ResolutionNumber);
foreach (var item in allResolutions)
{
SearchPagingViewModels searchItem = new SearchPagingViewModels();
searchItem.ObjectID = item.ObjectID;
searchItem.ResolutionYear = item.ResolutionYear;
searchItem.ResolutionNumber = item.ResolutionNumber;
searchItem.ResolutionText = item.ResolutionText;
searchItem.ResolutionDate = item.ResDate;
searchItem.IsResNumChecked = resnum;
searchList.Add(searchItem);
}
return View(searchList.ToPagedList(pageNumber, pageSize));
}
}
}
As you can see I create a List<SearchPagingViewModels> and then add each SearchPagingViewModels into the List<SearchPagingViewModels>. In my Index.cshtml, I use a foreach loop to traverse the list and display each item and create a PagedList. Should I be changing my ViewModel to store a List<AllResolutions> like so:
using PagedList;
using Resolutions.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Web;
namespace Resolutions.ViewModels
{
public class SearchPagingViewModels
{
public List<AllResolution> AllResolutions { get; set; }
public int? PageNumber { get; set; }
public bool? IsResYearChecked { get; set; }
public bool? IsResNumChecked { get; set; }
public bool? IsKeywordChecked { get; set; }
public string SearchKeyword { get; set; }
}
}
or do I want to use the current values within the ViewModel? If instead I used a List<AllResolutions>, how do you access the values within the list in the cshtml file?
I have a DBContext "StatusDBContext", a Model "Status_T" with some(n) properties and a corresponding ViewModel "Status" with few of the Model properties. I am using Entity Framework with code first from database.
DBContext:
namespace xxx.Areas.SysParam.Models
{
using System;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
public partial class StatusDbContext : DbContext
{
public StatusDbContext()
: base("name=xxxConnectionString")
{
}
public virtual DbSet<STATUS_T> STATUS_T { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<STATUS_T>().ToTable("STATUS_T");
}
}
}
Model:
namespace xxx.Areas.SysParam.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
[Table("STATUS_T")]
public partial class STATUS_T
{
[Key]
[Column(Order = 0)]
[StringLength(35)]
public string TYPE { get; set; }
[Key]
[Column(Order = 1)]
public byte STATUS { get; set; }
[StringLength(30)]
public string DESCRIPTION { get; set; }
[Key]
[Column(Order = 2)]
[StringLength(2)]
public string LANG_CODE { get; set; }
public DateTime UPD_DTIME { get; set; }
public DateTime? DELETE_DTIME { get; set; }
public short? VER_NO { get; set; }
[StringLength(1)]
public string STAT_USE { get; set; }
}
}
View Model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using xxx.Areas.SysParam.Models;
namespace xxx.Areas.SysParam.ViewModels
{
public class Status
{
[Display(Name = "Status ID")]
public byte STATUS { get; set; }
[Display(Name = "Description")]
public string DESCRIPTION { get; set; }
[Display(Name = "Type")]
public string TYPE { get; set; }
[Display(Name = "In Use")]
public string STAT_USE { get; set; }
}
}
Before introducing ViewModel the Controller looked like:
public ActionResult StatusView()
{
List<Models.STATUS_T> StatusList = new List<Models.STATUS_T>();
using (var status = new Models.StatusDbContext())
{
StatusList = Status.STATUS_T.ToList();
}
return View(StatusList);
}
Now I have two questions.
1) As I googled about Model, ViewModel and DataAnnotations its somewhat clear that DataAnnotations should be added to ViewModel but in Code First from Existing DB the Models are generated with few DataAnnotations so what will be the best practice here, to copy properties from Model to ViewModel and add more DataAnnotations whenever required?
2) How to replace Model with ViewModel in Controller code?
Help will be appreciated. Thanks!!!
Updated: Controller:
public ActionResult DWPStatusView()
{
var DWPStatusList = new List<ViewModels.DWPStatus>();
using (var DWPStatus = new Models.DWPStatusDbContext())
{
DWPStatusList = DWPStatus.DWP_STATUS_T.ToList().Select(p => new ViewModels.DWPStatus(p)).ToList();
}
return View(DWPStatusList);
}
1.Yes, best practise is to create separate view model class and copy there necessary properties from DB model, because:
may happen that DB model have unwanted properties for view
view model may need additional properties and adding them to DB model
is not good practise
View model usually have validation data annotations attributes, so better keep them also separate from DB annotations.
2.
public ActionResult StatusView()
{
var statusList = new List<ViewModels.Status>();
using (var status = new Models.StatusDbContext())
{
statusList = Status.STATUS_T.ToList().Select(p => new ViewModels.Status {
Property1 = p.Property1,
Property2 = p.Property2,
...
}).ToList();
}
return View(statusList);
}
You can place property mapping into view model constructor, then selecting data will look next:
statusList = Status.STATUS_T.ToList().Select(p => new ViewModels.Status(p)).ToList();
Update: and view model:
public class Status
{
public Status(){}
public Status(Models.STATUS_T model)
{
//here comes mapping
}
....
}
I am developing an ASP .Net MVC 3 application using C# and SQL Server 2005.
I want to customize my interface depending on the type of user logged.
I was following
this tuto
in the microsoft site and i am stuck when he use ActionLog instance in the filter class (ActionLogFilterAttribute).
Infact, this class is declared in 'StoreDB.designer.cs' class which i don't have because i created my project using the 'code first' method of Entity Framework.
I have only this class for the context :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
namespace MvcApplication2.Models
{
public class GammeContext : DbContext
{
public GammeContext()
{
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<GammeContext>());
}
public DbSet<Account> Accounts { get; set; }
public DbSet<Ns_AFaire> Ns_AFaires { get; set; }
public DbSet<Famille> Familles { get; set; }
public DbSet<Fonction> Fonctions { get; set; }
public DbSet<Fonction_Poste> Fonction_Postes { get; set; }
public DbSet<Gamme> Gammes { get; set; }
public DbSet<Historique> Historiques { get; set; }
public DbSet<Ligne> Lignes { get; set; }
public DbSet<Phase> Phases { get; set; }
public DbSet<Poste> Postes { get; set; }
public DbSet<Produit> Produits { get; set; }
public DbSet<Profile_Ga> Profil_Gas { get; set; }
public DbSet<Sous_Famille> Sous_Familles { get; set; }
public DbSet<UF> UFs { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<Num_Serie> Num_Series { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.PluralizingTableNameConvention>();
}
}
}
and this is the filter class that i created :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcApplication2.Models;
namespace MvcApplication2.Filters
{
public class ActionLogFilterAttribute : ActionFilterAttribute, IActionFilter
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
GammeContext db = new GammeContext();
ActionLog log = new ActionLog()
{
Controller = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName,
Action = filterContext.ActionDescriptor.ActionName,
IP = filterContext.HttpContext.Request.UserHostAddress,
DateTime = filterContext.HttpContext.Timestamp
};
db.AddToActionLogs(log);
db.SaveChanges();
base.OnActionExecuting(filterContext);
}
}
}
So, is there any solution ??
The ActionLog instance he is using is the Enitity that is related to his ActionLog table.
What you need to do is to add your own ActionLog entity - that is all :)
In my controller i am creating a subcategory object and giving that object a reference to the category it belongs to. Everything works fine when i debug the site but when i load the list of objects from my entityframework db all the category object references are removed. the rest persists. anybody got an idea why this happens ?
Controller:
[Authorize(Roles = "administrator")]
[HttpPost]
public ActionResult Create(CategoryViewModel viewmodel, HttpPostedFileBase Icon)
{
SubCategory subcategory = new SubCategory();
Category category = categorycontroller.getCategoryByName(viewmodel.SelectedValue);
viewmodel.subcategory.Category = category;
subcategory = viewmodel.subcategory;
category.Subcategories.Add(subcategory);
if (Icon != null && Icon.ContentLength > 0)
{
var fileName = Path.GetFileName(Icon.FileName);
var path = Path.Combine(Server.MapPath("../../Content/icons/"), fileName);
Icon.SaveAs(path);
subcategory.Icon = fileName;
}
if (ModelState.IsValid)
{
subcategorydb.categories.Attach(category);
subcategorydb.subcategories.Add(subcategory);
subcategorydb.SaveChanges();
return RedirectToAction("Index");
}
return View(subcategory);
}
and this is my viewmodel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using System.Web.Mvc;
using SkyLearn.Areas.Categories.Controllers;
namespace SkyLearn.Areas.Categories.Models
{
public class CategoryViewModel
{
public List<SelectListItem> PossibleValues { get; set; }
public string SelectedValue { get; set; }
public SubCategory subcategory { get; set; }
public CategoryController categorycontroller;
public CategoryViewModel()
{
PossibleValues = new List<SelectListItem>();
}
}
}
And here is my Category and SubCategory class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
namespace SkyLearn.Areas.Categories.Models
{
public class Category
{
public int ID { get; set; }
public string Title { get; set; }
public string Icon { get; set; }
public string Description { get; set; }
public List<SubCategory> Subcategories;
public Category()
{
Subcategories = new List<SubCategory>();
}
}
public class CategoryDBContext : DbContext
{
public DbSet<Category> categories { get; set; }
public DbSet<SubCategory> subcategories { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using SkyLearn.Areas.Categories.Controllers;
namespace SkyLearn.Areas.Categories.Models
{
public class SubCategory
{
public int ID { get; set; }
public string Title { get; set; }
public string Icon { get; set; }
public string Description { get; set; }
public int CategoryID { get; set; }
public Category Category { get; set; }
}
public class SubCategoryDBContext : DbContext
{
public DbSet<SubCategory> subcategories { get; set; }
public DbSet<Category> categories { get; set; }
}
}
i have searched many sites for info on this problem but couldnt find much of help. Anybody here able to identify my problem?
as seen on this screenshot the object is correctly referenced by all means. but when i load the data next time the object reference has disapeared. all other attributes are still there and saved as they should:
thanks AronChan
//// Update ////
I am now getting the following error:
A foreign key value cannot be inserted because a corresponding primary
key value does not exist. [ Foreign key constraint name =
SubCategory_Category ]
Your category object won't get saved because it is not attached to the DbContext that you add the subcategory to. The subcategory might know about the reference but the category won't. If there is a lookup table (which there must be if its many to many) I don't see how that record would be saved. Try attaching the category, adding the subcategory and then saving. Personally I have always set up the many-to-many look up tables as their own entity. It is a little easier to visualize what is actually happening as opposed to giving all control to EF.
Also, if you are using code first, make sure your EntityConfigurations are correct. Try running the EdmxWriter over your context to make sure the data model looks exactly how you want it to.