如何在LiteDB中实现级联包含

本文关键字:实现 级联 包含 LiteDB | 更新日期: 2023-09-27 18:13:26

这里是关于如何在LiteDB中存储交叉引用实体的示例。LiteDB完全可以存储交叉引用的实体,但是当我试图找到/加载实体时,问题就来了。我的目标不仅是被请求的实体,还有被引用的实体。在LiteDB网页上有一个快速教程章节"DbRef用于交叉引用",如何实现它。LiteDB有"Include"选项(在"FindAll"之前调用),它表示必须加载哪些引用实体。我试图在这个代码示例中实现它,但没有结果,即代码引发异常("D_Ref"),意思是"D_Ref"引用未加载:

namespace _01_simple {
using System;
using LiteDB;
public class A {
    public int Id { set; get; }
    public string Name { set; get; }
    public B B_Ref { set; get; }
}
public class B {
    public int Id { set; get; }
    public string Name { set; get; }
    public C C_Ref { set; get; }
}
public class C {
    public int Id { set; get; }
    public string Name { set; get; }
    public D D_Ref { set; get; }
}
public class D {
    public int Id { set; get; }
    public string Name { set; get; }
}
class Program {
    static void Main(string[] args) {
        test_01();
    }
    static string NameInDb<T>() {
        var name = typeof(T).Name + "s";
        return name;
    }
    static void test_01() {
        if (System.IO.File.Exists(@"MyData.db"))
            System.IO.File.Delete(@"MyData.db");
        using (var db = new LiteDatabase(@"MyData.db")) {
            var As = db.GetCollection<A>(NameInDb<A>());
            var Bs = db.GetCollection<B>(NameInDb<B>());
            var Cs = db.GetCollection<C>(NameInDb<C>());
            var Ds = db.GetCollection<D>(NameInDb<D>());
            LiteDB.BsonMapper.Global.Entity<A>().DbRef(x => x.B_Ref, NameInDb<B>());
            LiteDB.BsonMapper.Global.Entity<B>().DbRef(x => x.C_Ref, NameInDb<C>());
            LiteDB.BsonMapper.Global.Entity<C>().DbRef(x => x.D_Ref, NameInDb<D>());
            var d = new D { Name = "I am D." };
            var c = new C { Name = "I am C.", D_Ref = d };
            var b = new B { Name = "I am B.", C_Ref = c };
            var a = new A { Name = "I am A.", B_Ref = b };
            Ds.Insert(d);
            Cs.Insert(c);
            Bs.Insert(b);
            As.Insert(a);
        }
        using (var db = new LiteDatabase(@"MyData.db")) {
            var As = db.GetCollection<A>(NameInDb<A>());
            var all_a = As
                .Include(x => x.B_Ref)
                .FindAll();
            foreach (var a in all_a) {
                if (a.B_Ref == null)
                    throw new Exception("B_Ref");
                if (a.B_Ref.C_Ref == null)
                    throw new Exception("C_Ref");
                if (a.B_Ref.C_Ref.D_Ref == null)
                    throw new Exception("D_Ref");
            }
        }
    }
}}

如何在LiteDB中实现级联包含

经过小型研究,我已经解决了这个问题,只是通过添加额外的"Include"参数化"x => x.B_Ref.C_Ref" lambda,其中x.B_Ref.C_Ref是引用层次结构中的路径:

var all_a = As
    .Include(x => x.B_Ref)
    .Include(x => x.B_Ref.C_Ref)
    .FindAll();

下面是完整的示例

namespace _01_simple {
using System;
using LiteDB;
public class A {
    public int Id { set; get; }
    public string Name { set; get; }
    public B B_Ref { set; get; }
}
public class B {
    public int Id { set; get; }
    public string Name { set; get; }
    public C C_Ref { set; get; }
}
public class C {
    public int Id { set; get; }
    public string Name { set; get; }
    public D D_Ref { set; get; }
}
public class D {
    public int Id { set; get; }
    public string Name { set; get; }
}
class Program {
    static void Main(string[] args) {
        test_01();
    }
    static string NameInDb<T>() {
        var name = typeof(T).Name + "s";
        return name;
    }
    static void test_01() {
        if (System.IO.File.Exists(@"MyData.db"))
            System.IO.File.Delete(@"MyData.db");
        using (var db = new LiteDatabase(@"MyData.db")) {
            var As = db.GetCollection<A>(NameInDb<A>());
            var Bs = db.GetCollection<B>(NameInDb<B>());
            var Cs = db.GetCollection<C>(NameInDb<C>());
            var Ds = db.GetCollection<D>(NameInDb<D>());
            LiteDB.BsonMapper.Global.Entity<A>().DbRef(x => x.B_Ref, NameInDb<B>());
            LiteDB.BsonMapper.Global.Entity<B>().DbRef(x => x.C_Ref, NameInDb<C>());
            LiteDB.BsonMapper.Global.Entity<C>().DbRef(x => x.D_Ref, NameInDb<D>());
            var d = new D { Name = "I am D." };
            var c = new C { Name = "I am C.", D_Ref = d };
            var b = new B { Name = "I am B.", C_Ref = c };
            var a = new A { Name = "I am A.", B_Ref = b };
            Ds.Insert(d);
            Cs.Insert(c);
            Bs.Insert(b);
            As.Insert(a);
        }
        using (var db = new LiteDatabase(@"MyData.db")) {
            var As = db.GetCollection<A>(NameInDb<A>());
            var all_a = As
                .Include(x => x.B_Ref)
                .Include(x => x.B_Ref.C_Ref)
                .Include(x => x.B_Ref.C_Ref.D_Ref)
                .FindAll();
            foreach (var a in all_a) {
                if (a.B_Ref == null)
                    throw new Exception("B_Ref");
                if (a.B_Ref.C_Ref == null)
                    throw new Exception("C_Ref");
                if (a.B_Ref.C_Ref.D_Ref == null)
                    throw new Exception("D_Ref");
            }
        }
    }
}}

我希望它节省了一些人的时间。

更新:LiteDB作者说不支持级联包含。但它计划在下一个版本中(见问题)。考虑一下,假设B_Ref是B的Lite,那么就没有机制来强制更深层的Include。