C# MVC: How to create model for multi step form? - c#

I have multi step form where user completes university registration:
In first form, student fills his personal details. (Name, Email, Mobile)
In second form, student fills marks obtained in high school. (Percentage)
In third form, student fills his parents details. (Name, Email, Mobile)
This finally gets saved to database.
I have created three partial views for these forms.
Should I create 1 c# model class that has all these fields and use it across the three partial views?
OR
Create separate c# model classes for each of these views?
Please note that these form steps may have different layout/number of fields on different platforms like desktop,mobile,apps i.e. we are planning to combine step1 and step2 on desktop and keep them as separate steps on mobile & apps.

Do something Like
public class ViewModel
{
public basic BDetails{get;set;}
public Advanced ADetails{get;set;}
public Personal PDetails{get;set;}
}
public class basic{
.....
}
public class Advanced
{
....
}
public class Personal
{
......
}
use the ViewModel class as your View class

Separate Models and Database Tables.
I did a similar project for a secondary school and the original system was based on flat topography. There ended up being multiple children and redundant information as siblings were enrolled. The data was partially normalized into tables for families, students, schools, subjects and bridge tables to handle the 1:n and n:n relationships between them.
While this took a little longer to implement, it was easier when the system was enhanced to be more user friendly. Schools were pre-populated and able to be selected in a list; the same was done with subjects. Addresses were standardized to conform with post office specifications.
The end result was a very happy client. Besides uniformity of the information, duplicate emails and postal mailings were heavily reduced. They also contracted for further work to add in demographic reporting and identify their recruiting weaknesses and strengths. They contracted with a sister company for marketing too.

First off: I would suggest that you use one model for student and parent(since they have similar properties - Name, Email, Mobile). You could make a Person model and it could have the enum PersonType. PersonType should be Student or Parent:
public class Person
{
public int PersonId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Mobile { get; set; }
public PersonType Person { get; set; }
}
enum PersonType
{
Student,
Parent
}
Next off: only one view is necessary in your case. Use a ViewModel as the model for it. The ViewModel could look something like this:
public class VMStudentDetails
{
public float Percentage { get; set; }
public Person Student { get; set; }
public Person Parent { get; set; }
}

Related

Creating C# objects via MySQL

I would like to get help from you, please :-)
I'm thinking about good way for programmatically creating of classes in C# via MySQL database.
In my app I'm creating composite classes. For example Student, Classroom, Room (dormitory) and so on. Class Student contains properties Classroom and Room. ClassRoom is also related to another entities in database...
public class Student
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Classroom Classroom { get; set; }
public Room Room { get; set; }
}
public class Classroom
{
public int Id { get; set; }
public string Title { get; set; }
public byte Level { get; set; }
public Teacher Teacher { get; set; }
}
...etc
Usually when I need create object of some class, I must create also another classes' objects (sometime a part of database :-) ).
I think this way is not good optimalized, BUT there are great OOP benefits. When I load all students in a DataGridView, I can manage lots of related parts... for example:
Student student = ...
string currentTeacher = student.Classroom.Teacher.LastName //... and so on.
Is OK to create all related classes' objects immediately or is better create only necessary data of current created object and another data load / create "on demand"?
Or absolutely different way? :-)
See, the idea is for you to make a query exactly like what you need an Ingress for a structural database like sql, talking a lot about the EntityFrame mappings where it is possible to query only the student object/table only by its id, however, if no process you will need the Classroom in which it belongs to you use a .Include() no entity and you would only be able to fetch the objects you will need in your request no problem mapping all entities as a bank into objects, the problem is to retrieve all of them from the relation since it only has a feature in some articles
https://learn.microsoft.com/pt-br/ef/ef6/querying/related-data
https://www.entityframeworktutorial.net/code-first/configure-entity-mappings-using-fluent-api.aspx
But if your purpose is performance, mount only the data you need in an object, just an example StudentInfo with the information you need grouped, use a Dapper to make the optimized query and make it do this mapping to your object, gaining performance
this is clear speaking of relational databases like Sql if your case is a NoSql database like MongoDb there is no problem in your mappings since it will return everything in a single document it is structured for this type of information there will be no InnerJoin cost between tables

Model relationships causes trouble with Swagger/endpoints

I have two entities, Classroom, and Student. One-to-many relationships and I use EF Core: one Classroom can have many Students, and one Student can be in one Classroom.
public class Classroom
{
public int ClassroomId { get; set; }
public List<Student> Students{ get; set; }
}
public class Student
{
public int StudentId { get; set; }
public string Name { get; set;
public int ClassroomId { get; set; }
public Classroom Classroom { get; set; }
}
To make this as short as possible I have left out Controller, DataContext, DbSet<> for tables, etc., but I have created it all.
Now, if I run my application and I want to POST a Classroom through Swagger, it includes the list of students in the model schema, so that I have to create the list of students as if it was a property that I wanted to create at the same time as I create a classroom. Similarly, if I want to create/POST a student, it includes the classroom in the model schema.
Instead, I want to be able to create a Classroom and Student separately. When I create a Student, I want to be able to specify only the Classroom Id, so that I can connect students to existing classrooms, not create them same time.
How do I go about this? I am sure I misunderstand something, so I appreciate all help I can get. Thanks
How do I go about this?
You do not expose your database models to the outside world. They are your database models, not your data exchange objects. Nobody but your ORM needs to see them or should see them, you can annotate them so your database layer will know what to do.
Your controller layer should have a set of model classes that you use to talk to the outside world via REST (using swagger). You can build them however you see fit, you can annotate them so your REST layer will understand what to do.
Then you need to map the models you get from the outside world to something you want to do with your database. That should be quite straightforward.

MVC Complex Model Binding to List<T>

I am a new noob at c# MVC and I would really like some help if possible or if someone could kindly point me in the right direction. I have spent hours and hours looking for a solution online and I am yet to find anything helpful which is why I am posting here.
I am working on creating an employee database web application for my company and I have for example the following classes.
namespace my_app.Models.Employee
{
public class Employee
{
public Employee()
{
}
// id
public int id { get; set; }
// employee id/payroll no
public string Employeeid { get; set; }
// employee qualifications
public IList<EmployeeQualification> EmployeeQualifications { get; set; }
}
}
namespace my_app.Models.Employee
{
public class EmployeeQualification
{
public EmployeeQualification()
{
}
// employee Qualification id
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
// employee Qualification institution
public string Institution { get; set; }
// employee Qualification qualificaiton
public string Qualification { get; set; }
public IList<Employee> Employees { get; set; }
}
}
The employee is being added to an EmployeeViewModel which looks something like this:
namespace my_app.ViewModels
{
public class EmployeeViewModel
{
public Employee Employee { get; set; }
// more stuff here
}
}
Now the problem I have and that I need help with is I would like to display the employee (i.e. Name, Address etc) in a view but also be able to list out the employee's qualifications with the ability to add and delete qualifications.
I have seen lots of tutorials out on the web of how to do this via AJAX and Entity framework SaveChanges method and i am sure that will work but the slightly complicated part with what i want to do is that i would like for the changes to remain on the client and only when the whole form including any changes to the employee object is submitted then the changes are persisted to the database.
Is there any way to do this with standard mvc controls or do i have to write a ton of JavaScript to save the changes to a local array of objects and then on the form submit append the additional form data.
I did write a whole bunch of jQuery to kind of get it to work but the issue is that I need to have this functionality on multiple views of the application and to have to write that much code each time does not seem smart.
Any help would be greatly appreciated, thanks.
Hope I can give you a direction to move forward.
Firstly, you need to change your Models design. Basically, 1 employee can have many qualifications and 1 qualification can owned by many employees. So you have many-to-many relationship here. Which means you need 3 models (Employee, EmployeeQualification, Qualification). The 2nd model will hold foreign keys to employee and qualification.
Next thing is UI, you want to keep all changes in UI before doing only 1 submit to persist data. That's actually a very good idea in term of user friendly system design. To do this, you just need to maintain a list of SelectedQualificationIds. Then keep that list in a hidden field, so after submitting, you can just load all qualitifications from DB, compare with the list, and remove/add qualification accordingly.

MVC5 - Proper way to get multiple lists into a view (i.e. Customer Contacts, Customer Locations)

I am using MVC5, EF6 DbFirst, AutoMapper. I have 3 tables: Customers, CustomerContacts, CustomerLocations. I set all of my relationships and updated my model from database. Then I created Model (Dto) classes for each of them (i.e. Model.Customer, Model.CustomerContacts, Model.CustomerLocations)
In my controller I have an Action result called Details and in the Details.cshtml I need to display not only basic customer info but also a list of all the customer's contacts and customer's locations.
In my Model.Customer I added the following properties:
public List<CustomerContact> Contacts { get; set; }
public List<CustomerLocation> Locations { get; set; }
I am trying to figure out how to utilize these properties directly from my Customer object rather than have to pass a Customer and 2 separate lists to my view. Can someone help me with the proper workflow to do something like this in MVC5. It is the only piece I am missing.
Suppose You have Customer Object Like below:
public string Name{ get; set; }
public string CustLevel{ get; set; }
public List<CustomerContact> Contacts { get; set; }
public List<CustomerLocation> Locations { get; set; }
Then in Razor use this model:
#Html.LabelFor(t=>t.Name);
#Html.LabelFor(t=>t.CustLevel);
#foreach(var contactlist in Model.Contacts)
{
#Html.LabelFor(t=>t.ContactNum);
#Html.LabelFor(t=>t.ContactType);
}
AS a suggestion I would say just create a model which contains properties like: Name,Contact,Location,etc.
Then In controller create a List type obejct of your Model. Populate it using your Db and pass it into your View.
Then Comes Display Templates. Add a Folder named DisplayTemplates and create a strongly typed view of your model type and pass that list into It . It will iterate automatically and give you the result.

How to deal with C# object references in MongoDB?

I'm wondering how to handle when an object is used in multiple locations. Given th following code (just example code) :-
public class Group
{
public ObjectId Id { get; set; }
public string Name { get; set; }
public List<Person> People { get; set; }
public List<Meeting> Meetings { get; set; }
}
public class Meeting
{
public string Subject { get; set; }
public List<Person> Attendees { get; set; }
}
public class Person
{
public string Name { get; set; }
}
If I store the group as a mongodb document, it will serialize all the people and meetings. However the same Person object can be refered to in the People List and as an attendee of a meeting. However once serialized they become separate objects. How can I maintain that the same "Person" object is both in the People list and Meetings list?
Or is there are better way to model this? One thing that could be done is put the "People" in a separate Document and embeded / reference it? This then starts to create more and more separate collections, ideally I'd like to maintain references within a single document.
Or within a document should I Id each person and have one master list and then only store lists of Ids in the "Meetings" and use some kind of helper method to resolve the Id from the master list? Can be done, but a little bit ugly.
I'm not an expert with MongoDB but I think in this scenario each of these items should be a separate collection with references to get the results you are after.
Meetings have a Group ID and a list of Person ID attendees.
Groups have a list of Person ID members (people).
If a person can only belong to one group then they can have a single group ID.
Once they go into the database the only option you have with your existing design is checking for name equality which as you say can be done but doesn't seem like the right approach.
Essentially you are using the embedded relationship model with how you are storing 'Person' in 'Group' and 'Meeting' but if you want the same 'Person' object for both then you need to use references for Attendees or both. This seems like the simplest approach to me while not 'fighting' against the standard behaviour.

Categories