如何在Mongo DB中保存对对象先前版本的引用

时间:2019-05-31 09:29:57

标签: c# mongodb

我正在尝试开始使用MongoDB。我曾经使用过关系数据库引擎,但现在我必须根据要求使用MongoDB。

我正在尝试尽可能简化地解释我的一般性问题。想象一下是Person。您有一些特征,例如姓名或一些朋友。现在您已经去世了,并以新人类的身份出生。您现在可以使用其他名称和不同的朋友。

现在,您不喜欢新的“您”,而是想返回自己的上一个版本,也许是因为您更喜欢这个名字或朋友。

为此,将Person绑定到Soul上,后者仅存储当前的Person以及以前的所有内容。

现在,当您将该对象存储在MongoDB中时,您会很快得到一个非常大的文档(在我的案例中,行数超过了13000行)。我创建了一个类似的JSON结构来突出此问题。

    "Souls:" {
        "UniqueId": {
            "CurrentPerson": {
                "Name": "Jane Doe",
                "PreviousLifePerson": {
                    "Name": "John Doe",
                    "PreviousLifePerson": {
                        "Name": "Max Mustermann",
                        "PreviousLifePerson": {
                            "Name": "Erika Mustermann",
                            "PreviousLifePerson": null 
                        }
                    }
                }
            }
        }
    }

我已阅读到MongoDB默认将相关对象保存为嵌入式文档。 解决此问题的方法可能是通过对象的ID保存关系。但是,我仍然不确定这是否真的是最好的解决方案,此外,我对.NET MongoDB驱动程序的常规最佳做法有一些疑问。

在C#中,我可能会拥有一个像这样的类:

    public class Person
    {
        [BsonId]
        public ObjectId Id { get; set; }

        [BsonElement("Name")]
        public string Name { get; set; }

        [BsonElement("Friends")]
        public List<ObjectId> FriendIds { get; set; }
        [BsonIgnore]
        public List<Person> Friends { get; set; }


        [BsonElement("Reincarnation")]
        public int Reincarnation { get; set; }

        [BsonElement("PreviousLifePerson")]
        public ObjectId PreviousLifePersonId { get; set; }
        [BsonIgnore]
        public Person PreviousLifePerson { get; set; }
    }
  1. 对于每个被忽略的元素,我都必须向数据库发送一个附加查询并检索这些元素。这是正确的吗?

  2. 那我将为SoulPerson提供一个个人收藏,即使一个人总是被分配一个灵魂?

  3. 在没有显式指定对象ID作为属性的情况下,肯定没有从数据库反序列化对象的内置方法,是吗?

1 个答案:

答案 0 :(得分:1)

since this is a highly relational problem domain, i would do it with MongoDB.Entities convenience library. here's a full program covering all the bases you mentioned.

using MongoDB.Entities;
using System.Linq;

namespace StackOverflow
{
    public class Program
    {
        public class Soul : Entity
        {
            public Many<Person> Incarnations { get; set; }
            public One<Person> CurrentIncarnation { get; set; }

            public Soul() => this.InitOneToMany(() => Incarnations);
        }

        public class Person : Entity
        {
            public string Name { get; set; }
            public One<Soul> Soul { get; set; }
            public One<Person> PreviousLife { get; set; }
            public Many<Person> Friends { get; set; }
            public bool IsDead { get; set; } = false;

            public Person() => this.InitOneToMany(() => Friends);
        }

        static void Main(string[] args)
        {
            new DB("test");

            //big bang
            var god = new Soul();
            god.Save();


            //first man is born
            var adam = new Person
            {
                Name = "Adam",
                Soul = god.ToReference()
            };
            adam.Save();
            god.Incarnations.Add(adam);
            god.CurrentIncarnation = adam.ToReference();

            //first woman is born (without a soul ;p)
            var eve = new Person
            {
                Name = "Eve",
            };
            eve.Save();

            //adam and eve become friends under an apple tree
            adam.Friends.Add(eve);
            eve.Friends.Add(adam);

            //adam dies and comes back as sally
            adam.IsDead = true; adam.Save();
            var sally = new Person
            {
                Name = "Sally",
                Soul = god.ToReference(),
                PreviousLife = adam.ToReference()
            };
            sally.Save();
            god.CurrentIncarnation = sally.ToReference();
            god.Incarnations.Add(sally);

            //sally and eve feel a deep connection
            sally.Friends.Add(eve);

            //sally feels stuck in a mans body, so she goes back to being adam
            sally.IsDead = true;
            sally.Save();
            god.CurrentIncarnation = adam.ToReference();
            god.Save();
            adam.IsDead = false;
            adam.PreviousLife = sally.ToReference();
            adam.Save();

            //invite sally's friends to the funeral
            var guestlist = DB.Find<Person>().One(sally.ID)
                                             .Friends.Collection()
                                             .ToList();
        }
    }
}

the library stores relationships by using special join collections which are automatically indexed which makes queries extremely fast.

my personal rule of thumb is to not embed an object inside another if there's gonna be more than a handful of them in there. but it all depends on how your app queries the data, what data is needed by your apps views. with MongoDB.Entities you have the freedom to do both quite easily.