Matteo Fontana
Matteo Fontana

Reputation: 73

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

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?

Upvotes: 7

Views: 12544

Answers (1)

mnemosyn
mnemosyn

Reputation: 46291

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.

Upvotes: 14

Related Questions