I have set up a large form with lots of entries. It populates my model and then saves to the database. I also need to be able to pull this information out of the database, put it into the model, and populate a bunch of fields with it for review. How do I do this?
Using ASP.NET MVC 4 Razor.
var db = new TechProjPlansContext();
TechProjPlan model = new TechProjPlan();
I can set up my data context and model, but where do I go from here to populate the model with a data entry chosen by ID?
You can search by givenId and if found return result type of TechProjPlan otherwise null
var resultFound = db.TechProjPlans.Where(e=>e.Id = givenId).FirstOrDefault();
I strongly recommend following this tutorial step by step. From the tutorial to answer your question:
Write a Model class like:
public class Movie
{
public int ID { get; set; }
public string Title { get; set; }
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
public decimal Price { get; set; }
}
Add a DbSet to your Context class: (TechProjPlansContext in your project)
public class MovieDBContext : DbContext
{
public DbSet<Movie> Movies { get; set; }
}
Make sure you can connect to the database server, check your connectionStrings in your Web.config file.
As you wanted to filter only one Entity by using ID, you need a Controller class:
public ActionResult Details(int id = 0) // here id is set to 0 if it's null
{
Movie movie = db.Movies.Find(id);
if (movie == null)
{
return HttpNotFound();
}
return View(movie);
}
As you see, you'll be returning View(movie), that means you return Details page with the Entity (a movie) you got from the database. And have a View, that renders to actual HTML code the client will see. At the top of it, add the line:
#model MvcMovie.Models.Movie // (something TechProjPlans.Models.Movie in your project)
#Html.LabelFor(model => model.Title)
This will create a simple text showing the movie's title.
It's not logical to go deeper within an answer, so rest is up to you with that tutorial. Just keep in mind that the code above is only one example and you can use endless variations within each level for your situation.
You can right click on the directory Controllers, select Add New and select your Model class and Context class at the page. That will produce a Controller and Views (index, edit, delete, details, insert) tied to it which will be a good way to start your MVC study.
Related
My current employer is developing a mobile app using Xamarin.Forms and Asp.net mvc on the backend. I suggested to use realm in the mobile app. My manager want to see a POC(Proof of concept) app using realm with backlink feature before allowing it to be used in the app. I am working on the POC on GitHub . The documentation is very limiting and the GitHub repo of realm-dotnet don’t have good sample.
I completed the project. But unable to implement backlink. The sample app I have developed allow user to create assignees(employees) in the first page. The user can delete or edit the employees using context menu. When the user clicks on the employee name the app navigates to the ToDoListPage of that particular employee. Here the user can create ToDoItems. On this ToDoList page I want to show the ToDoItems that where assigned to that employee only.
The models were as follows:
public class Assignee : RealmObject
{
public Assignee()
{
ToDoItems = Enumerable.Empty<ToDoItem>().AsQueryable();
}
[PrimaryKey]
public string Id { get; set; } = Guid.NewGuid().ToString();
public string Name { get; set; }
public string Role { get; set; }
[Backlink(nameof(ToDoItem.Employee))]
public IQueryable<ToDoItem> ToDoItems { get; }
}
public class ToDoItem : RealmObject
{
[PrimaryKey]
public string Id { get; set; } = Guid.NewGuid().ToString();
public string Name { get; set; }
public string Description { get; set; }
public bool Done { get; set; }
public Assignee Employee { get; set; }
}
I am adding employee to each ToDo Item:
Item.Employee = Employee;
_realm.Add(Item);
Now I want to access the ToDoItems for the Employee:
Items = _realm.All<Assignee>().Where(x => x.Id == EmployeeId).FirstOrDefault().ToDoItems;
But this does not work. I will be grateful if someone can help me out by preferably writing code in my sample app or write the correct code in the reply.
Thank you
Firstly, Realm .NET doesn't currently support traversing properties (x.Employee.Id). Due to this, when I start the app and try to go to the ToDoListPage, the app crashes with the exception:
The left-hand side of the Equal operator must be a direct access to a persisted property in Realm
Realm supports object comparison, so we can fix this like so:
var employee = _realm.Find<Assignee>(EmployeeId);
Items = _realm.All<ToDoItem>().Where(x => x.Employee == employee);
Secondly, everything seemed fine in your code, so I dug a bit deeper and saw why it isn't working. The issue is that when we try to get all items with the code above, the EmployeeId parameter is null. Since the EmployeeId is being populated after the load logic has been triggered, we don't need to load the data in the ctor. So you can remove this code.
Finally, since you won't be loading the data in the ctor, and instead in the SetValues method, the UI needs to know, when the data has been updated, what exactly to redraw. Thus, you need to mark the collection to be Reactive too:
[Reactive]
public IEnumerable<ToDoItem> Items { get; set; }
Then, you need to change the SetValues method to use object comparison, instead of traversing:
async Task SetValues()
{
Employee = _realm.Find<Assignee>(EmployeeId);
Title = Employee.Name;
Items = _realm.All<ToDoItem>().Where(x => x.Employee == Employee);
}
To sum up - you don't need to try and load the data in the ctor, since you don't know when the EmployeeId will be set. You are already tracking when the property will change and inside the SetValues command you simply need to change the expression predicate.
How to save two Entities from one View. Suppose I have two Entities Party and Person with One to Many relation. Now I need to save both Entities from Party View. I am using ASP.NET MVC4.
public partial class Cm_Opt_Pty_Party_S
{
public Cm_Opt_Pty_Party_S()
{
this.Cm_Opt_Psn_Person_S = new HashSet<Cm_Opt_Psn_Person_S>();
}
public int Pty_ID { get; set; }
public Nullable<int> Pty_PARTYTYPECODE { get; set; }
public string Pty_FULLNAME { get; set; }
public string Pty_GOVTID { get; set; }
public Nullable<int> Pty_GOVTIDTC { get; set; }
public Nullable<int> Pty_GOVTIDSTAT { get; set; }
public virtual ICollection<Cm_Opt_Psn_Person_S> Cm_Opt_Psn_Person_S { get; set; }
}
What you can do is create a ViewModel This class would contain the relevant properties needed to create both entities.
Then you base your View on the ViewModel instead, and pass that to the controller.
When you want to save the entities, you can build up the separate entities and save them.
I have a better understanding of your issue, so editing this answer to show the solution I would use.
Your Controller will deliver the Party object to your view for displaying the Party information. Using a loop you can display the items contained in the collection.
#foreach(var m in Model.Persons)
{
#Html.DisplayFor(model=>m.FirstName)
#Html.DisplayFor(model=>m.Surname)
}
When you want to add more items into the collection, you will need to render a partial view or new view containing a form for adding a Person. It will be strongly typed as Person model and the Controller action recieving the post will be expecting a Person
If for example a Person just had a FirstName,Surname and PartyId the form would use these helpers in your view
#Html.TextboxFor(m=>m.FirstName)
#Html.TextboxFor(m=>m.Surname)
#Html.TextBoxFor(m=>m.PartyId)
You then submit that back to your controller, and have logic for adding the person to the collection. Then return the view with Party model containing the newly added Person in the Persons collection.
Using #Ajax.BeginForm or some custom Jquery/Javascript you could handle this async to prevent page refreshing during the process.
If you don't want to do it this way, another option is EditorTemplates. See here for example: ASP.NET MVC LIST and Create in same view
Obviously there are a number of ways to do this, but I thought I'd ask for a little feedback on benefits and drawbacks of the approaches.
First of all, the NerdDinner tutorial's Edit Action is in the form (say Form A):
[HttpPost]
public ActionResult Edit(int id, FormCollection collection) {
It seems to me that if you shape your ViewModels well to match your views, that the approach Form B:
[HttpPost]
public ActionResult Edit(MyViewModel mvm) {
just seems like a better, cleaner approach. I then just map the VM properties to the Model properties and save. However, if this ViewModel has other entities embedded in it that are initialized via the constructor (for example in the nerddinner tutorial), then this edit action fails if there is no default constructor and you'd have to use the first approach.
So, the first question is do you agree that generally Form B is usually better? Are there drawbacks?
Secondly, it seems then if Form B is used, the decorator type validation would need to be in the ViewModel. Are there advantages of embedding entities in ViewModels and keeping the validation at the entity level only?
This is a pretty general SO question.
the first question is do you agree that generally Form B is usually better?
The only time I do not use Form B is when I upload files. Otherwise, I don't believe anyone should ever need to use Form A. The reason I think people use Form A is a lack of understanding of the abilities of ASP.Net's version of MVC.
Secondly, it seems then if Form B is used, the decorator type validation would need to be in the ViewModel.
Sort of / it Depends. I'll give you an example:
public IValidateUserName
{
[Required]
string UserName { get; set; }
}
public UserModel
{
string UserName { get; set; }
}
[MetadataType(typeof(IValidateUserName))]
public UserValiationModel : UserModel
{
}
The validation decorator is in an interface. I'm using the MetadataType on a derived class to validate the derived type. I personally like this practice because it allows reusable validation and the MetadataType/Validation is NOT part of the ASP.NET core functionality, so it can be used outside of ASP.Net (MVC) application.
Are there advantages of embedding entities in ViewModels ..
Yes, I do my absolute best to never pass a basic model to the view. This is an example of what I don't do:
public class person { public Color FavoriteColor { get; set; } }
ActionResult Details()
{
Person model = new Person();
return this.View(model);
}
What happens when you want to pass more data to your view (for partials or layout data)? That information is not Person relevant most of the time so adding it to the Person model makes no sense. Instead, my models typically look like:
public class DetailsPersonViewModel()
{
public Person Person { get; set; }
}
public ActionResult Details()
{
DetailsPersonViewModel model = new DetailsPersonViewModel();
model.Person = new Person();
return this.View(model);
}
Now I can add required data the DetailsPersonViewModel that view needs beyond what a Person knows. For example, lets say this is going to display a for with all the colors for the Person to pick a favorite. All the possible colors aren't part of a person and shouldn't be part of the person Model, so I'd add them to the DetailPersonViewModel.
public class DetailsPersonViewModel()
{
public Person Person { get; set; }
public IEnumerable<Color> Colors { get; set; }
}
.. and keeping the validation at the entity level only?
System.ComponentModel.DataAnnotations weren't designed to validate properties' properties, so doing something like:
public class DetailsPersonViewModel()
{
[Required(property="FavoriteColor")]
public Person Person { get; set; }
}
Doesn't exist and doesn't make sense. Why ViewModel shouldn't contain the validation for the entity that needs validation.
this edit action fails if there is no default constructor and you'd have to use the first approach.
Correct, but why would a ViewModel or a Entity in a ViewModel not have a parameterless constructor? Sounds like a bad design and even if there is some requirement for this, it's easily solved by ModelBinding. Here's an example:
// Lets say that this person class requires
// a Guid for a constructor for some reason
public class Person
{
public Person(Guid id){ }
public FirstName { get; set; }
}
public class PersonEditViewModel
{
public Person Person { get; set; }
}
public ActionResult Edit()
{
PersonEditViewModel model = new PersonEditViewModel();
model.Person = new Person(guidFromSomeWhere);
return this.View(PersonEditViewModel);
}
//View
#Html.EditFor(m => m.Person.FirstName)
//Generated Html
<input type="Text" name="Person.FirstName" />
Now we have a form that a user can enter a new first name. How do we get back the values in this constructor? Simple, the ModelBinder does NOT care what model it is binding to, it just binds HTTP values to matching class properties.
[MetadataType(typeof(IPersonValidation))]
public class UpdatePerson
{
public FirstName { get; set; }
}
public class PersonUpdateViewModel
{
public UpdatePerson Person { get; set; }
}
[HttpPost]
public ActionResult Edit(PersonUpdateViewModel model)
{
// the model contains a .Person with a .FirstName of the input Text box
// the ModelBinder is simply populating the parameter with the values
// pass via Query, Forms, etc
// Validate Model
// AutoMap it or or whatever
// return a view
}
I have not yet taken a look at the NerDinner project, however, I generally try to avoid having a ViewModel in the POST of an action and instead, only have the elements of the "form" submitted.
For instance, if the ViewModel has a Dictionary that is used in some kind of dropdown, the entire dropdown will not be submitted, only the selected value.
My general approach is:
[HttpGet]
public ActionResult Edit(int id)
{
var form = _service.GetForm(id);
var pageViewModel = BuildViewModel(form);
return View(pageViewModel);
}
[HttpPost]
public ActionResult Edit(int id, MyCustomForm form)
{
var isSuccess = _service.ProcessForm(id);
if(isSuccess){
//redirect
}
//There was an error. Show the form again, but preserve the input values
var pageViewModel = BuildViewModel(form);
return View(pageViewModel);
}
private MyViewModel BuildViewModel(MyCustomForm form)
{
var viewModel = new MyViewModel();
viewModel.Form = form;
viewModel.StateList = _service.GetStateList();
return viewModel;
}
I am new to MVC3
DB has a table called users (id,name,username,lat,lon). I do not have access to the database.
I created entity model using the above table. Then, I created a SearchController and Search View. On the index page I display the list of all users. Also, I created a form on the page that searches the table using the username. After clicking on the details link I show the details page where I display the user's details.
Now I need to display other users that are within a mile of the selected user. I already have the sql query to get the list of other users that are within a mile of the selected user (This is a sql query). I need to show this list on Details page.
I created a custom class model.
public class SearchDetailsViewModel
{
public decimal id { get; set; }
public string name { get; set; }
public string username { get; set; }
public Nullable<decimal> lat { get; set; }
public Nullable<decimal> lon { get; set; }
public string profile_img_url { get; set; }
public IQueryable<user> usersWithinAMile { get; set; }
}
I am not sure if this is the right approach. Also, I do not know how I would intialize this class.
Any help or suggestion is really appreciated.
Yes, you are on the right track, you get the data from your SQL into the class, and then to the view, in the ActionResult, like this:
using System.Collections.Generic;
public ActionResult Index() {
var data = new List<SearchDetailsViewModel>();
// foreach row in your SQL
var s = new SearchDetailsViewModel();
s.lat = -42.00000M;
// more data added to the s object here
data.Add(s);
// end loop
return View("ThePage", data);
}
Then on your view itself you would do something like this:
#foreach (var s in Model) {
// output your values on the page
}
I am new to MVC. I am developing an web application in asp.net MVC. I have a form through which users can get registered, after registration user redirected to ProfileView.aspx page. till here everything is fine.
Now I want to show the articles headings posted by that user right under his profile.
Right now I m using following code:
public ActionResult ProfileView(int id)
{
Profile profile = profileRepository.GetProfileByID(id);
var articles = articlesRepository.FindArticlesByUserID(id).ToList();
return View("ProfileView", profile);
}
Thanks for helping in advance
Baljit Grewal
I can think of two options:
Use the ViewData dictionary to store the articles.
public ActionResult ProfileView(int id)
{
Profile profile = profileRepository.GetProfileByID(id);
var articles = articlesRepository.FindArticlesByUserID(id).ToList();
ViewData["Articles"] = articles;
return View("ProfileView", profile);
}
Or, if you want to avoid using ViewData, create a ViewModel. A ViewModel is kind of a data transport object. You could create a ProfileViewModel class like this:
public class ProfileViewModel
{
public Profile Profile{ get; set; }
public IList<Article> Articles { get; set; }
}
or just include the Profile properties you are using in your view, this will make binding easier but you'll have to copy values from your Model to your ViewModel in your controller.:
public class ProfileViewModel
{
public int Id{ get; set; }
public string Name { get; set; }
.......
public IList<Article> Articles { get; set; }
}
If you go for this last option take a look at AutoMapper (an object to object mapper).
you will want your page to inherit from ViewPage and then you can use your model inside the .aspx markup like