LiteDB icon indicating copy to clipboard operation
LiteDB copied to clipboard

Getting list of Ids from collection throws Unable to cast object of type 'LiteDB.ObjectId' to type 'System.String'

Open ssteiner opened this issue 1 year ago • 2 comments

Version LiteDb 5.0.21 on Win11 2023H2 on .NET 8.0.7

Describe the bug

Here's my object model:

public class PhoneBookCategory
{
    public string Id { get; set; }

    public string Name { get; set; }
}

Then I populate my DB as follows:

PhoneBookCategory category1 = new()
{
    Id = ObjectId.NewObjectId().ToString(),
    Name = "Category1"
};
PhoneBookCategory category2 = new()
{
    Id = ObjectId.NewObjectId().ToString(),
    Name = "Category2"
};
PhoneBookCategory category3 = new()
{
    Id = ObjectId.NewObjectId().ToString(),
    Name = "special Subcategory3"
};

database.GetCollection<PhoneBookCategory>().Insert(category1);
database.GetCollection<PhoneBookCategory>().Insert(category2);
database.GetCollection<PhoneBookCategory>().Insert(category3);

And I'm trying to fetch the list of Ids

var accessibleObjects = database.GetCollection<PhoneBookCategory>().Query().Select(x => x.Id).ToList();

When I run this, it throws

Unable to cast object of type 'LiteDB.ObjectId' to type 'System.String'. at at LiteDB.LiteQueryable1.<ToEnumerable>b__27_1(BsonValue x) at System.Linq.Enumerable.SelectEnumerableIterator2.ToList() at LiteDB.LiteQueryable1.ToList() at LiteDbTest.LiteDbContext.<>c__DisplayClass21_01.<BulkDelete>b__0(LiteDatabaseContext context) at LiteDbTest.LiteDbContext.PerformDatabaseOperation[T](Func`2 myFunc, IUserInformation userInfo, String methodName)

What I would expect is to get a List containing all Ids in my database.

If I remove the ToList(), it runs fine. If I replace ToList() with .FirstOrDefault(), it runs fine.

ssteiner avatar Jul 29 '24 11:07 ssteiner

Hi! I have a same problem in a same environment configuration of ssteiner, but not in cast to string but to long.

My stack trace:

Unable to cast object of type 'LiteDB.ObjectId' to type 'System.Int64'.- at lambda_method168(Closure, Object, Object) at LiteDB.BsonMapper.DeserializeObject(EntityMapper entity, Object obj, BsonDocument value) at LiteDB.BsonMapper.Deserialize(Type type, BsonValue value) at LiteDB.LiteQueryable 1.<ToEnumerable>b__27_2(BsonDocument x) at System.Linq.Enumerable.SelectEnumerableIterator 2.MoveNext() at System.Linq.Enumerable.<Any>g__WithEnumerator|36_0[TSource](IEnumerable 1 source) at System.Linq.Enumerable.Any[TSource](IEnumerable 1 source)

Vernizze avatar Aug 15 '24 12:08 Vernizze

@Vernizze : did you ever look in the database directly? I had the lingering feeling that in my case, I had a messed up value in the database. And since the IEnumerable only gets evaluated when I access the data, that would explain why it threw on ToList()

As I was using exclusive DB access mode, I never looked at the data.

ssteiner avatar Sep 10 '24 10:09 ssteiner

I run this code in the upstream repository and it works fine:

using Xunit;

namespace LiteDB.Tests.Issues;

public class Issue2527_Tests
{
    [Fact]
    public void Test() 
    {
        using LiteDatabase database = new(new ConnectionString()
        {
            Filename = "Demo.db",
        });

        PhoneBookCategory category1 = new()
        {
            Id = ObjectId.NewObjectId().ToString(),
            Name = "Category1"
        };
        PhoneBookCategory category2 = new()
        {
            Id = ObjectId.NewObjectId().ToString(),
            Name = "Category2"
        };
        PhoneBookCategory category3 = new()
        {
            Id = ObjectId.NewObjectId().ToString(),
            Name = "special Subcategory3"
        };

        database.GetCollection<PhoneBookCategory>().Insert(category1);
        database.GetCollection<PhoneBookCategory>().Insert(category2);
        database.GetCollection<PhoneBookCategory>().Insert(category3);

        var accessibleObjects = database.GetCollection<PhoneBookCategory>().Query().Select(x => x.Id).ToList();
    }

    public class PhoneBookCategory
    {
        public string Id { get; set; }
        public string Name { get; set; }
    }
}

Changing string to long also works. Maybe your database IDs are corrupted or the issue got fixed. Please send more info if you still have the issue @ssteiner @Vernizze.

Joy-less avatar Oct 22 '24 14:10 Joy-less

I wasn't able to create a repro sample that you could run - as I said in my previous post, I suspect I had some data corruption somewhere.

ssteiner avatar Oct 22 '24 15:10 ssteiner

I can't reproduce the issue, so I'll assume it's corrupted data, and am closing it. If you can find a way to reproduce the issue, please re-open it. Thanks

Joy-less avatar Nov 21 '24 01:11 Joy-less