Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB C# entity Mapping: "one to many relation"

Tags:

c#

mongodb

I'm new to MongoDb, but i am aware that speaking about relation in a document db is something that smell. Anyway i'm trying it just to understand if it fits my needs and where are its limits.

I've just a simple c# entity in my domain that is:

class Person
{
    public int Id { get; set; }

    public string Name { get; set; }

    public string Surname { get; set; }

    public ICollection<Person> Friends { get; set; }
}

And i just want that the serialization process makes that collection a sort of list of

["...api/persons/1", "...api/persons/2", ...]

is it possible in some way?

like image 830
Matteo Fontana Avatar asked Mar 06 '15 18:03

Matteo Fontana


People also ask

Can I use MongoDB with C++?

Welcome to the documentation site for the official MongoDB C++ driver. You can add the driver to your application to work with MongoDB using the C++11 or later standard. Download the library, mongocxx , from mongocxx.org or set up a runnable project by following our tutorial.

What is a MongoDB driver?

The official MongoDB Node. js driver allows Node. js applications to connect to MongoDB and work with data. The driver features an asynchronous API which allows you to interact with MongoDB using Promises or via traditional callbacks.

What is TDocument in C#?

TDocument. The type of the documents stored in the collection.


1 Answers

relation in a document db is something that smell

No, not at all. Sadly, that notion is popular, but there's nothing wrong with relations in non-relational databases. It's just a different approach to manage those relations.

But let's look at your model:

public ICollection<Person> Friends { get; set; }

As you have probably figured out, that would serialize a tree of documents:

{ "name" : "doe",  
  "firstName" : "john", 
  "friends" : [ 
      { "name" : "rogers", 
        "firstName" : "mike", 
        "friends" : [ {"name" : "myers", "firstName" : "lucy", ... },  
        ... ] },
 ... ] }

In other words, these would not serialize as relations, but as embedded documents.

Now the easiest and cleanest approach is to store relations if you want relations:

class Person {
    public ObjectId Id { get; set; }
    public string FirstName { get; set; }
    public List<ObjectId> FriendIds { get; set; }
}

That will require manually translating from your domain model to a database-compatible model, which begs the question why you want a domain model in the first place.

The problem with domain models is that they require a partially serialized graph in RAM. That seems convenient to work with from the .NET side, e.g. you could do something like

person.Friends.First().Friends.Where(p => p.Name == "Doe").Friends.Last...

But it's utterly unclear how to fetch all this from the database, because that simple one-line expression would probably require at least 4 round-trips to the database. While such a mapping can be implemented (transparent activation), it hides a lot important information from the programmer.

If you add modifications (and modification tracking) to the equation, things get very messy very quickly.

Also, the model looks like an m:n relation to me (a person can have many friends, and a person could be referenced as friends by many other persons, right?). For m:n relations, embedding lists of references might not be the best approach, but there are alternatives.

like image 162
mnemosyn Avatar answered Oct 08 '22 17:10

mnemosyn