如何在 LiteDB 中进行级联包含
How to do Cascading Include in LiteDB
这里是关于如何在 LiteDB 中存储交叉引用实体的示例。 LiteDB 非常好地存储交叉引用的实体,但是当我尝试返回 find/load 实体时出现问题。我的目标不仅是请求的实体,而且是引用的实体。 LiteDB webpage 上有快速教程部分 "DbRef for cross references" 如何实现它。 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");
}
}
}
}}
经过小型研究后,我通过添加额外的 "Include" parameterize by "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 作者说不支持级联包含。但它计划在下一个版本中(参见 issue)。考虑一下,假设 B_Ref 是 B 的精简版,那么就没有强制更深包含的机制。
这里是关于如何在 LiteDB 中存储交叉引用实体的示例。 LiteDB 非常好地存储交叉引用的实体,但是当我尝试返回 find/load 实体时出现问题。我的目标不仅是请求的实体,而且是引用的实体。 LiteDB webpage 上有快速教程部分 "DbRef for cross references" 如何实现它。 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");
}
}
}
}}
经过小型研究后,我通过添加额外的 "Include" parameterize by "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 作者说不支持级联包含。但它计划在下一个版本中(参见 issue)。考虑一下,假设 B_Ref 是 B 的精简版,那么就没有强制更深包含的机制。