LiteDB:字段“_id”上的 BSON 数据类型“Null”无效

本文关键字:无效 BSON 数据类型 上的 Null id 字段 LiteDB | 更新日期: 2023-09-27 17:56:44

使用LiteDB,真是太神奇了。它适用于加载和存储数据,但是,在创建数据库后无法在后续加载时使用。

在初始负载时,一切都很完美。它创建数据库并完美地存储新记录,查询返回空,因为该集合中尚不存在任何内容。

后续加载中,在查询数据(工作并获得结果)后,.Update()中存在导致此问题的问题。根据他们的文档,当未指定"Id"时,它应该创建一个。从集合返回对象时,它不包含此"_Id"字段,因此无法更新数据库中的记录。

public class AuctionCache
{
    public double lastModified { get; set; }
    public string server { get; set; }
    public AuctionCache() { }
}
private static bool IsCached(AuctionCache auction)
{
    string filename = string.Format("{0}-{1}.json", auction.server, auction.lastModified);
    bool cached = false;
    try
    {
        using (LiteDatabase db = new LiteDatabase("cache.db"))
        {
            // Get customer collection
            var auctions = db.GetCollection<AuctionCache>("auctions");
            // Use Linq to query documents
            try
            {
                var results = auctions.Find(x => x.server == auction.server).DefaultIfEmpty(null).Single();
                if (results == null)
                {
                    // Insert new cached server
                    auctions.Insert(auction);
                    auctions.EnsureIndex(x => x.server);
                }
                else
                {
                    if (results.lastModified < auction.lastModified)
                    {
                        // Update existing cached server data
                        results.lastModified = auction.lastModified;
                        auctions.Update(results);
                        auctions.EnsureIndex(x => x.server);
                    }
                    else
                    {
                        cached = File.Exists(filename);
                    }
                }
            }
            catch (LiteException le1) {
                Log.Output(le1.Message);
                // Get stack trace for the exception with source file information
                var st = new StackTrace(le1, true);
                // Get the top stack frame
                var frame = st.GetFrame(0);
                // Get the line number from the stack frame
                var line = frame.GetFileLineNumber();
                var module = frame.GetMethod();
                var file = frame.GetFileName();
            }
            catch (Exception e)
            {
                Log.Output(e.Message);
                // Get stack trace for the exception with source file information
                var st = new StackTrace(e, true);
                // Get the top stack frame
                var frame = st.GetFrame(0);
                // Get the line number from the stack frame
                var line = frame.GetFileLineNumber();
            }
        }
    } catch (Exception ee) {
        Log.Output(ee.Message);
        // Get stack trace for the exception with source file information
        var st = new StackTrace(ee, true);
        // Get the top stack frame
        var frame = st.GetFrame(0);
        // Get the line number from the stack frame
        var line = frame.GetFileLineNumber();
    }
    return cached;
}

如果您希望快速使用上述代码,可以使用以下内容进行演示(初始加载):

   AuctionCache ac = new AuctionCache();
   ac.lastModified = (double)12345679;
   ac.server = "Foo";
   // should return true on subsequent loads.
   Console.WriteLine( IsCached( ac ) );

确保在测试时在初始创建后停止程序,然后启动程序"新",使用以下代码对加载/更新数据库进行干净测试:

   AuctionCache ac = new AuctionCache();
   ac.lastModified = (double)22345679;
   ac.server = "Foo";
   // should return true on subsequent loads.
   Console.WriteLine( IsCached( ac ) );

这应该确保它将尝试更新记录并将 IDE 中的问题标记为lastModified比存储在cache.db中的问题更新,这将触发我的IsCached方法中的 .Update 方法。

LiteDB:字段“_id”上的 BSON 数据类型“Null”无效

当您有一个没有标识的对象时,LiteDB 将您的对象转换为 BsonDocument 并在插入时创建一个新的"_id"。如果您查询数据库(使用 shell),则可以在那里看到带有_id (ObjectId) 的文档。

但是,要更新文档,您必须使用插入时生成的此_id(请参阅此处:https://github.com/mbdavid/LiteDB/blob/v2.0.0-rc/LiteDB/Core/Collections/Update.cs#L25)。仅当将此_id存储在另一个数据库 (sql) 中或仅用于插入时,没有 id 的文档才有用。

在您的示例中,如果您server文档 ID,请使用[BsonId]属性来求解或创建public Guid Id { get; set; }

对于可能遇到此问题的其他人,这里有一个对我有用的示例。我有一个带有字段列 Id 的产品类,我添加了另一个类型为 objectId 的 Id 以消除该Invalid BSON data type 'Null' on field '_id'错误。

public class Product
    {
        [BsonId]
        public ObjectId Id { get; set; }
        public int ColumnId { get; }
        public int Quantity { get; private set; }
     .....
     }

我在另一个类中创建的更新方法是:

  public void UpdateQuantity(Product product)
        {
       var collection = database.GetCollection<Product>("products");
       var databaseProduct = collection.FindOne(x =>x.ColumnId.Equals(product.ColumnId));
       databaseProduct.DecrementQuantity();
       collection.Update(databaseProduct);
        }

Guid型对我不起作用。

我同意@mbdavid的回答。但是,当它适用于您不拥有的类型时,例如您从第三方程序集使用的内容,您需要使用 BsonMapper:

BsonMapper.Global.Entity<IdentityServer4.Models.IdentityResources.OpenId>()
    .Id(oid => oid.Name);

把它放在你的启动代码中的某个地方。