I have a Controller action the receives 2 URL parameters, which are foreign keys for the data model:
public ActionResult Create(SurveyResponseModel surveyresponsemodel, int MemberId, int ProgramId)
{
surveyresponsemodel.MemberId = MemberId;
surveyresponsemodel.ProgramId = ProgramId;
return View(surveyresponsemodel);
}
Here is the data model:
public class SurveyResponseModel
{
[Key]
public int ResponseId { get; set; }
public int MemberId { get; set; }
public int ProgramId { get; set; }
// "If yes, what changes did you make? Mark all that apply."
[DisplayName("Did you make any changes in your practice, research, or administration activities as a result of participating in this CME activity?")]
public string CmeChanges { get; set; }
[DisplayName("Better patient follow-up")]
public bool PatientFollowUp { get; set; }
public virtual SurveyProgramModel SurveyProgramModel { get; set; }
public virtual PersonModel PersonModel { get; set; }
And the Data Model for "SurveyProgramType"
public class SurveyProgramModel
{
[Key]
public int ProgramId { get; set; }
public int ProgramYear { get; set; }
public int ProgramStatusId { get; set; }
public string ProgramTitle { get; set; }
public int ProgramTypeId { get; set; }
public virtual SurveyProgramTypeModel ProgramType { get; set; }
public virtual ProgramStatusModel ProgramStatusModel { get; set; }
}
What I want to be able to do in my view, is retrieve the ProgramTitle by the URL parameter that is passed for ProgramId. So the view looks something like:
<div class="editor-label">
#Model.SurveyProgramModel.ProgramTitle
</div>
However, #Model.SurveyProgramModel.ProgramTitle is throwing an exception because it is null. I'm thinking I have my navigation property set up incorrectly. Any idea what that is?
Shouldn't you return your view model to the view?
public ActionResult Create(
SurveyResponseModel surveyresponsemodel) //, int MemberId, int ProgramId)
{
// MemberId and ProgramId arguments do not need to be defined
// They will be picked up my MVC model binder, since there are properties
// with the same name in SurveyResponseModel class
//surveyresponsemodel.MemberId = MemberId;
//surveyresponsemodel.ProgramId = ProgramId;
surveyresponsemodel.SurveyProgramModel = new SurveyProgramModel(); // new line
return View(surveyresponsemodel); // <- return your view model here
}
without passing the model to the view, you cant access the properties of the model in your view. thats the possible cause of the error.
public ~ActionResult PassModel(DemoModel _model, int id)
{
// your code goes here....
return View(_model); // pass the model to view ..so you can work on your model
}
Related
I have one model class called Client.
namespace Logistic.Models
{
public class Client
{
public int ClientId { get; set; }
public string Name { get; set; }
public string LastName { get; set; }
public ICollection<Dispatch> dispatches { get; set; }
}
}
I have another class that has two properties with relationship to Client:
namespace Logistic.Models
{
public class Dispatch
{
public int DispatchId { get; set; }
public int CustomerId { get; set; }
public int RecipientId { get; set; }
public Client Customer { get; set; }
public Client Recipient { get; set; }
}
}
In order to have a relationship in my Dispatch class I have to have clientId. Right? But in this case I will have two clientId. I am just started with ASP.NET MVC, and I can't understand it.
Because in my controller I have:
public ActionResult Dispatch()
{
db.Dispatches.Include("Customer").ToList();
db.Dispatches.Include("Recipient").ToList();
var dispatch = db.Dispatches;
return View(dispatch);
}
And in my View I am trying to display:
#model IEnumerable<Logistic.Models.Dispatch>
#{
ViewBag.Title = "Dispatch";
}
<h2>Dispatch</h2>
#foreach(var item in Model)
{
<h2>Tracking : #item.TrackingId</h2> <br />
<h2>Customer : #item.Customer.Name</h2> <br />
<h2>Recipient : #item.Recipient.Name</h2> <br />
}
If I understand correctly, you are trying to use RecipientId and CustomerId as Foreign Keys for Recipient and customer respectively? In this case you can add the foreign key attribute to the properties like this:
namespace Logistic.Models
{
public class Dispatch
{
public int DispatchId { get; set; }
public int CustomerId { get; set; }
public int RecipientId { get; set; }
[ForeignKey("CustomerId")]
public Client Customer { get; set; }
[ForeignKey("RecipientId")]
public Client Recipient { get; set; }
}
}
This will explicitly specify the foreign keys for the relationship. Hope this helps!
I used scaffolding to create the Index, Details, Create, Edit and Delete views and the controller. I have two view models (Parent / Child) relation. In my Index view I want to display the list of Teams as well as some information on the players (Parent / child). For example I want to display in the Index view the teams with the players count per team and last players that was modified. I am not sure where to begin.
Example:
(Team) Red -- (Last Modified) 01/02/2015 -- (Number Players) 10 and so on.
Team ViewModel
public class TeamVM
{
public int ID { get; set; }
public string Name { get; set; }
public DateTime? LastActivity { get; set; }
public string NumberPlayers { get; set; }
public IList<PLayerVM> PlayerVM { get; set; }
}
Player ViewModel
public class PlayerVM
{
public int ID { get; set; }
public int TeamID { get; set; }
public string PlayerInfo { get; set; }
public DateTime? CreateDate { get; set; }
}
Other ViewModel
public class TeamViewModel
{
public List<Team> Teams{ get; set; }
}
Controller
public ActionResult Index()
{
TeamViewModelviewModel = new TeamViewModel();
viewModel.Teams= db.Teams.ToList();
return View(viewModel);
}
db.Products.ToList()?? I assume that is where you mean db.Teams.ToList()?
You are using viewmodels, so you should map the db data to your viewmodels first:
public ActionResult Index()
{
var teams = db
.Teams
.Include("Players") // Assuming your Team entity has a collection of Players
.SelectMany(t => new TeamVM {
ID = t.ID,
// etc..
})
.ToList();
return View(new TeamViewModel { Teams = teams });
}
model:
public class TeamVM
{
public int ID { get; set; }
public string Name { get; set; }
public DateTime? LastActivity { get; set; }
public IList<PLayerVM> PlayerVM { get; set; }
public int NumberPlayers {
get { return PlayerVM.Count(); }
}
}
Then in your view:
#model MyProject.Models.TeamViewModel
<table>
#foreach(var team in Model.Teams.ToList()) {
<tr>
<td>#team.Name</td> // Name
<td>#team.NumberPlayers</td> // Playercount
<td>#team.PlayerVM.Max(p => p.LastActivity).LastActivity</td> // Last edited
</tr>
}
</table>
I have two tables in my database that have similar data but not same.
I'd like to show these tables in the same view. Looking in internet the most suggested practice is to use a ViewModel class.
So... These are my class tables:
iCareIndoorAlert.cs
[Table("iCareIndoorAlerts")]
public class iCareIndoorAlert
{
[Key]
[DisplayName("ID Allarme iCare indoor")]
public long AlertID { get; set; }
[DisplayName("ID Messaggio")]
public long MessageID { get; set; }
public string UUID { get; set; }
public int MAG { get; set; }
public int MIN { get; set; }
[DisplayName("Distanza")]
public float Dist { get; set; }
[DisplayName("Data ora")]
public DateTime DateTime { get; set; }
public virtual HttpPop3 HttpPop3 { get; set; }
}
iCareOutdoorAlert.cs
[Table("iCareOutdoorAlerts")]
public class iCareOutdoorAlert
{
[Key]
[DisplayName("ID Allarme iCare outdoor")]
public long AlertID { get; set; }
[DisplayName("ID Messaggio")]
public long MessageID { get; set; }
[DisplayName("Latitudine")]
public float Lat { get; set; }
[DisplayName("Longitudine")]
public float Lon { get; set; }
[DisplayName("Accuracy")]
public float Acc { get; set; }
[DisplayName("Data ora")]
public DateTime DateTime { get; set; }
}
After I created a ViewModel folder with a iCareAlertViewModel.cs class:
public List<iCareIndoorAlert> iCareIndoorAlert { get; set; }
public List<iCareOutdoorAlert> iCareOutdoorAlert { get; set; }
And added there rows in the iCareEntities.cs:
public DbSet<iCareIndoorAlert> iCareIndoorAlerts { get; set; }
public DbSet<iCareOutdoorAlert> iCareOutdoorAlerts { get; set; }
public DbSet<iCareAlertViewModel> iCareAlertsViewModels { get; set; }
After I generated the iCareAlertController.cs and run the view Index.cshtml but I get the error "Key not found". So in the ViewModel I added a dummy variable with [Key] attribute and now a get an error that says that can't find the iCareAlertViewModel table...
What am I doing wrong?
Thank you
First, don't create a DbSet for your view model, that's not necessary. A view model is a POCO that sits between your data models (i.e. your entities) and your user interface.
What you probably need to do is define an interface that has the properties that are common to your two entities, so something like this:
public interface IAlert
{
long AlertID { get; set; }
long MessageID { get; set; }
//etc...
}
Now each entity can implement that interface:
public class iCareIndoorAlert : IAlert
{
//snip
}
Now your viewmodel:
public class AlertViewModel : IAlert
{
public long AlertID { get; set; }
public long MessageID { get; set; }
//snip
}
So your view will now be something like this:
#model IEnumerable<My.Assembly.AlertViewModel>
#foreach(var alert in Model)
{
#Html.DisplayFor(m => m.AlertID)
//etc
}
Finally you need something to map your entities to your view model, you can use a library like Automapper but manually, it's something like this (including the action method and return):
public ActionResult Index()
{
List<IAlert> alerts = GetOutdoorAlerts(); //for example
List<AlertViewModel> alertViewModels = alert
.Select(a => new AlertViewModel
{
AlertID = a.AlertID,
MessageID = a.MessageID,
//etc...
});
return View(alertViewModels);
}
I have two models, a code model and a tag model which are linked by a many to many relationship. I am trying to add a code entry that includes a possible selection of many tags using a view model (using check boxes for the tags in my view). I am getting the error:
The model item passed into the dictionary is of type 'System.Collections.Generic.List'1[StoRed.Models.Code]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[StoRed.Models.CodeTagViewModel]'.
It feels like I need to somehow convert my data to the acceptable format before trying to save it into the table but I'm new to MVC and I am having trouble finding any useful information on the internet about my specific problem. Any help would be greatly appreciated.
The code model
public class Code
{
[Key]
public int CodeID { get; set; }
[Required]
[StringLength(30)]
public string Title { get; set; }
[Required]
[StringLength(150)]
public string Description { get; set; }
public DateTime DateAdded { get; set; }
public DateTime LastUpdated { get; set; }
[Required]
[StringLength(30)]
public string Project { get; set; }
[Required]
[StringLength(30)]
public string CMS { get; set; }
public int DotNetVersion { get; set; }
[Required]
[StringLength(150)]
public string Dependencies { get; set; }
[StringLength(30)]
public string Author { get; set; }
public string CodeFile { get; set; }
[Required]
[StringLength(100)]
public string TFSLocation { get; set; }
////Creates a relationship in the DB with Tag
//[ForeignKey("TagID")]
public virtual ICollection<Tag> Tags { get; set; }
////Purely for API
//[Required]
public int TagID { get; set; }
}
The Tag model
public class Tag
{
[Key]
public int TagID { get; set; }
[Required]
[StringLength(30)]
public string TagName { get; set; }
public virtual ICollection<Code> Code { get; set; }
}
The context
public class Context : DbContext
{
public DbSet<Code> Code { get; set; }
public DbSet<Tag> Tags { get; set; }
}
The view model
public class CodeTagViewModel
{
public Tag Tag { get; set; }
public Tag TagID { get; set; }
public List<Tag> Tags { get; set; }
public int CodeID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public DateTime DateAdded { get; set; }
public DateTime LastUpdated { get; set; }
public string Project { get; set; }
public string CMS { get; set; }
public int DotNetVersion { get; set; }
public string Dependencies { get; set; }
public string Author { get; set; }
public string CodeFile { get; set; }
public string TFSLocation { get; set; }
}
Relevant part of the code controller
[HttpPost]
public ActionResult Create(CodeTagViewModel codeTagViewModel)
{
if (ModelState.IsValid)
{
Code code = new Code();
Tag tag = new Tag();
var codeTag = new CodeTagViewModel();
code.Title = codeTagViewModel.Title;
code.Description = codeTagViewModel.Description;
code.DateAdded = codeTagViewModel.DateAdded;
code.LastUpdated = codeTagViewModel.LastUpdated;
code.Project = codeTagViewModel.Project;
code.CMS = codeTagViewModel.CMS;
code.DotNetVersion = codeTagViewModel.DotNetVersion;
code.Dependencies = codeTagViewModel.Dependencies;
code.Author = codeTagViewModel.Author;
code.CodeFile = codeTagViewModel.CodeFile;
code.TFSLocation = codeTagViewModel.TFSLocation;
code.Tags = codeTagViewModel.Tags;
db.Code.Add(code);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(codeTagViewModel);
}
Your best bet is to create some kind of provider/manager/service/factory/handler - choose a name that makes most sense in terms of the job it is doing within the flow of data through your system - that is responsible for taking the ViewModel and mapping the properties of the ViewModel into an instance of the domain model before persisting the domain model to the data store, either itself or by passing the hydrated domain model to a repository layer. You can either do this manually or by using something like AutoMapper. Here's a quick manual example:
Create a CommandHandlers folder in your web project with the interface and dependant handler:
public interface ICodeCommandHandler
{
int Save(CodeTagViewModel input);
}
public class CodeCommandHandler : ICodeCommandHandler
{
private IRepository<Code> repository;
public CodeCommandHandler(IRepository<Code> repository)
{
this.repository = repository;
}
public int Save(CodeTagViewModel input)
{
Code code = new Code();
Tag tag = new Tag();
code.Title = input.Title;
code.Description = input.Description;
code.DateAdded = input.DateAdded;
code.LastUpdated = input.LastUpdated;
code.Project = input.Project;
code.CMS = input.CMS;
code.DotNetVersion = input.DotNetVersion;
code.Dependencies = input.Dependencies;
code.Author = input.Author;
code.CodeFile = input.CodeFile;
code.TFSLocation = input.TFSLocation;
code.Tags.Add(tag);
return repository.Save(code);
}
}
Then in your controller, inject the ICodeCommandHandler in via constructor injection, the same as you do with the repository in the CodeCommandHandler:
private readonly ICodeCommandHandler commandHandler;
public CodeController(ICodeCommandHandler commandHandler)
{
this.commandHandler = commandHandler;
}
[HttpPost]
public ActionResult Create(CodeTagViewModel codeTagViewModel)
{
if (!ModelState.IsValid)
{
return View(codeTagViewModel);
}
var id = codeCommandHandler.Save(codeTagViewModel);
// maybe do something useful with the document id after save
return RedirectToAction("Index");
}
To keep the Repository nice and simple, here's how that could look:
public interface IRepository<T>
{
int Save(T entity);
}
public class CodeRepository : IRepository<Code>
{
public int Save(Code entity)
{
using (var context = new Context())
{
context.Code.Add(entity);
context.SaveChanges();
}
}
}
I've not gone into detail about the dependency injection side of things as that wasn't part of the question but this should give you an idea of where to start
I have a model
public class Product : BaseEntity
{
private string _name;
public string Name
{
get { return _name; }
private set{_name = value;}
}
public decimal Price { get; set; }
public double Weight { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public double Depth { get; set; }
public DateTime DateAdded { get; set; }
...
public string GeneralInfo {get{//some get logic}...}
}
and a View model:
public sealed class ProductDetailsModel
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public double Weight { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public double Depth { get; set; }
...
public string GeneralInfo {get;set;}
}
and controller:
public class ProductController : Controller
{
...
public ActionResult Details(int id)
{
var product = _productRepository.GetProduct(id);
var productViewModel = Mapper.Map<ProductDetailsModel>(product);
return View(productViewModel);
}
...
}
everything works great, BUT... I have some get logic for product model general info property, which gets this general info from database, and sometimes, when product doesn't have general info, this property returns null. What I need is to generate alternative general info from available properties such as With, Height, etc. Something like:
private string GenerateGeneralInfoFromProductProperties()
{
var generalInfoStringBuilder = new StringBuilder();
generalInfoStringBuilder.Append(#"<b>Width: </b>").Append(Width).Append("</br>");
generalInfoStringBuilder.Append(#"<b>Weight: </b>").Append(Weight).Append("</br>");
...
return generalInfoStringBuilder.ToString();
}
If I add this logic to product model ...
public class Product : BaseEntity
{
...
public string GeneralInfo
{
get
{
var gInfo = getGeneralInfoFromBD();
if (gInfo==null)
gInfo = GenerateGeneralInfoFromProductProperties();
return gInfo;
}
set { SetPropertyValue(ProductPropertyType.GeneralInfo, value); }
}
}
Everything works fine, BUT it would be wrong and illogical, because I have a view model for representation of product details, so I want to add this logic to view model, but my view model instance is created by mapper, Product view model has no constructors to pass product instance to get it's general info, because, as I said, it has no need in constructor. How can I add this "general info if null" replace logic to mapper, or view model?
Try AfterMap
Automapper.CreateMap<Product,ProductDetailsModel>()
.AfterMap((p,pm) => {
// now you have access to both objects, so you can do whatever you please
});