MongoDb relationship - c#

In my Domain layer, I have the following two Entities for mongodb collections
public class League
{
public ObjectId Id { get; set; }
public string LeagueName { get; set; }
public List<ObjectId> Teams { get; set; }
}
public class Team
{
public ObjectId Id { get; set; }
public string UserId { get; set; }
public string Teamname { get; set; }
public int Rating { get; set; }
}
Service layer
private static IEnumerable<ObjectId> GetTeamsNotInSeason(Season season, IEnumerable<Team> teams )
{
var teamsInSeason = season.Leagues.Where(x => x.Teams != null).SelectMany(x => x.Teams).ToList();
return teams.OrderByDescending(x => x.Rating).Select(x => x.Id).Except(teamsInSeason);
}
So each League has a list of Teams, referencing use ObjectId. But that means in my service layer it needs to know about ObjectId, hence I have to have a mongoDb reference in there. So my question is, do you have to store relationship references as a type of ObjectId, What is the normal standard for relationships in mongodb? Within c#

Yoe need to analyze first the reads vrs the writes that you are going to have in the database.
Some basic rules:
If you'll perform more reads than writes then embed as much as you can, that will improve read performance and allow to read data in a single call to the database. The choice embed or not is usually made on how data will grow, change over time and how you gonna query it.
Consider de-normalization of data for fast querying, sometimes duplicated name on other collection is not that bad as long you avoid to do multiples queries to the database.
other notes:
Denormalization always add some overhead to writes, but increase read speed. For your case I assumed will be more reads than writes and heavily used denormalization.
When reading data consider excluding fields from object when you no need them, proyections doesn't work very well on c# using linq but there are some workarounds for this particular issue so just be aware of it.
EDIT:
if you plan to have more reads than writes probably you can have a single collection with all the imofrmation.
public class League
{
public ObjectId Id { get; set; }
public string LeagueName { get; set; }
public List<Team> Teams { get; set; }
}
EDIT:
The best datatype to creating references between objects is ObjectId, however I'd be great for you to check the escenarios for data modeling in the case you haven't looked at it.

Related

Adding run-time only collection to OData list

I'm new to OData and I have a working solution for complex requests of my domain data, which is great. The bit I'm looking for help with is using this data and sending the entire list to another API to append additional data to the OData response for a particular object type.
I don't mind losing the ability to further query the appended collection, this can be done later in my front end. I'm looking for some help in identifying the right architecture for my solution.
I've seen a few possible answers that would be to create a custom serializer or use AutoMapper to populate the DTO but this would send the requests to the other API one at a time. I'm looking to send the entire list as the performance is improved rather than one at a time as there can be 20,000+ items in the response.
Here's my current schema.
Domain
public class InventoryItem
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual string DeviceName { get; set; }
}
DTO
public class InventoryItem
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual string DeviceName { get; set; }
public IList<ReadingDto> Readings { get; set; } = new List<ReadingDto>();
}
public class ReadingDto
{
public double? Value { get; set; }
}
As the ReadingDto is obtained from another API, this shouldn't be present in my domain model. It would never be populated.
The ideal solution would be to utilise a service within my project which would send the list over to the other API whilst maintaining the flexibility of using OData. Whether this is in a custom serializer, middleware or filters, I'm just not sure what would be best.

Store ObjectId instead of full object

How can I Store ChatRoom with only the SiteId instance of full object ?
thanks
public class ChatRoom
{
public ObjectId Id { get; set; }
public DateTime StartDate { get; set; }
public **Site** **Site** { get; set; }
}
That's pretty straightforward if you're willing to change the model:
public class ChatRoom
{
public ObjectId Id { get; set; }
public DateTime StartDate { get; set; }
public ObjectId SiteId { get; set; }
}
However, that means that you need to ensure referential integrity yourself. For instance, if the Site you want to refer to hasn't been stored yet, you will first have to store the Site in the database, then store the ChatRoom with the SiteId set to the Id of the referenced Site - otherwise, there's no Id to refer to.
More importantly, that means you're no longer working with an object graph, or domain model in your code. This has impact on your entire code architecture.
For example, you can't build expressions like MyUser.ChatRoom.Site.Owner.Address.Street. That has disadvantages, because you effectively can't implement a domain model at all, but it also comes with advantages because it's unclear when the freight trains actually would talk to the database.
However, these 'freight trains' are often dangerous, because it's unclear when the respective elements are loaded from the database.

mongodb C# driver not generating ObjectId of newly added document in embedded list of objects when using Update.Push

I am using mongodb C# driver and trying to add "Goal" Entity in the "List", contained in Client class, but mongodb always returns an empty objectId og Goal.
Client.cs
public class Client
{
public string UserName { get; set; }
[BsonId]
public ObjectId ClientId { get; set; }
[BsonIgnore]
public string ClientIdString
{
get
{
return this.ClientId.ToString();
}
}
[BsonRequired]
public string ClientName { get; set; }
public string EmailAddress { get; set; }
public string CompanyName { get; set; }
public List<Goal> Goals { get; set; }
}
Goal.cs
public class Goal
{
public ObjectId GoalId { get; set; }
[BsonRequired]
public string Title { get; set; }
public string Description { get; set; }
[BsonDefaultValue(State.NotStarted)]
public State GoalState { get; set; }
[BsonIgnore]
public string StateString
{
get
{
return this.GoalState.ToString();
}
}
}
and i am trying to add Goal to client with following code:
IMongoQuery query = Query<Client>.EQ(eq => eq.ClientId, id);
IMongoUpdate update = Update<Client>.Push<Goal>(push => push.Goals, goal);
WriteConcernResult result = this.ClientCollection.Update(query, update);
But every time mongodb returns an empty objectId of newly added Goal in the List in client.
Kindly guide me what i am doing wrong?
Thanks in advance. :)
Kindly guide me what i am doing wrong?
Nothing really, but you're expecting the wrong behavior.
Embedded documents don't have an _id. Of course, you can force mongodb to create a field that happens to have that name, but unlike the root _id, such a field has no special semantics and there's no default index. The lack of these special semantics is also the reason why the driver doesn't bother generating a value for the field for you.
Generally speaking, having a unique index in an embedded document is often a sign of a malformed data structure. Make sure such an id is strictly required. If the id must be globally unique, it appears the embedded document might also make sense or be relevant if it had another parent, which indicates that it should be a first-level citizen, i.e. have a collection of its own.
Remember that this also a question of ownership - what happens with concurrent writes? Of course, you can go to great lengths and only use atomic modifiers to allow different writes to one document, but that is unnecessarily complicated IMHO.

Should I be using a DTO when passing data from my server to clients?

I feel like I've gone and over-complicated my design by using DTOs, but I'm looking for a second opinion.
My structure is:
User <- One-to-Many -> Playlist <- One-to-Many -> PlaylistItem <- One-to-One -> Video
As such, a PlaylistItem domain object looks like:
public class PlaylistItem
{
public virtual Guid Id { get; set; }
public virtual Playlist Playlist { get; set; }
public virtual int Sequence { get; set; }
public virtual string Title { get; set; }
public virtual Video Video { get; set; }
// Not written to the database. Used for client to tell who is who after a save.
public virtual string Cid { get; set; }
}
and a PlaylistItem DTO looks like:
[DataContract]
public class PlaylistItemDto
{
[DataMember(Name = "playlistId")]
public Guid PlaylistId { get; set; }
[DataMember(Name = "id")]
public Guid Id { get; set; }
[DataMember(Name = "sequence")]
public int Sequence { get; set; }
[DataMember(Name = "title")]
public string Title { get; set; }
[DataMember(Name = "video")]
public VideoDto Video { get; set; }
[DataMember(Name = "cid")]
public string Cid { get; set; }
}
The only change is that I have broken the circular-referential structure by replacing the Playlist reference with a PlaylistId.
The default JSON serializer in C# .NET MVC was unable to handle circular structures. I've since updated to using the JSON.NET serializer which is capable of handling circular structures. I'm now re-evaluating why I even need my DTO.
Are there any benefits of a DTO that I should be aware of / considering here? Is it bad practice to JSONize a circular reference and send it across the wire?
JSON, being a hierarchical format, is going to work best when representing data in a hierarchical fashion. JSON isn't a node graph, so trying to serialize graph-like data is going to prove difficult, I think. I think your solution of converting an object (Playlist) to a form of "reference" (PlaylistId) is the correct one. The code receiving and processing this JSON can reconstruct the circular reference, if necessary, since you have your "foreign key" (PlaylistId) in place.
Most of the time I would rather have an extra DTO than none at all. DTOs insulate you from change--in this case, insulate your API from change. PlaylistId is unlikely to change its schema in the future, but the actual Playlist might.
Are there any benefits of a DTO that I should be aware of / considering here?
Design. THis is a public API and you want to make sure it is sable, while the internal objects are / can change without a lot of review. Changes in data types are a lot more problematic if this is an "out of the server" style interface and you do not want to force API updates (client updates) every time you do a minor change.
As such, having API level definition objects (DTO) separately defined helps with this part of not changing a public interface.

Class linking best practices in C#

First off, EF is not an option for our development environment so please no "just use EF" answers ...
I think this is a pretty standard dilemma so I'm sure there must be a way that most Pros do it that I just have not stumbled across ... so I'm out here hoping y'all can show me what it is.
Let's say you have the following database tables:
tblCompanies
ID
NAME
tblDepartments
ID
COMPANY_ID
NAME
tblEmployees
ID
DEPARTMENT_ID
FIRSTNAME
LASTNAME
... what's the best way to represent this in Classes within your code?
I assume the best way is like this:
public class Company
{
public int ID { get; set; }
public string Name { get; set; }
public List<Department> Departments { get; set; }
}
public class Department
{
public int ID { get; set; }
public string Name { get; set; }
public List<Employee> Employees { get; set; }
}
public class Employee
{
public int ID { get; set; }
public string FirstName { get; set;}
public string LastName { get; set; }
}
I believe that to the be the "OOP Proper approach" to this. However, what seems to always happens is something like this:
public class Department
{
public int ID { get; set; }
public string Name { get; set; }
public int CompanyID { get; set; }
public List<Employee> Employees { get; set; }
}
... mainly because when you pull just a Department from the database you are only going to have Company ID, not all the other attributes needed to fully populated an instance of the Company class.
(I've used a pretty vanilla example here but the one I'm actually tackling in my current project has 3 fields that it uses to link the data together so the thought of having the same 3 fields in several classes seems wrong to me)
Is there a Best Practice for these scenarios? As much as I don't like the thought of storing the same data in multiple classes just out of laziness, I also don't like returning an instance of a class with just one of its fields populated because that's all I had at the time.
This is a common problem, and one that ORMs try to solve. To be sure it isn't an easy one depending on what your wants are and what your constraints are.
There are only two fundamental options to keep one copy of the information. Lazily load the data as requested or load it all to begin with (Greedy load). Otherwise you have to duplicate the data.
With lazy loading you basically set things up such that when navigating into a property you make a call to the database and grab the information needed to load the entity representing the property you are accessing. The tricky part to watch with this is the SELECT N + 1 problem. You experience this problem when you end up iterating a set of parent entities and trigger lazy loads on every child entity, thus resulting in N+1 calls to the database to load a set of entities (1) and their children (N).
Greedy loading basically says load everything you need to start with. ORMs (where they work) are nice because they take care of many of the details via LINQ and create solutions that can be performant and maintainable usually along with the ability of allowing you to manipulate the usage of Greedy and Lazy Loading.
Another important gotcha is many to many relationships. You need to make sure not to have circular initialization, and get all the baggage of circular dependencies. There are surely many more I have missed.
In my humble opinion I am not so sure there is a best practice as much as there are practices with some of them bad - nothing is perfect. You can:
Start rolling your own object relational mapper allowing you to get rid of the duplicate ID
Use a lighter ORM framework to handle some of this allowing you to get rid of the duplicate ID
Create specialized queries to load aggregations of data allowing you to get rid of the duplicate ID (* cough * DDD)
Just keep the duplication of the ID like you mention above and not worry about creating an explicit relational model in your domain.
This one is on you to choose what is best based on your constraints. This is a deep topic and my experience is limited...so take what I am saying with alot of salt.
I don't think there's a "best practices" manual for this kind of things, and surely it depends on how your classes are going to be used. But in my personal experience, I have ended up following this approach:
public class Company
{
public int ID { get; set; }
public string Name { get; set; }
public IEnumerable<Department> GetDepartments()
{
// Get departments here
}
}
public class Department
{
public int ID { get; set; }
public string Name { get; set; }
protected int CompanyID { get; set; }
private Company _Company;
public Company Company
{
get
{
// Get company here
}
}
public IEnumberable<Employee> GetEmployees()
{
// Get employees here
}
}
public class Employee
{
public int ID { get; set; }
public string Name { get; set; }
protected int DepartmentID { get; set; }
private Department _Department;
public Department Department
{
get
{
// Get department here
}
}
public IEnumberable<Employee> GetEmployees()
{
// Get employees here
}
}
In some cases I have exposed some of the "navigation" properties of my classes as public (like CompanyID and DepartmentID) to prevent the instantiation of a new class to get a value that has been loaded already.
As others have noted, you could also simulate "lazy loading", but this will require some extra effort from your part.
I would think it depends on requirements. Do you need to traverse upward (get company from department, department from employee, etc). If you do, then it is best that you provide a means of doing that. Ideally that would be something like a Company or Department property, of course you wouldn't want to get data you don't really need, so you'd likely keep a private company id and have a public getCompany function which queries for the data.
I believe that this is not a really OOP question, in your case you just have an database model (database representation in classes) which does not contain any logic and all the classes are used as structs, and this is a right way to map your database to classes - structs. So in your next module which will represent the logic of your program you have to map your database module to the real classes which will contain the logic (I mean methods which will implement it) of course if you really need them. So in my opinion the OO question should be in the logic part of your application. On the other hand you could take a look on nhibernate and how the mapping done in there it will give you a hint for the bes database model implementation.
I believe this is what your classes would look like in NHibernate:
public class Company
{
public int ID { get; set; }
public string Name { get; set; }
public IList<Department> Departments { get; set; }
}
public class Department
{
public int ID { get; set; }
public string Name { get; set; }
public Company Company { get; set; }
public IList<Employee> Employees { get; set; }
}
public class Employee
{
public int ID { get; set; }
public string FirstName { get; set;}
public string LastName { get; set; }
public Department Department { get; set; }
}
Note that there is a way to navigate from Employee to Department and from Department to Company (in addition to what you already specified).
NHibernate has all kinds of features to make that just work. And it works very, very well. The main trick is run-time proxy objects to allow for lazy loading. Also, NHibernate supports a lot of different ways to eager and lazy load just exactly how you want to do it.
Sure, you can get these same features without NHibernate or a similar ORM, but why wouldn't use just use a feature rich mainstream techology instead of hand coding your own feature poor custom ORM?
There is another option. Create a 'DataController' class which handles the loading and 'memoization' of your objects. The dataController maintains a dictionary of [CompanyIDs, Company objects] and [DepartmentIDs, Department objects]. When you load a new Department or Company, you keep a record in this DataController dictionary. Then when you instantiate a new Department or Employee you can either directly set the references to the parent objects OR you can use a Lazy[Company/Department] object and set it using a lambda (in the constructor) which will maintain the scope of the DataController without it being referenced directly inside the objects. One thing I forgot to mention, you can also place logic in the getter / get method for the Dictionaries that queries the database if a particular ID is not found. Using all of this together allows your Classes (Models) to be very clean while still being fairly flexible as to when / how their data is loaded.

Categories