RavenDB Relational Model - c#

I'm working on a side project to create a Forum built on top of RavenDB. I am currently trying to work out the relationship between Authors of Topics, and the "Last Reply" user on a topic. In a typical relational model I would simply store the FK to the User who posted the topic, and have a join off to the replies table to get the most recent replies author. This is obviously not the use case for Raven or any Document store for that matter.
What would be the most "optimal" way of pulling this off? Currently I'm tossing around a couple ideas.
Idea 1:
Save the FK of the Author on the Topic model, add a JsonIgnored User object that I will populate on the Topic load by using an Include in my session load (so one request so far from the client side, just makes the Load itself and model a bit complicated). Then possibly using a map-reduce index to get the most recent replies author (or even the same method as getting the Topic Author, so 1 or 2 queries depending).
Idea 2:
Saving both the Author and the most recent reply User on the model. Main "problem" here is the potential for stale data (say if a username changes). However that could potentially be alleviated with a background task (or simply keeping that in mind when updating a user document and going back over all posts from a user).
Example of the models in question.
public class User
{
public string Id { get; set; }
public string UserName { get; set; }
public string PasswordHash { get; set; }
}
public class Topic
{
public string Id { get; set; }
public string Title { get; set; }
public string Body { get; set; }
// Idea 1 Relationships
public string AuthorId { get; set; }
[JsonIgnore]
public User Author { get; set; } // Would need to be populated on loads from an Include on AuthorId
public string MostRecentReplyUserId { get; set; }
[JsonIgnore]
public User MostRecentReplyUser { get; set; } // Same as Author
// Idea 2 Relationships
public User Author { get; set; }
public User MostRecentReplyUser { get; set; }
}
Note: I would likely add a method to the User model to return a "clean" version where I scrub out things like the PasswordHash and use that on the Save for Idea 2.

Depending on your needs in case of update and query performance both ways may be the better choice.
I personally would recommend the first idea because you don't need to update existing documents when some data changes on the user records. Using include on query/load time is quite a nice feature of ravendb which can help you when retrieving nested records from the database.
Just make sure that you don't forget to include all nested documents - otherwise you may get many roundtrips.
Embedding documents (like Idea 1 but with a stored value of the users) may be better if your data processing is seperated from the data retrieval and you don't have access to the database session when converting data to be handed out to the frontend. We're using such a system that heavily relies on that (getting one input and mapping out a json pendant of the value) - this seperates data retrieval logic completely from the output (like mapping to json) logic.
Downside here: You've to make sure that existing (embedded) data get's updated whenever a user changes and the data that is transferred over the wire is more than on idea 1.

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.

Domain Design crossing Aggregate Root Boundaries

I'm a novice DDD'er and struggling with my first attempt to implement some of these concepts. I am writing an application to manage some marketing campaigns for different users, so a Campaign is an obvious aggregate root, but I also have Users as an aggregate root.
public class Campaign : IDomainObject
{
public virtual int CampaignId { get; set; }
public virtual string Name { get; set; }
...
public virtual int UserId { get; set; }
...
public virtual IList<CampaignEvent> Events { get; set; }
}
public class CampaignEvent
{
public virtual int CampaignEventId { get; set; }
public virtual int CampaignId { get; set; }
public virtual int UserId { get; set; }
...
}
So now when I search for a list of campaigns to display, how do I get the User's name from the Id?
If I design the model with a database-agnostic perspective, I would add a UserName string to both objects and develop from there. However, I have to be practical and consider how this will eventually go back-and-forth to the database, and it doesn't appear that this new model will work with the ORM (presently NHibernate, but I don't believe this is possible with EF either).
What are some meet-in-the-middle solutions that will accomplish the goal of getting some user information available in the object, without compromising the concepts of DDD?
I think the key here is that you want to change the thought process to entity to entity or value object relationships.
In the way you are modeling your classes, you have a UserId as a property and are talking about it as if it was a relationship. I think what you are wanting to convey is a relationship between the Campaign and a User, a CampaignEvent and a User, etc. It is perfectly acceptable for a Campaign to be an Aggregate Root and a User to be an Aggregate Root. When you search for a campaign, it will have a relationship to a User, so how you get the name is by getting the Name from the User entity. We don't want to speak about Id's alone, as this breaks our representation of the real entity we are trying to model. So a campaign has a/a collection user/users, and a user has a/a collection of campaign/campaigns, as opposed to a campaign has a userid.
If you would like to display the user name from some result set that you got from your ORM/domain model then this is a somewhat of a problem. You should not query your domain model. So how to do it then?
Well, you should try to incorporate a query/read model. A very simple query layer should be developed. To get the data, you have a couple of options. You probably want to opt for some denormalisation along the way. You could add the user id and name as a value object to your aggregate so that it is stored in your transactional store. Your query would be able to access that and have the data readily available; else your query side would need to do a join.
You could also go with eventual consistency via a truly read-specific store that contains view-specific tables.
This approach will probably bring up some more questions but it really is not as cumbersome as it may appear.

Consecutive IDs in a navigation property List

I'm trying to make a discussion forum in ASP.NET MVC 5 (mostly as a test as I'm pretty new to C#/MVC/any coding).
I have two classes, Discussion and Message.
public class Discussion
{
public int DiscussionID { get; set; }
[Required]
[Display(Name="Discussion Title")]
public string DiscussionTitle { get; set; }
//[Required]
//ForumUser UserCreatedThread { get; set; }
[Required]
DateTime CreatedTime { get; set; }
public ICollection<Message> Messages { get; set; }
}
and
public class Message
{
public int MessageID { get; set; }
public int MessageNumber { get; set; }
[Required]
[Display(Name="Message Content")]
[DataType(DataType.MultilineText), AllowHtml]
public string Content { get; set; }
[Required]
public DateTime MessageTime { get; set; }
public virtual int DiscussionID { get; set; }
}
Discussion has a list of Messages which I would like the MessageID, or another property to be ordered 1,2,3,etc for each list. Currently if more than one discussion is created the MessageID can be 1,4,5,8,etc.
I started using a static method in the GetMessage() and GetDiscussion() methods to fix the IDs as the messages were returned to the controller by ordering the threads by the MessageID then iterating over them to change the values to 1,2,3,etc.
Now I've changed that to add a MessageNumber property, save the message to the database when a new message is created (using EF6), retrieve the message, get the count of messages, update MessageNumber to the count and save the changes.
The latter works but I assume could cause problems if a new message is created between saving the message then retrieving the count. Two messages would have the same MessageNumber.
Is there a better way to do this or a should I use a different way to access the messages that doesn't need the ID?
The id is just the key for the table; it's not really intended to be part of the UI, even though you commonly see ids floating around in URLs across the web. It's far better to expose and use something like a slug for user-facing scenarios.
Regardless, though, what you're trying to do is really not possible. The id is typically set as an identity column, and is auto-incremented for each row in the table. Even if you don't rely on auto-increment and set it manually, you still need to ensure a unique value for each one (i.e., you can't repeat id 1 for multiple rows. The only way around this would be to create a composite key utilizing a manually set id and something like the foreign key to the Discussions table, but that's really, really, not a good thing to do. Please, don't do that. Not only would any good DBA smack you for using a foreign key as part of a composite key for another table, but then you have a ton manual work to do each time you want to save a new message.
My best advice is to just not worry about the id. If you want a consecutive number, you can create another property much like the MessageNumber property you have already and put anything you want in that as long as it's not a key or index for the table. That means you can't (or at least shouldn't) actually retrieve anything using that field. You would still need to lookup by the actual row id, or something like a slug, as mentioned earlier.
I'm not sure why you want to do what you want to do, but if your implementation of Messages is a List, then you can use an index and add one to it. An indexes are by nature consecutive numbers. You would do that something like this:
int index = Messages.FindIndex(message => message.MessageID = theID);
If you want something a little more flexible:
Messages.Select((m, index) => new { index, Message = m })
.Single(message => message.MessageID == theID);

How to save an entity's change history

I have a Task entity with various navigation properties, including a Comment entity:
public Comment {
public int ID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public DateTime CreateDate { get; set; }
public DateTime LastEditedDate { get; set; }
public virtual User User { get; set; }
}
A comment can be edited, and I want to keep a history of all such changes. Think of the way Stackoverflow allows you to edit your questions/comments, but keeps a history of changes.
Keeping a history means more complexity, and it becomes harder to maintain. My options:
add properties such as public virtual ICollection<string> DescriptionHistory { get; set; }, and a similar one for Title, User, EditDate, etc. It gets out of hand very quickly.
keep the Title, Description, etc. properties as strings, but make them CSV strings and stuff all those changes into a fewer set of properties. This means more processing, but the entity is simpler. The problem is that it becomes tricky to associate one CSV fragment with the corresponding one from a different property, eg a historical title must match its historical description and date.
do both, have the current set of properties, and another single set of nullables like TitleHistory, DescriptionHistory, etc., which are CSV strings of older versions, and so it only gets complicated when you are dealing with the historical stuff.
Also there are problems around the storage of the user, unless I use a CSV of IDs rather than the entities.
What is the best approach to this problem? There are various techniques such as sprocs and "insert only" tables - but I am using Entity Framework 5, and so prefer a solution which leverages the technology I am already using.
I've settled on using an "insert only" table. Pity it's not easy to do with EF5.

Categories