mbdavid / LiteDB

LiteDB - A .NET NoSQL Document Store in a single data file
http://www.litedb.org
MIT License
8.62k stars 1.25k forks source link

[BUG] BsonRef Self Ref outoverflowexception #2310

Closed sgf closed 5 months ago

sgf commented 1 year ago

Version ver 5.0.16

Describe the bug

public class Package {

[BsonRef()]
public Package Parent{get;set;}

public List<Package>Childs {get;set;}

}

https://github.com/mbdavid/LiteDB/issues/975 https://github.com/mbdavid/LiteDB/issues/2265

Code to Reproduce

var col= db.GetCollection();//error here

Expected behavior code execute pass

Screenshots/Stacktrace

image

Additional context

This problem is caused by circular references. But reasonable citations should often be allowed. For example, father and son. But I believe this kind of reference should have some exit mechanism. For example: parent node, child node must be finite. Therefore, I suggest a limit on the number that can be used with the Attribute token exit mechanism. For example: increase the reference depth for the specified field: BsonRef(limit=1024)

sgf commented 1 year ago

i have modify a fork for this bug. but i cant make a pull request. because i have not install some old sdk.if some one like to do the pull request.pls do that. https://github.com/sgf/LiteDBEx

Garados007 commented 11 months ago

I found a workaround for a similar issue. Lets say we have the following data classes:

public class A
{
    [BsonRef("b")]
    public B B { get; set; }
}

public class B
{
    [BsonRef("a")]
    public A A { get; set; }
}

This returns the same error. To prevent a stack overflow during GetCollection<>(), you just have to comment [BsonRef("a")] (or remove) and add the following line to your setup routine (after doing all the GetCollection<>()):

BsonMapper.Global.Entity<B>().DbRef(x => x.A, "a"); // add [BsonRef] manually

More information: https://www.litedb.org/docs/object-mapping/ (chapter: Fluent Mapping)

sgf commented 11 months ago

I found a workaround for a similar issue. Lets say we have the following data classes:

public class A
{
    [BsonRef("b")]
    public B B { get; set; }
}

public class B
{
    [BsonRef("a")]
    public A A { get; set; }
}

This returns the same error. To prevent a stack overflow during GetCollection<>(), you just have to comment [BsonRef("a")] (or remove) and add the following line to your setup routine (after doing all the GetCollection<>()):

BsonMapper.Global.Entity<B>().DbRef(x => x.A, "a"); // add [BsonRef] manually

More information: https://www.litedb.org/docs/object-mapping/ (chapter: Fluent Mapping)

The situation you described is a circular reference between two types, while my situation is a self-reference.

wlscodes commented 10 months ago

I found a workaround for a similar issue. Lets say we have the following data classes:

public class A
{
    [BsonRef("b")]
    public B B { get; set; }
}

public class B
{
    [BsonRef("a")]
    public A A { get; set; }
}

This returns the same error. To prevent a stack overflow during GetCollection<>(), you just have to comment [BsonRef("a")] (or remove) and add the following line to your setup routine (after doing all the GetCollection<>()):

BsonMapper.Global.Entity<B>().DbRef(x => x.A, "a"); // add [BsonRef] manually

More information: https://www.litedb.org/docs/object-mapping/ (chapter: Fluent Mapping)

The situation you described is a circular reference between two types, while my situation is a self-reference.

Hello,

It should work for self-reference too. In docs https://www.litedb.org/docs/dbref/ chapter: Mapping a reference on database initialization there is a mention about using a fluent API. So i remove a [BsonRef] annotation from my model class and then I add this line to code:

BsonMapper.Global.Entity<PersonModel>().DbRef(x => x.Father, "people");
public class PersonModel
{
    [BsonId]
    public required ObjectId Id { get; set; }

    //[BsonRef("people")]
    public PersonModel? Father { get; set; }
}

I hope this will help someone.

sgf commented 10 months ago

It should work for self-reference too. In docs https://www.litedb.org/docs/dbref/ chapter: Mapping a reference on database initialization there is a mention about using a fluent API. So i remove a [BsonRef] annotation from my model class and then I add this line to code:

BsonMapper.Global.Entity<PersonModel>().DbRef(x => x.Father, "people");
public class PersonModel
{
    [BsonId]
    public required ObjectId Id { get; set; }

    //[BsonRef("people")]
    public PersonModel? Father { get; set; }
}

I hope this will help someone.

After testing, I have to admit that this does seem to be a solution. Although this method is not convenient for me.

I don't know why, but an ID column must be defined.