I have a new Mvc Core application. I want to display a list if items from an sql view. Based on this article, I created a class corresponding to the sql view:
public class ItemsUsersAllocations
{
public int UserId { get; set; }
public int ItemId { get; set; }
...
}
Then I added the following code to the DbContext:
public virtual DbQuery<ItemsUsersAllocations> ItemsUsersAllocations { get; set; }
And the following to OnModelCreating() of the DbContext:
modelBuilder.Query <ItemsUsersAllocations>().ToView("vw_UsersAllocations");
I have the following simple action method in the controller before adding any viewmodel:
public IActionResult Index()
{
return View();
}
And now I tried to auto-generate the Index view. But got an error message:
How can I solve this?
Related
I am working on creating a datagrid in ASP MVC 3 where I have two tables in one view. Each table is being used from its own Model. Therefore, I would have to call two Models into one View which does not seem as simple as I wish it was.
I am pretty new to MVC and I was looking through Stack and found this link:
Two models in one view in ASP MVC 3
Which seems to be the direction that i would want to go... I think.
Here is the code for my first model:
[Table]
public class Model1
{
[Column(IsPrimaryKey = true, IsDbGenerated = true)]
public int Column1 { get; set; }
[Column]
public string Column2 { get; set; }
[Column]
public string Column3 { get; set; }
}
Here is the code for my second model:
[Table]
public class Model2
{
[Column(IsPrimaryKey = true, IsDbGenerated = true)]
public int Column1 { get; set; }
[Column]
public int Column2 { get; set; }
[Column]
public string Column3 { get; set; }
[Column]
public string Column4 { get; set; }
}
Here is the code for the Parent View Model that the other Stack Forum suggested:
public class ParentModelView
{
public Model1 Model1 { get; set; }
public Model2 Model2 { get; set; }
}
I was able to get each one to work individually so i know that it isn't any other issue. The other Stack Forum seemed to be a little too vague for my understanding. I feel like there would have to be more to it than just adding another parent model that is using each model within it (what i am getting out of it).
Some other information that you may find useful is that each model is in its own file. Also, Here is my error:
The model item passed into the dictionary is of type
'System.Data.Linq.Table 1[Model1]', but this dictionary requires a model
item of type 'System.Collections.Generic.IEnumerable 1[ParentModelView]'.
Description: An unhandled exception occurred during the execution of the
current web request. Please review the stack trace for more information
about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: The model item passed
into the dictionary is of type 'System.Data.Linq.Table 1[Model1]', but this
dictionary requires a model item of type
'System.Collections.Generic.IEnumerable 1[ParentModelView]'.
Source Error:
An unhandled exception was generated during the execution of the current
web request. Information regarding the origin and location of the exception
can be identified using the exception stack trace below.
---EDIT 1---
Here is the code inside of my View:
#model IEnumerable<ParentModelView>
#{
WebGrid gridModel1 = new WebGrid(Model);
WebGrid gridModel2 = new WebGrid(Model);
}
<div class="Table">
<h2>Model1</h2>
#gridModel1.GetHtml(columns: new[] {
gridModel1.Column("Column1"),
gridModel1.Column("Column2"),
gridModel1.Column("Column3")
})
</div>
<div class="Table" id="rightTable">
<h2>Model2</h2>
#*#gridModel2.GetHtml(columns: new[] {
gridModel2.Column("Column1"),
gridModel2.Column("Column2"),
gridModel2.Column("Column3"),
gridModel1.Column("Column4")
})*#
</div>
EDIT 2
As most of you have requested, here is my controller code. I know that it is not right because i am not quite sure how to pass through the information between two models into the same view. If someone would be able to help with that, it would be much appreciated.
public class HomeController : Controller
{
public ActionResult Index()
{
Model1Repo repoModel1 = new Model1Repo ();
var Model1RepoSQL = repoModel1.All();
Model2Repo repoModel2 = new Model2Repo();
var Model2RepoSQL = repoModel2.All();
return View(Model1RepoSQL);
}
}
Any other information would be much appreciated. Thanks!
I think what you want is something more like this:
public class ParentModelView
{
public IEnumerable<Model1> Model1 { get; set; }
public IEnumerable<Model2> Model2 { get; set; }
}
And in your view
#model ParentModelView
#{
WebGrid gridModel1 = new WebGrid(Model.Model1);
WebGrid gridModel2 = new WebGrid(Model.Model2);
}
EDIT;
Apparently, you aren't populating the parent model correctly. I assumed you would understand how to do that.
public ActionResult MyAction() {
var model1 = // get rows of model1
var model2 = // get rows of model2
return View("myview", new ParentModelView { Model1 = model1, Model2 = model2 }) ;
}
You can always use ViewModel in this case. For example create a viewmodel
public class ViewModel{
public int Table1Column1 { get; set; }
public string Table1Column2 { get; set; }
public string Table1Column3 { get; set; }
public int Table2Column1 { get; set; }
public int Table2Column2 { get; set; }
public string Table2Column3 { get; set; }
public string Table2Column4 { get; set; }
}
Get the data into ViewModel from both the models in business layer or data access layer.
P.S: What McGarnagle said is true but it's vice versa, you are sending child models into the view while it is expecting ParentModelView. If you can post parts of code for controller and view, it would be helpful.
I'm building an MVC 3 website. I have a model looking like this:
public class Survey
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime DateStart { get; set; }
public DateTime DateEnd { get; set; }
// Not in view
public DateTime DateCreated { get; set; }
// Not in view
public DateTime DateModified { get; set; }
}
Based on this I also have a View Model to edit the survey information:
public class SurveyEditViewModel
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime DateStart { get; set; }
public DateTime DateEnd { get; set; }
}
When the user finishes editing I would like to persist the changes. Here's my controller post action:
[HttpPost]
public ActionResult Edit(SurveyEditViewModel model)
{
// Map the view model to a domain model using AutoMapper
Survey survey = Mapper.Map<SurveyEditViewModel, Survey>(model);
// Update the changes
_repository.Update(survey);
// Return to the overview page
return RedirectToAction("Index");
}
In my repository (it's a generic one for now) I have the following code:
public void Update(E entity)
{
using (ABCDataContext context = new ABCDataContext())
{
context.Entry(entity).State = System.Data.EntityState.Modified;
context.SaveChanges();
}
}
When this executes I get the following error: "Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries."
I guess this was to be expected. Mapping from the view model to the model doesn't give me a complete Survey object.
I could modify my controller to look like this. And then it works:
[HttpPost]
public ActionResult Edit(SurveyEditViewModel model)
{
// Map the model to a real survey
survey = _repository.Find(model.Id);
survey.Name = model.Name;
survey.Description = model.Description;
survey.DateStart = model.DateStart;
survey.DateEnd = model.DateEnd;
// Update the changes
_repository.Update(survey);
// Return to the overview page
return RedirectToAction("Index");
}
But I was wondering if a better way is available?
[HttpPost]
public ActionResult Edit(SurveyEditViewModel model)
{
// Fetch the domain model to update
var survey = _repository.Find(model.Id);
// Map only the properties that are present in the view model
// and keep the other domain properties intact
Mapper.Map<SurveyEditViewModel, Survey>(model, survey);
// Update the changes
_repository.Update(survey);
// Return to the overview page
return RedirectToAction("Index");
}
I have a ViewModel. something like this
public class ViewModel
{
public int Id { get; set; }
public int? Value { get; set; }
}
I have a table of existing ViewModels, and below that I have a form where you can add a new ViewModel
For existing ViewModels that are fetched from DB i want no validation on the Value property, but for the case when adding a new ViewModel I want required validation.... The real model is more complex then this one so I want to use the same model in both cases.. Is it possible?
edit: this works
public class AddNewViewModel : ViewModel
{
public new int Value { get; set; }
}
Is it better to use new or virtual/override and why?
Required attributes are compiled into the class. You could do something like this:
public class BaseViewModel
{
public int Id { get; set; }
public virtual int? Value { get; set; }
}
public class CreateViewModel : BaseViewModel
{
[Required]
public override int? Value { get; set; }
}
This way, you only add the validation attribute to the properties where you need them.
I'm trying to create an ImagesController in MVC4 like this
But I keep getting this error.
Had no problem creating controller for PeopleController using this class
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual IEnumerable<Affair> Affairs { get; set; }
}
The problem is with your File property on the Image class. Because EntityFramework won't understand the type HttpPostedFileBase and can't store it in the DB and the controller generator is smart enough to check this. Altough the error message doesn't tell you what is the problem. To fix this you should rewrite your property to use a byte array:
public class Image
{
...
public byte[] File { get; set; }
}
And then the controller generation should work. And you can add your own image upload action, something like this:
[HttpPost]
public ActionResult Upload(Image image, HttpPostedFileBase file)
{
if (ModelState.IsValid)
{
db.Entry(image).State = EntityState.Modified;
image.File = new byte[file.ContentLength];
file.InputStream.Read(image.File, 0, file.ContentLength);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(image);
}
I'm having trouble passing view information from my Get/Create action to my view. Here are my three model classes;
public class Competition
{
public int Id { get; set; }
public int CompetitionId { get; set; }
public string Name { get; set; }
public string Prize { get; set; }
}
public class CompetitionEntry
{
public int Id { get; set; }
public int CompetitionEntryId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public int CompetitionId { get; set; }
}
public class CompetitionEntryViewModel
{
public int Id { get; set; }
public Competition Competitions { get; set; }
public int CompetitionId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
Here is my Get/Create action in CompetitionEntry Controller;
public ActionResult Create(int id)
{
CompetitionEntryViewModel competitionentryviewmodel = db.CompetitionEntriesView.Find(id);
return View(competitionentryviewmodel);
}
I know this doesn't work. The id parameter goes into the URL fine. How to I get access to my Competition class in th Get action? I need to be able to show the competion name on my Create Competition entry view.
Thanks in advance!
public ActionResult Create(int id)
{
var data = db.CompetitionEntriesView.Find(id);
CompetitionEntryViewModel competitionentryviewmodel = new CompetitionEntryViewModel();
competitionentryviewmodel.CompetitionName = data.Name;
return View(competitionentryviewmodel);
}
What you are trying to do is build an object graph and display it through a view model. In order to do this, you need to map your domain model(s) to your view model.
You can do the mapping yourself by writing a lot of code (re-inventing the wheel), or, you could consider using third party tools to do this for you. I recommend you use an AutoMapper as it is very simple to use imo.
The other problem is that your view model contains a domain model. This is likely to cause you a lot of headache in near future. If I were you, I would replace Competition with CompetitionViewModel.
I would also consider creating a view model for a list of competitions, i.e. CompetitionsViewModel. Look into partial views to see how you can display a list of competitions.
Good luck