I am learning how to use MVC right now and I just have a question on when I am creating and updating entries in the database. I was reading a post from this page: asp.mvc 4 EF ActionResult Edit with not all fields in view
The guy in it said to create a model that will be used, so is the efficient way to insert a new row and update an existing row by having two models with different properties?
So my models would look like this -
public class UserModelView
{
public string FirstName { get; set; }
public string Surname { get; set; }
public DateTime AccountCreated { get; set; }
public DateTime? LastLoggedIn { get; set; }
}
public class UserModelCreate
{
[Key]
public int UserId { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
public DateTime AccountCreated { get; set; }
}
public class UserModelUpdate
{
public string FirstName { get; set; }
public string Surname { get; set; }
public DateTime? LastLoggedIn { get; set; }
}
Is this the best way to do what I need to do?
Im guessing you were previously using the entity class when binding your model back in.
You shouldn't do that!
The guy in the post is right, this is a much better way of controlling your entity and model information and provides a layer of seperation between the two.
After all you wouldnt want a user being able to directly manipulate an entity via a HTTP request.
I answered something similar here
Related
I am working with AutoMapper, which I am relatively new with, and I stumbled upon a small mapping problem I was hoping the community could assist with.
So I have two data transfer objects:
public class UserDto {
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public List<CharacterDto> Characters { get; set; }
}
public class CharaterDto {
public string CharacterName { get; set; }
public string ClassName { get; set; }
public int CharacterLevel { get; set; }
}
and two Domain Entities
public class Character {
public int ID { get; set; }
public int UserId { get; set; }
public string CharacterName { get; set; }
public string ClassName { get; set; }
public int CharacterLevel { get; set; }
}
public class User {
public int ID { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
The end goal is to be able to save the data taken in by the DTOs into the database via the Domain Entities; however, when it comes to typing up the list of Characters for 'UserDto', I do not know how to map this properly with AutoMapper. I can map it manually with little to no problems... but I can't find anything that helps to explain this or any examples that would help me understand it better.
I have tried doing things like:
CreateMap<UserDto, Character>()
.ForMember(dest => dest.CharacterName, m => m.MapFrom(source => source.Characters[0].CharacterName));
However, this seems to only map the 1st entry and not the others. I have also considered mapping the individual mappings like so:
CreateMap<CharacterDto, Character>();
CreateMap<UserDto, Character>()
.ForMember(?/*this section I cannot figure out*/)
But can't figure out how to associate the the collection of characters to the mapped CharacterDto. I doubt that if I run the code without that association, the code is going to automatically understand that for each character in characters, map each character using the appropriate mapper... If I must manually do this, I can... but if there is an AutoMapper way, any help constructing it would be greatly appreciated.
Type converters are you friend here for mapping 1 to many like this.
Let me know if you need me to go further and get you a working example from your models.
https://stackoverflow.com/a/18096914/7911333
I am creating some view models for my ASP MVC web app.
I created "code first" models for database. Is it a good way to derive view models from database models?
Example database model:
public class Project
{
[Key]
public int Id { get; set; }
public int? CustomerId { get; set; }
public int TypeId { get; set; }
public string Number { get; set; }
public string Name { get; set; }
}
View model:
public class ViewModelProject : Project
{
[NotMapped]
public DateTime? Start { get; set; }
[NotMapped]
public DateTime? End { get; set; }
[NotMapped]
public string Manager { get; set; }
}
Is this the right way or is it completely false?
EDIT (subquestion):
I have some very simple database models like ProjectType, which only contains i.e. two properties. Should I also fragment those models in model view or can I make it that way:
Simple database model:
public class ProjectType
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int? Code { get; set; }
}
Can I use it like so:
public class ProjectVM
{
public string Name { get; set; }
public int Number { get; set; }
public ProjectType Type { get; set; }
}
Or does it have to be fragmented like so:
public class ProjectVM
{
public string Name { get; set; }
public int Number { get; set; }
public string Type { get; set; }
public int TypeCode { get; set; }
}
I would not recommend doing it this way. I (and many others) have tried it and it doesn't work well. You will inadvertedly run into troubles, since an MVC model has to be tailored to the view and what you get from the DB rarely fits. Sure, you can hammer it into place, but the code quickly gets messy and store-related and UI code starts to mangle together. This even shows in your example, since you have to put the NotMappedAttribute (which is related to data storage), to ViewModelProject (a class at UI level).
There are many other examples to show this problem, but an especially good one I find when you want to serialize a model object to JSON and send it to a JavaScript client. The JSON serializer takes the values of all public properties and adds them to the JSON. If you want to exclude a property, you have to mark it with a ScriptIgnoreAttribute, which you would also have to apply to the base class, which breaks separation between UI and store-related code.
The better way to go is to keep the staorage model and the MVC model separated and to map the data from one to the other (there are already pre-existing frameworks that help you with that, such as Automapper). This comes with additional advantages, for example better testability, since you are now not dependent on a specific data store to create model instances.
I am creating a quiz creator module. There are 5 subjects. Each subject has 2000 questions.
Say, it's called "Create Full model test", and it will contain 100 questions, 20 questions from 5 subjects. So, 20*5=100
In the UI, creator will first select "Create full model test" from the drop down. Suppose if he select the "Full model test". He will have to select one subject among 5 subjects, then he will have to select 20 questions per subject. and then will have to save them into that "Full model test" segment.
If he selects English, he will have to select 20 questions, then he will have to select another subject, for example, physics, and will have to select another 20 questions for physics, then he will have to select maths and then will have to select another 20 questions and so on for maths. Finally 100 questions will be submitted by the form.
Now, my question is, how can I auto save the selected questions into that "Full model test" segment, so that he can continue saving 5 subject's questions before he submit the form.
Here is my Department model:
namespace MvcBCS.Models
{
public class Department
{
[Key]
public int DepartmentId { get; set; }
public string DepartmentName { get; set; }
public string DepartmentCode { get; set; }
public virtual ICollection<Subject> Subject { get; set; }
public virtual ICollection<Section> Section { get; set; }
public virtual ICollection<Subsection> Subsection { get; set; }
}
}
Here is my Subject Model:
namespace MvcBCS.Models
{
public class Subject
{
[Key]
public int SubjectId { get; set; }
public string SubjectName { get; set; }
public string SubjectCode { get; set; }
public int DepartmentId { get; set; }
public virtual Department Department { get; set; }
public virtual ICollection<Section> Section { get; set; }
}
}
Here is the Section Model:
namespace MvcBCS.Models
{
public class Section
{
[ForeignKey("Department")]
public int? DepartmentId { get; set; }
public virtual Department Department { get; set; }
[ForeignKey("Subject")]
public int? SubjectId { get; set; }
public virtual Subject Subject { get; set; }
[Key]
public int SectionId { get; set; }
public string SectionName { get; set; }
}
}
Here is the subjection model:
namespace MvcBCS.Models
{
public class Subsection
{
[ForeignKey("Department")]
public int? DepartmentId { get; set; }
public virtual Department Department { get; set; }
[ForeignKey("Subject")]
public int? SubjectId { get; set; }
public virtual Subject Subject { get; set; }
[ForeignKey("Section")]
public int? SectionId { get; set; }
public virtual Section Section { get; set; }
[Key]
public int SubsectionId { get; set; }
public string SubsectionName { get; set; }
public string SubsectionCode { get; set; }
}
}
All that you need is just to store all temporary data on client side.
And when you get complete pasts or even full set of data - send it to server using POST/JSON/XML/etc.
I think it such case it will be better for you to use some kind of JavaScript frameworks, for example KnockoutJS, which with only few click's and couple lines of code will allows you to store all your data on client side in object-based model.
Anyway if you will use any framework or not, you should use JavaScript to store all of your data, including question, answers and subjects. JavaScript will allows you to store,validate and send all data that you need.
To make your work with JavaScript easier and faster - you can use jQuery library which contains functions for interaction with both DOM structure and server side.
To make learning of KnockoutJS easier just use tutorial: http://learn.knockoutjs.com
This is how I am going to attempt it.
business rules:
- full model test will be completed if all the subjects questions are submitted by certain user.
Assumption: we knew in advance that we have five subjects. Therefore
public enum Subject
{
English,
Physics,
...
}
Test Poco entity structure:
public class Test
{
public int Id{get;set;}
public User CreatedBy{get;set;}
public Subject Subject{get;set;}
public bool IsFullTestCompleted{get;set;}
public string Question1{get;set;}
public string Question2{get;set;}
...
}
Assumptions:
You can use partial views/ajax/Jquery/Angularjs/Knockout whatever suits you best in your problem context to implement it to auto save the changes
You will add necessary view model with appropriate validation annotations/attributes
you will add validation where necessary.
you will add/update the Test entity. like for first subject you will add data into Test entity, and subsequently you will update it.
Hope it will be helpful
Hi I'm learning to use MVc using Code first method. I'm having trouble understanding the use of ICollection<> with my setup. I have two classes/entitys: 'Restaurant' & 'RestaurantReview' as below:
public class Restaurant
{
public int Id { get; set; }
public string Name { get; set; }
public string City { get; set; }
public string Country { get; set; }
public ICollection<RestaurantReview> Reviews { get; set; }
}
and.....
public class RestaurantReview
{
public int Id { get; set; }
public int Rating { get; set; }
public string Body { get; set; }
public string ReviewerName { get; set; }
public int RestaurantId { get; set; }
}
now whats confusing me is the last property of the Restaurant class. Why is it of type 'ICollection' and uses my RestaurantReview class as a parameter, what does it do, hope I
have made myself clear
It's a definition of one to many relationship.
With that property (sometimes called Navigation Property) Entity Framework will be able to connect Review with Restaurant it was written about. It will also allow you to get Review entities for given Restaurant entity really easily.
You can also remove public int RestaurantId { get; set; } from RestaurantReview class - That column is gonna be generated automatically by EF because of ICollection<RestaurantReview> in Restaurant class.
I think I have read every article and stack overflow question regarding this, but cannot work out the solution. Let me start out with my models
public class Entry
{
public Entry ()
{
DateEntered = DateTime.Now;
}
public int Id { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string Email { get; set; }
public string Number { get; set; }
public string FbId { get; set; }
[ReadOnly(true)]
public DateTime DateEntered { get; set; }
public string AccessToken { get; set; }
//Relationsips
public Backgrounds Background { get; set; }
public Cars Car { get; set; }
}
public class Backgrounds
{
public int Id { get; set; }
public string Name { get; set; }
public string Filename { get; set; }
}
public class Cars
{
public int Id { get; set; }
public string Name { get; set; }
public string FileName { get; set; }
}
Now in my controller, I am updating the entry. Like follows
// PUT /api/entries/5
public HttpResponseMessage Put(Entry entry)
{
if(ModelState.IsValid)
{
_db.Entries.Attach(entry);
_db.Entry(entry).State = EntityState.Modified;
_db.SaveChanges();
return new HttpResponseMessage(HttpStatusCode.NoContent);
}
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
My Entry model gets updated correctly, but if for eg entry.Background.Name changes, this will not be persisted to the database. My controller is accepting the entire entry model including its relationships => Backgrounds and Cars. However any value that is changed to the relationship is not updated or reflected. Any elegant solution without having to query the database then updating? I dont want to have any extra queries or lookups before I update.
Thanks
Tyrone
You must manually tell EF about all changes done to the object graph. You told EF just about change to entry instance but you didn't tell it about any change to related entities or relations itself. There is no elegant way to solve this. You have generally two options:
You will use some DTOs instead your entities and these DTOs will have some flag like IsDirty - when you receive object graph back to your controller you will reconstruct entities from DTOs and set their state based on IsDirty. This solution needs further extensions for example if your client can also delete relations.
You will query object graph from database and merge your incoming changes to entities retrieved from database.
There are some partial solutions like forcing to save changes to all related objects by setting their state to modified and identifying new objects by Id == 0 but again these solutions work only in specific scenarios.
More complex discussion about this problem.