How to deal with C# object references in MongoDB? - c#

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.

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

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.

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

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; }
}

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.

Modifying specific item in nested collection in RavenDB

I have something that looks like the following document structure:
public class Document {
public int Id { get; set; }
public string Name { get; set; }
public List<Property> Properties { get; set; }
}
public class Property {
public int Id { get; set; }
public string Name { get; set; }
}
Now, querying and modifying Documents is easy. But I need to access specific Property-instances in my app, and it seems that they won't automatically get an ID like the root document does. And it seems this is by design in RavenDB.
I might be me stuck in the relational world, but what I'd like to do is basically retrieve the correct document, then get the right property, modify it and save the document again.
from property in document.Properties
where property.Id == someId
select property
...which will obviously not work as long as
RavenDB does not auto-set the Id field or
I don't make any ID-generating mechanism myself
Am I heading completely the wrong way, or does what I'm trying to do mak sense? Should I move the Properties out to being a root node and make some sort of reference to them in Document? Or should I just do something like this when inserting properties:
Retrieve the document with the list of properties
Get Properties[last]'s ID
Add 1 and insert new ID myself in new properties
?
This would, however, require at least two requests (one to get existing properties, one to save the changes) to the database, which just seems dirty and unnecessarsy for such a seemingly simple task.
I've found a lot of sortof similar posts, but none of them really answers this AFAIK.
Check to see how we do that in RaccoonBlog:
https://github.com/ayende/RaccoonBlog/blob/master/RaccoonBlog.Web/Infrastructure/Tasks/AddCommentTask.cs

Categories