#c# #.net #litedb #nosql
#c# #.net #litedb #nosql
Вопрос:
вот пример того, как хранить объекты с перекрестными ссылками в LiteDB. LiteDB отлично хранит объекты с перекрестными ссылками, но проблема возникает, когда я пытаюсь найти / загрузить объекты обратно. Моя цель — НЕ ТОЛЬКО запрашиваемая сущность, но и объекты, на которые ссылаются. На веб-странице LiteDB есть краткий раздел руководства «DBRef для перекрестных ссылок», как это можно реализовать. В LiteDB есть опция «Включить» (которая вызывается перед «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");
}
}
}
}}
Ответ №1:
после небольшого исследования я решил проблему, просто добавив дополнительную параметризацию «Включить» с помощью лямбда-выражения «x => x.B_Ref.C_Ref», где 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, тогда нет механизма принудительного более глубокого включения.
Комментарии:
1. Теперь вы можете использовать глубокие включения в версии 4, используя
BsonExpression
. Используйте строковые выражения, такие как «$.Customer», «$.Customer. Адрес» или linqx => x.Customer
. github.com/mbdavid/LiteDB/wiki/DbRef