简体   繁体   English

.NET Core Web API 和使用通用 JSON 对象的 MongoDB 驱动程序

[英].NET Core Web API and MongoDB Driver using Generic JSON Objects

I'm creating an ASP.NET Web API to perform CRUD operations in a MongoDB database.我正在创建一个 ASP.NET Web API 来在 MongoDB 数据库中执行 CRUD 操作。 I've been able to create a simple application based on the following Microsoft tutorial: Create a web API with ASP.NET Core and MongoDB .我已经能够基于以下 Microsoft 教程创建一个简单的应用程序: Create a web API with ASP.NET Core and MongoDB

This tutorial, like others I found, all use defined data models (in the above tutorial it's the Book model).本教程和我发现的其他教程一样,都使用定义的数据模型(在上面的教程中是 Book 模型)。 In my case i need to perform CRUD operations with generic JSON objects.就我而言,我需要使用通用 JSON 对象执行 CRUD 操作。 For example, the JSON object might be any of the following examples:例如,JSON 对象可能是以下任何示例:

Example #1:示例#1:

{_id: 1, name: 'Jon Snow', address: 'Castle Black', hobbies: 'Killing White Walkers'}

Example #2:示例#2:

{_id: 2, name: 'Daenerys Targaryen', family: 'House Targaryen', titles: ['Queen of Meereen', 'Khaleesi of the Great Grass Sea', 'Mother of Dragons', 'The Unburnt', 'Breaker of Chains', 'Queen of the Andals and the First Men', 'Protector of the Seven Kingdoms', 'Lady of Dragonstone']}

The reason why I'm using a NoSQL database (MongoDB) is mainly because of the undefined data structure, and the ability to preform CRUD operations with just JSON.我使用 NoSQL 数据库 (MongoDB) 的原因主要是因为未定义的数据结构,以及仅使用 JSON 就可以执行 CRUD 操作的能力。

As a trial and error attempt, I replaced the 'Book' model with 'object' and 'dynamic' but I get all sorts of errors regarding cast types and unknown properties:作为反复试验的尝试,我用“对象”和“动态”替换了“书”模型,但我收到了有关强制转换类型和未知属性的各种错误:

public class BookService
{
    private readonly IMongoCollection<object> _books;

    public BookService(IBookstoreDatabaseSettings settings)
    {
        var client = new MongoClient(settings.ConnectionString);
        var database = client.GetDatabase(settings.DatabaseName);

        _books = database.GetCollection<object>(settings.BooksCollectionName);
    }

    public List<object> Get() => _books.Find(book => true).ToList();

    //public object Get(string id) => _books.Find<object>(book => book.Id == id).FirstOrDefault();

    //public object Create(object book)
    //{
    //    _books.InsertOne(book);
    //    return book;
    //}

    //public void Update(string id, object bookIn) => _books.ReplaceOne(book => book.Id == id, bookIn);

    //public void Remove(object bookIn) => _books.DeleteOne(book => book.Id == bookIn.Id);

    //public void Remove(string id) => _books.DeleteOne(book => book.Id == id);
}

Errors:错误:

'object' does not contain a definition for 'Id' and no accessible extension method 'Id' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) “object”不包含“Id”的定义,并且找不到接受“object”类型的第一个参数的可访问扩展方法“Id”(您是否缺少 using 指令或程序集引用?)

InvalidCastException: Unable to cast object of type 'd__51' to type 'System.Collections.IDictionaryEnumerator'. InvalidCastException:无法将“d__51”类型的对象转换为“System.Collections.IDictionaryEnumerator”类型。

So, my question is, how can I use generic JSON data types with ASP.NET Core Web API and the MongoDB Driver?所以,我的问题是,如何将通用 JSON 数据类型与 ASP.NET Core Web API 和 MongoDB 驱动程序一起使用?

UPDATE: Based on @pete-garafano suggestion , I've decided to proceed with a POCO model.更新:根据@pete-garafano 的建议,我决定继续使用 POCO 模型。

I found an article in MongoDB's Github page explaining how to use static and dynamic data with the ASP.NET Core Driver.在 MongoDB 的 Github页面上找到了一篇文章,解释了如何通过 ASP.NET Core 驱动程序使用静态和动态数据。 So I made the following changes to the Book model:因此,我对 Book 模型进行了以下更改:

public class Book
{
    [BsonId]
    [BsonRepresentation(BsonType.ObjectId)]
    public string Id { get; set; }

    public string Name { get; set; }

    public decimal Price { get; set; }

    public string Category { get; set; }

    public string Author { get; set; }

    [BsonExtraElements]
    public BsonDocument Metadata { get; set; } //new property
}

Now I'm facing other issues, if my data is formatted exactly as the model, i'm able to list the data and create new entries in the database.现在我面临其他问题,如果我的数据格式与模型完全一致,我就可以列出数据并在数据库中创建新条目。 But, if i try to create a new entry with the bellow format, i get an error:但是,如果我尝试使用波纹管格式创建新条目,则会出现错误:

{
    "Name": "test 5",
    "Price": 19,
    "Category": "Computers",
    "Author": "Ricky",
    "Metadata": {"Key": "Value"} //not working with this new field
}

System.InvalidCastException: Unable to cast object of type 'MongoDB.Bson.BsonElement' to type 'MongoDB.Bson.BsonDocument'. System.InvalidCastException:无法将“MongoDB.Bson.BsonElement”类型的对象转换为“MongoDB.Bson.BsonDocument”类型。

Also, if i change the data format of one entry in Mongo and then try to list all results, i get the same error:此外,如果我在 Mongo 中更改一个条目的数据格式,然后尝试列出所有结果,则会出现相同的错误:

Mongo Compass 文档列表

System.InvalidCastException: Unable to cast object of type 'MongoDB.Bson.BsonDocument' to type 'MongoDB.Bson.BsonBoolean'. System.InvalidCastException:无法将“MongoDB.Bson.BsonDocument”类型的对象转换为“MongoDB.Bson.BsonBoolean”类型。

Based on the Mongo documents , the BsonExtraElements should allow generic/dynamic data to be attached to the model.根据Mongo 文档,BsonExtraElements 应该允许将通用/动态数据附加到模型。 What am I doing wrong in the new approach?我在新方法中做错了什么?

UPDATE #2: Added detailed stack trace of the error更新 #2:添加了错误的详细堆栈跟踪

System.InvalidCastException: Unable to cast object of type 'MongoDB.Bson.BsonDocument' to type 'MongoDB.Bson.BsonBoolean'. System.InvalidCastException:无法将“MongoDB.Bson.BsonDocument”类型的对象转换为“MongoDB.Bson.BsonBoolean”类型。 at get_AsBoolean(Object ) at System.Text.Json.JsonPropertyInfoNotNullable`4.OnWrite(WriteStackFrame& current, Utf8JsonWriter writer) at System.Text.Json.JsonPropertyInfo.Write(WriteStack& state, Utf8JsonWriter writer) at System.Text.Json.JsonSerializer.HandleObject(JsonPropertyInfo jsonPropertyInfo, JsonSerializerOptions options, Utf8JsonWriter writer, WriteStack& state) at System.Text.Json.JsonSerializer.WriteObject(JsonSerializerOptions options, Utf8JsonWriter writer, WriteStack& state) at System.Text.Json.JsonSerializer.Write(Utf8JsonWriter writer, Int32 originalWriterDepth, Int32 flushThreshold, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.JsonSerializer.WriteAsyncCore(Stream utf8Json, Object value, Type inputType, JsonSerializerOptions options, CancellationToken cancellationToken) at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding) at Microsoft.AspNetCor在 get_AsBoolean(Object ) 在 System.Text.Json.JsonPropertyInfoNotNullable`4.OnWrite(WriteStackFrame& current, Utf8JsonWriter writer) 在 System.Text.Json.JsonPropertyInfo.Write(WriteStack& state, Utf8JsonWriter writer) 在 System.Text.Json.JsonSerializer。 HandleObject(JsonPropertyInfo jsonPropertyInfo, JsonSerializerOptions 选项, Utf8JsonWriter writer, WriteStack& state) at System.Text.Json.JsonSerializer.WriteObject(JsonSerializerOptions options, Utf8JsonWriter writer, WriteStack& state) at System.Text.Json.JsonSerializer.Write(UtfWriterIntJsonWriter original writer, , Int32 flushThreshold, JsonSerializerOptions 选项, WriteStack& state) at System.Text.Json.JsonSerializer.WriteAsyncCore(Stream utf8Json, Object value, Type inputType, JsonSerializerOptions options, CancellationTokenCancellationToken) at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter(WriteResponseBodyAsyncCore) context, Encoding selectedEncoding) 在 Microsoft.AspNetCor e.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters() --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged|17_1(Re e.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state , Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)在 Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters() --- 从上一个抛出异常的位置的堆栈跟踪结束 --- 在 Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|19_0(ResourceInvoker invoker, Task Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged|17_1(Re sourceInvoker invoker) at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context) sourceInvoker invoker) at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionInvokeMiddleware HttpContext 上下文)

UPDATE #3: Added the Book service and controller code files, database Book collection and exception launched in get() result.更新 #3:添加了 Book 服务和控制器代码文件、数据库 Book 集合和在 get() 结果中启动的异常。

BookServices.cs:图书服务.cs:

public class BookService
{
    private readonly IMongoCollection<Book> _books;

    public BookService(IBookstoreDatabaseSettings settings)
    {
        var client = new MongoClient(settings.ConnectionString);
        var database = client.GetDatabase(settings.DatabaseName);

        _books = database.GetCollection<Book>(settings.BooksCollectionName);
    }

    public List<Book> Get() => _books.Find(book => true).ToList();


    public Book Get(string id) => _books.Find<Book>(book => book.Id == id).FirstOrDefault();

    public Book Create(Book book)
    {
        _books.InsertOne(book);
        return book;
    }

    public void Update(string id, Book bookIn) => _books.ReplaceOne(book => book.Id == id, bookIn);

    public void Remove(Book bookIn) => _books.DeleteOne(book => book.Id == bookIn.Id);

    public void Remove(string id) => _books.DeleteOne(book => book.Id == id);
}

BooksController.cs: BooksController.cs:

[Route("api/[controller]")]
[ApiController]
public class BooksController : ControllerBase
{
    private readonly BookService _bookService;

    public BooksController(BookService bookService)
    {
        _bookService = bookService;
    }

    [HttpGet]
    public ActionResult<List<Book>> Get() => _bookService.Get(); // error happens when executing Get()

    [HttpGet("{id:length(24)}", Name = "GetBook")]
    public ActionResult<Book> Get(string id)
    {
        var book = _bookService.Get(id);

        if (book == null)
        {
            return NotFound();
        }

        return book;
    }

    [HttpPost]
    public ActionResult<Book> Create([FromBody] Book book)
    {
        _bookService.Create(book);

        return CreatedAtRoute("GetBook", new { id = book.Id.ToString() }, book);
    }

    [HttpPut("{id:length(24)}")]
    public IActionResult Update(string id, Book bookIn)
    {
        var book = _bookService.Get(id);

        if (book == null)
        {
            return NotFound();
        }

        _bookService.Update(id, bookIn);

        return NoContent();
    }

    [HttpDelete("{id:length(24)}")]
    public IActionResult Delete(string id)
    {
        var book = _bookService.Get(id);

        if (book == null)
        {
            return NotFound();
        }

        _bookService.Remove(book.Id);

        return NoContent();
    }
}

BookstoreDb.Books: BookstoreDb.Books:

//non-pretty
{ "_id" : ObjectId("5df2b193405b7e9c1efa286f"), "Name" : "Design Patterns", "Price" : 54.93, "Category" : "Computers", "Author" : "Ralph Johnson" }
{ "_id" : ObjectId("5df2b193405b7e9c1efa2870"), "Name" : "Clean Code", "Price" : 43.15, "Category" : "Computers", "Author" : "Robert C. Martin" }
{ "_id" : ObjectId("5df2b1c9fe91da06078d9fbb"), "Name" : "A New Test", "Price" : 43.15, "Category" : "Computers", "Author" : "Ricky", "Metadata" : { "Key" : "Value" } }

Detailed result from Mongo Driver: Mongo Driver 的详细结果:

[/0]:{Api.Models.Book} Author [string]:"Ralph Johnson" Category [string]:"Computers" Id [string]:"5df2b193405b7e9c1efa286f" Metadata [BsonDocument]:null Name [string]:"Design Patterns" Price [decimal]:54.93 [/0]:{Api.Models.Book} 作者 [string]:"Ralph Johnson" 类别 [string]:"Computers" Id [string]:"5df2b193405b7e9c1efa286f" Metadata [BsonDocument]:null Name [string]:"Design图案”价格[十进制]:54.93

[/1]:{Api.Models.Book} Author [string]:"Robert C. Martin" Category [string]:"Computers" Id [string]:"5df2b193405b7e9c1efa2870" Metadata [BsonDocument]:null Name [string]:"Clean Code" Price [decimal]:43.15 [/1]:{Api.Models.Book} 作者 [string]:"Robert C. Martin" 类别 [string]:"Computers" Id [string]:"5df2b193405b7e9c1efa2870" Metadata [BsonDocument]:null Name [string]: 《清洁代码》价格【十进制】:43.15

[/2]:{Api.Models.Book} Author [string]:"Ricky" Category [string]:"Computers" Id [string]:"5df2b1c9fe91da06078d9fbb" Metadata [BsonDocument]:{{ "Metadata" : { "Key" : "Value" } }} AllowDuplicateNames [bool]:false AsBoolean [bool]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsBoolean' threw an exception of type 'System.InvalidCastException' AsBsonArray [BsonArray]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsBsonArray' threw an exception of type 'System.InvalidCastException' AsBsonBinaryData [BsonBinaryData]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsBsonBinaryData' threw an exception of type 'System.InvalidCastException' AsBsonDateTime [BsonDateTime]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsBsonDateTime' threw an exception of type 'System.InvalidCastException' AsBsonDocument [BsonDocument]:{{ "Metadata" : { "Key" : "Value" } }} AsBsonJavaSc [/2]:{Api.Models.Book} 作者 [string]:"Ricky" 类别 [string]:"Computers" Id [string]:"5df2b1c9fe91da06078d9fbb" 元数据 [BsonDocument]:{{ "Metadata" : { "Key " : "Value" } }} AllowDuplicateNames [bool]:false AsBoolean [bool]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsBoolean' 抛出了类型为“System.InvalidCastException”的异常' AsBsonArray [BsonArray]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsBsonArray' 抛出了类型为 'System.InvalidCastException' AsBsonBinaryData [BsonBinaryData]:'(new System.Collections.Collections. Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsBsonBinaryData' 抛出类型为'System.InvalidCastException' AsBsonDateTime [BsonDateTime]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata。 AsBsonDateTime' 抛出了类型为 'System.InvalidCastException' 的异常 AsBsonDocument [BsonDocument]:{{ "Metadata" : { "Key" : "Value" } }} AsBsonJavaSc ript [BsonJavaScript]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsBsonJavaScript' threw an exception of type 'System.InvalidCastException' AsBsonJavaScriptWithScope [BsonJavaScriptWithScope]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsBsonJavaScriptWithScope' threw an exception of type 'System.InvalidCastException' AsBsonMaxKey [BsonMaxKey]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsBsonMaxKey' threw an exception of type 'System.InvalidCastException' AsBsonMinKey [BsonMinKey]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsBsonMinKey' threw an exception of type 'System.InvalidCastException' AsBsonNull [BsonNull]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsBsonNull' threw an exception of type 'System.InvalidCastException' AsBsonRegularExpression [BsonRegularExpression]:'(new System.Collections.Generic.IColle ript [BsonJavaScript]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsBsonJavaScript' 抛出了一个类型为 'System.InvalidCastException' AsBsonJavaScriptWithScope [BsonJavaScriptWithScope] 的异常:'(new System.Collections.Generic .ICollectionDebugView(test).Items 2 ).Metadata.AsBsonJavaScriptWithScope' 抛出类型为'System.InvalidCastException' AsBsonMaxKey [BsonMaxKey]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsBsonMaxKey ' 抛出类型为 'System.InvalidCastException' AsBsonMinKey [BsonMinKey]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsBsonMinKey' 抛出类型为 'System.InvalidCastException' 的异常 AsBsonNull [ BsonNull]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsBsonNull' 抛出了'System.InvalidCastException'类型的异常 AsBsonRegularExpression [BsonRegularExpression]:'(new System.Collections.Generic.IColle ctionDebugView(test).Items 2 ).Metadata.AsBsonRegularExpression' threw an exception of type 'System.InvalidCastException' AsBsonSymbol [BsonSymbol]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsBsonSymbol' threw an exception of type 'System.InvalidCastException' AsBsonTimestamp [BsonTimestamp]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsBsonTimestamp' threw an exception of type 'System.InvalidCastException' AsBsonUndefined [BsonUndefined]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsBsonUndefined' threw an exception of type 'System.InvalidCastException' AsBsonValue [BsonValue]:{{ "Metadata" : { "Key" : "Value" } }} AsByteArray [byte[]]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsByteArray' threw an exception of type 'System.InvalidCastException' AsDateTime [DateTime]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadat ctionDebugView(test).Items 2 ).Metadata.AsBsonRegularExpression' 抛出类型为'System.InvalidCastException' AsBsonSymbol [BsonSymbol]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsBsonSymbol'的异常抛出类型为“System.InvalidCastException”的异常 AsBsonTimestamp [BsonTimestamp]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsBsonTimestamp' 抛出类型为“System.InvalidCastException”的异常 AsBsonUndefined [BsonUndefined ]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsBsonUndefined' 抛出了类型为 'System.InvalidCastException' AsBsonValue [BsonValue]:{{ "Metadata" : { "Key" : "Value" } }} AsByteArray [byte[]]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsByteArray' 抛出了一个类型为 'System.InvalidCastException' AsDateTime [DateTime] 的异常: '(新 System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadat a.AsDateTime' threw an exception of type 'System.InvalidCastException' AsDecimal [decimal]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsDecimal' threw an exception of type 'System.InvalidCastException' AsDecimal128 [Decimal128]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsDecimal128' threw an exception of type 'System.InvalidCastException' AsDouble [double]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsDouble' threw an exception of type 'System.InvalidCastException' AsGuid [Guid]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsGuid' threw an exception of type 'System.InvalidCastException' AsInt32 [int]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsInt32' threw an exception of type 'System.InvalidCastException' AsInt64 [long]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsInt64' th a.AsDateTime' 引发了类型为“System.InvalidCastException”的异常 AsDecimal [decimal]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsDecimal' 引发了类型为“System.InvalidCastException”的异常' AsDecimal128 [Decimal128]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsDecimal128' 抛出了类型为 'System.InvalidCastException' 的异常 AsDouble [double]:'(new System.Collections. Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsDouble' 抛出了类型为 'System.InvalidCastException' AsGuid [Guid]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata 的异常。 AsGuid' 引发了类型为“System.InvalidCastException”的异常 AsInt32 [int]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsInt32' 引发了类型为“System.InvalidCastException”的异常 AsInt64 [long]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsInt64'th rew an exception of type 'System.InvalidCastException' AsLocalTime [DateTime]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsLocalTime' threw an exception of type 'System.InvalidCastException' [More] Name [string]:"A New Test" Price [decimal]:43.15重新生成类型为“System.InvalidCastException”的异常 AsLocalTime [DateTime]:'(new System.Collections.Generic.ICollectionDebugView(test).Items 2 ).Metadata.AsLocalTime' 抛出类型为“System.InvalidCastException”的异常 [更多]名称 [string]:"A New Test" 价格 [decimal]:43.15

You should use BsonDocument to work with untyped data in C# with MongoDB.您应该使用BsonDocument在 C# 中使用 MongoDB 处理无类型数据。

private readonly IMongoCollection<BsonDocument> _books;

It isn't ideal, as C# would prefer strongly typed field names.这并不理想,因为 C# 更喜欢强类型字段名称。 I would recommend trying to build POCO models for the data to simplify query/update operations.我建议尝试为数据构建 POCO 模型以简化查询/更新操作。 If you cannot do this, you won't be able to use syntax like如果你不能这样做,你将无法使用像

_books.DeleteOne(book => book.Id == id);

You will need to instead use a dictionary type accesor syntax, like:您将需要改用字典类型访问符语法,例如:

_books.DeleteOne(book => book["_id"] == id);

Please note that the _id field is special in MongoDB in that it must be present in every document, and unique in the collection.请注意_id字段在 MongoDB 中很特殊,因为它必须出现在每个文档中,并且在集合中是唯一的。 In the example you linked to, they provide an entity model.在您链接到的示例中,它们提供了一个实体模型。 The Id field in this model has 2 decorators此模型中的Id字段有 2 个装饰器

[BsonId]
[BsonRepresentation(BsonType.ObjectId)]

These tell the driver that the Id field should be used as the _id , and that field, while a string in C# should be treated as an ObjectId by MongoDB.这些告诉驱动程序应该将Id字段用作_id ,并且该字段,而 C# 中的字符串应该被 MongoDB 视为ObjectId

If you are using a completely untyped model, you will need to be aware of the difference between _id and id and be sure to either map the fields properly or create an index on id (the former probably being what you want).如果您使用的是完全无类型的模型,则需要了解_idid之间的区别,并确保正确映射字段或在id上创建索引(前者可能是您想要的)。

I wrote a post a while back that may be helpful to you.前段时间写了一篇文章,可能对你有帮助。 It covers much of the same material as the Microsoft post, but may provide you some more insight.它涵盖了与 Microsoft 帖子相同的大部分内容,但可能会为您提供更多见解。

While the example data you provided does vary somewhat, it would still be possible to create a POCO model that would allow you to use type information in the queries.虽然您提供的示例数据确实有所不同,但仍然可以创建允许您在查询中使用类型信息的 POCO 模型。 I would suggest that you investigate the feasibility of this to simplify your development.我建议您调查这样做的可行性以简化您的开发。 As I explained above, this isn't a requirement, but it will definitely improve the query experience.正如我上面解释的,这不是必需的,但它肯定会改善查询体验。

Update To Address Extra Questions更新以解决额外问题

The BsonExtraElements attribute is meant as a place for the driver to deserialize fields not in your model. BsonExtraElements属性是驱动程序反序列化模型中不存在的字段的地方。 For example, if you rename the Metadata field to, lets say, Foo , and rerun it.例如,如果您将Metadata字段重命名为Foo ,然后重新运行它。 The Metadata field from the database should now actually be contained in the Foo field.来自数据库的Metadata字段现在应该实际上包含在Foo字段中。

System.InvalidCastException: Unable to cast object of type 'MongoDB.Bson.BsonDocument' to type 'MongoDB.Bson.BsonBoolean'. System.InvalidCastException:无法将“MongoDB.Bson.BsonDocument”类型的对象转换为“MongoDB.Bson.BsonBoolean”类型。

This exception seems to indicate something is a BsonDocument in the database, but the driver is trying to assign it to a bool value.此异常似乎表明数据库中存在BsonDocument ,但驱动程序正试图将其分配给bool值。 I am unable to reproduce the error on my end.我最终无法重现该错误。 I created a document in the database just as you provided above.我按照上面提供的方法在数据库中创建了一个文档。 数据库文件

I then queried using LINQPad and a simple program.然后我使用 LINQPad 和一个简单的程序进行查询。 示例程序

Can you perhaps provide the rest of the stack trace?您能否提供堆栈跟踪的其余部分? It may provide us more information on which field is causing the problem.它可以为我们提供有关哪个字段导致问题的更多信息。 You can also try removing BsonExtraElements from the Metadata in your POCO and creating a new field just for BsonExtraElements .您还可以尝试从 POCO 的Metadata中删除BsonExtraElements并仅为BsonExtraElements创建一个新字段。

Update 3更新 3

Thank you for providing the full stack trace.感谢您提供完整的堆栈跟踪。 This lead me to an "a ha!"这让我“哈哈!” moment.片刻。 The error is not coming from the MongoDB Driver, per se.该错误本身不是来自 MongoDB 驱动程序。 The error is actually coming from the JSON Serializer as it accesses all the fields on the BsonDocument type.该错误实际上来自 JSON 序列化程序,因为它访问BsonDocument类型的所有字段。

A BsonDocument is a kind of lazy type. BsonDocument是一种惰性类型。 It doesn't "know" what it contains until you try to access it.在您尝试访问它之前,它不“知道”它包含的内容。 This is handled by providing a getter for a number of different fields, all named by the type that it could contain.这是通过为许多不同的字段提供一个 getter 来处理的,所有字段都由它可以包含的类型命名。 You can see them here .你可以在这里看到它们。

The JSON Serializer in ASP is dutifully iterating over each field ( AsBoolean , AsBsonArray , AsBsonBinaryData , etc) attempting to retrieve the value to serialize to JSON. ASP 中的 JSON 序列化器忠实地迭代每个字段( AsBooleanAsBsonArrayAsBsonBinaryData等),尝试检索值以序列化为 JSON。 Unfortunately, most of these are going to fail as the value in Metadata cannot cast to most (or any) of them.不幸的是,其中大多数都会失败,因为Metadata的值无法转换为大多数(或任何)。

I think you're going to need to either tell the JSON Serializer to ignore the Metadata field, or write a JSON serializer for BsonDocument .认为您需要告诉 JSON Serializer忽略Metadata字段,或者为BsonDocument编写一个 JSON 序列化BsonDocument

If anyone else happens upon this article because they received the System.InvalidCastException: Unable to cast object of type 'MongoDB.Bson.BsonDocument' to type 'MongoDB.Bson.BsonBoolean' when trying to use the [BsonExtraElements] property, the quickest and easiest fix will be to make your property an `IDictionary<string, object>' element.如果其他人因为收到System.InvalidCastException: Unable to cast object of type 'MongoDB.Bson.BsonDocument' to type 'MongoDB.Bson.BsonBoolean'在尝试使用[BsonExtraElements]属性时发生在这篇文章中,最快和最简单的解决方法是使您的属性成为“IDictionary<string, object>”元素。 Once I changed my ExtraElements property to the following, everything worked perfectly:一旦我将 ExtraElements 属性更改为以下内容,一切都运行良好:

[BsonExtraElements]
public Dictionary<string, object> ExtraElements
{
    get; set;
}

The ExtraElements property will contain the Metadata element. ExtraElements属性将包含Metadata元素。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM