LiteDB:字段“_id”上的 BSON 数据类型 'Null' 无效
LiteDB: Invalid BSON data type 'Null' on field '_id'
使用LiteDB,太棒了。它适用于加载和存储数据,但是,不适用于创建数据库后的后续加载。
初始加载时,一切都很完美。它创建数据库并完美地存储新记录,并且查询 returns 为空,因为该集合中还没有任何内容。
在随后的加载中,在查询数据(工作并获得结果)后,.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 ) );
确保在初始创建后测试停止程序,然后启动程序 'fresh' 使用以下代码对加载/更新数据库进行干净测试:
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
中存储的更新,这将触发 .Update
方法在我的 IsCached
方法中。
当你有一个没有标识的对象时,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; }
我同意@mbdavid 的回答。但是,当它用于您不拥有的类型时,例如您从第 3 方程序集中使用的类型,您需要使用 BsonMapper:
BsonMapper.Global.Entity<IdentityServer4.Models.IdentityResources.OpenId>()
.Id(oid => oid.Name);
将它放在启动代码的某处。
对于可能遇到此问题的其他人,这里有一个对我有用的示例。
我有一个带有字段 columnId 的产品 class,我添加了另一个类型为 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; }
.....
}
我在另一个 class 中创建的更新方法是:
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
对我不起作用。
使用LiteDB,太棒了。它适用于加载和存储数据,但是,不适用于创建数据库后的后续加载。
初始加载时,一切都很完美。它创建数据库并完美地存储新记录,并且查询 returns 为空,因为该集合中还没有任何内容。
在随后的加载中,在查询数据(工作并获得结果)后,.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 ) );
确保在初始创建后测试停止程序,然后启动程序 'fresh' 使用以下代码对加载/更新数据库进行干净测试:
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
中存储的更新,这将触发 .Update
方法在我的 IsCached
方法中。
当你有一个没有标识的对象时,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; }
我同意@mbdavid 的回答。但是,当它用于您不拥有的类型时,例如您从第 3 方程序集中使用的类型,您需要使用 BsonMapper:
BsonMapper.Global.Entity<IdentityServer4.Models.IdentityResources.OpenId>()
.Id(oid => oid.Name);
将它放在启动代码的某处。
对于可能遇到此问题的其他人,这里有一个对我有用的示例。
我有一个带有字段 columnId 的产品 class,我添加了另一个类型为 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; }
.....
}
我在另一个 class 中创建的更新方法是:
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
对我不起作用。